我试着写我的sql查询选择多个记录到一行,但它不工作的方式,我期望它目前我的表看起来像这样
person id | fruit | 1 | 苹果 | 1
---|---|
橙色 | |
香蕉 | |
苹果 | |
橙色 | |
3 | 苹果 |
您几乎已经完成了,只需要添加max和group by来聚合它。这在当时是一个典型的面试问题。如果我没理解错的话
with t as
(
select 1 as person_id, 'apple' fruit
union
select 1 ,'orange'
union
select 1 ,'banana'
union
select 2 ,'apple'
union
select 2 ,'orange'
union
select 3 ,'apple'
)
, b as
(
select
person_id,
case when fruit= 'apple' then 'yes' else null end 'apple',
case when fruit= 'orange' then 'yes' else null end 'orange',
case when fruit= 'banana' then 'yes' else null end 'banana'
from t
)
select
person_id,
max(apple) apple,
max(orange) orange,
max(banana) banana
from b
group by 1;
您已经标记了您正在使用的工具(SQL Server Management Studio),可以与不同的DBMS一起使用。由于Microsoft的SQL Server是这个工具中最常用的,我假设您正在使用它。
首先让我们看看你的表。这看起来有点奇怪。它似乎是一种键值表(又名EAV)。每一行都告诉我们一个属性是否为一个人所需要。现在如何在表格中识别一个人呢?列member
是唯一的个人ID吗?可能不会,因为那样的话,given_names
和surname
在表中的位置,会随着每一个元素的加入而改变。为什么当value_needed
是"生日"时,同一个ID为1234的人被称为约翰·史密斯,但当value_needed
是"移动"时,他被称为"安妮·米勒"?这没有多大意义。所以也许member
只是一个标志,不管一个人是否是成员,一个人是由他们的given_names
和surname
唯一标识的。但话又说回来,为什么同一个人John Smith在value_needed
是"Birthday"时是成员,而在value_needed
是"Mobile"时却不是成员呢?所以这里有问题。看来你的表格没有标准化。最好有一个人表和一个属性表。
话虽这么说,GROUP BY ___
的意思是"我想要每一行结果"。你按个人和他们的value_needed
分组。但是您不希望每个人和value_needed
都有一个结果行。您希望每个人有一个结果行。因此,按人分组。
然后你SELECT DISTINCT ...
。这意味着您想要删除重复的行。但是看看你选择的行。没有重复的。如果你使用GROUP BY
,你可以99.99%确定你不需要DISTINCT
。(确实存在一些罕见的情况,您自愿按列分组,不要选中所有列然后应用DISTINCT
,但这些情况非常罕见,您可能根本不会使用它们。)
现在进入任务:您想要从行转换到列。这被称为枢轴,可以通过PIVOT
关键字实现,但更常用的是使用条件聚合。"条件aggregation"意味着您汇总数据(每个人),然后应用一个条件。在标准SQL中:
SELECT MIN('YES') FILTER (WHERE f.value_needed = 'Postal Address')
您可以在这里使用MIN
或MAX
,这只是出于语法原因(FILTER
子句必须引用某个聚合函数)。
在SQL Server中没有FILTER
子句,所以你使用CASE
表达式代替:
SELECT MIN(CASE WHEN f.value_needed = 'Postal Address' THEN 'YES' END)
如果你想要空字符串''
而不是NULL,应用COALESCE
:
SELECT COALESCE(MIN(CASE WHEN f.value_needed = 'Postal Address' THEN 'YES' END), '')
包含特殊字符(如|
)的列别名需要引用。但不是单引号,因为它们表示字符串字面量。在标准SQL中使用双引号,在SQL Server中使用括号。但更好的做法是,通过在名称中避免使用特殊字符,将它们全部避免。
SELECT
person_id,
MIN(CASE WHEN value_needed = 'Postal Address' THEN 'yes' end) AS postal_address,
MIN(CASE WHEN value_needed = 'Birthday' THEN 'Yes' end) AS birthday,
MIN(CASE WHEN value_needed = 'Email' THEN 'Yes' END) AS email_address,
MIN(CASE WHEN value_needed = 'First Name' THEN 'Yes' END) AS first_name,
MIN(CASE WHEN value_needed = 'Surname' THEN 'Yes' END) AS surname,
MIN(CASE WHEN value_needed = 'Title and Gender' THEN 'Yes' END) AS title_gender,
MIN(CASE WHEN value_needed = 'Mobile' THEN 'Yes' END) AS mobile,
MIN(CASE WHEN value_needed = 'Beneficiary' THEN 'Yes' END) AS beneficiary
FROM #FINAL
GROUP BY person_id
ORDER BY person_id;