繁体   English   中英

我如何将 select 条记录合并为一行?

[英]How do I select records into a single row?

我试过将 sql 查询写入 select 多条记录到一行,但它没有按照我预期的方式工作 目前我的表看起来像这样

人员编号 水果
1个 苹果
1个 橘子
1个 香蕉
2个 苹果
2个 橘子
3个 苹果

我试过使用 CASE 和 GROUP BY,但它只是提供了额外的记录,并没有按照我想要的方式显示,而是像这样显示

SELECT DISTINCT
F.MEMBER
,F.GIVEN_NAMES
,F.SURNAME
--VALUES NEEDED
,CASE WHEN F.VALUE_NEEDED = 'Postal Address' THEN 'Yes' ELSE '' END POSTAL_ADDRESS
,CASE WHEN F.VALUE_NEEDED = 'Birthday' THEN 'Yes' ELSE '' END BIRTHDAY
,CASE WHEN F.VALUE_NEEDED = 'Email Address' THEN 'Yes' ELSE '' END EMAIL_ADDRESS
,CASE WHEN F.VALUE_NEEDED = 'First Name' THEN 'Yes' ELSE '' END FIRST_NAME
,CASE WHEN F.VALUE_NEEDED = 'Surname' THEN 'Yes' ELSE '' END SURNAME
,CASE WHEN F.VALUE_NEEDED = 'Title and Gender' THEN 'Yes' ELSE '' END 'TITLE|GENDER'
,CASE WHEN F.VALUE_NEEDED = 'Mobile' THEN 'Yes' ELSE '' END MOBILE
,CASE WHEN F.VALUE_NEEDED = 'Beneficiary' THEN 'Yes' ELSE '' END BENEFICIARY
FROM #FINAL F
GROUP BY F.MEMBER,F.GIVEN_NAMES
,F.SURNAME,VALUE_NEEDED
ORDER BY F.MEMBER
人员编号 苹果 橘子 香蕉
1个 是的
1个 是的
1个 是的

如何编写查询使其看起来更像这样?

人员编号 苹果 橘子 香蕉
1个 是的 是的 是的
2个 是的 是的
3个 是的

你几乎就在那里,只需要添加最大值和分组依据来聚合它。 这曾经是一个典型的面试问题。 如果我理解正确的话,这样的事情

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;
人员编号 苹果 橘子 香蕉
1个 是的 是的 是的
2个 是的 是的 NULL
3个 是的 NULL NULL

您已经标记了您正在使用的工具 (SQL Server Management Studio),它可以与不同的 DBMS 一起使用。 由于 Microsoft 的 SQL Server 是该工具中最典型的服务器,因此我假设您正在使用它。

首先让我们看看你的桌子。 似乎有点奇怪。 它似乎是一种键值表(又名 EAV)。 每行告诉我们一个人是否需要一个属性。 现在如何识别表中的一个人? member是唯一的人员 ID 吗? 可能不会,因为那样的话,该表中的given_namessurname会随着每个条目而改变。 为什么 ID 为 1234 的同一个人在value_needed为“生日”时被称为 John Smith,而在value_needed为“移动”时被称为“Anne Miller”? 那没有多大意义。 所以也许member只是一个标志,一个人是否是一个成员,一个人由他们的given_namessurname唯一标识。 但是话又说回来,为什么当value_needed是“生日”时同一个人约翰·史密斯会成为会员,而当value_needed是“移动”时却不是会员? 所以这里有些不对劲。 看来你的表没有规范化。 最好有一张人表和一张属性表。

话虽如此, GROUP BY ___的意思是“我希望每个 ___ 有一个结果行”。 你按人和他们的value_needed 但是您不希望每个人和value_needed一个结果行。 你想要每人一个结果行。 于是,以人为本。

那么你SELECT DISTINCT... 这意味着您要删除重复的行。 但是看看你选择的行。 没有重复项。 如果您使用GROUP BY ,您可以 99.99% 确定不需要DISTINCT (确实存在您自愿按列分组的罕见情况,不要 select 所有这些然后应用DISTINCT ,但这种情况非常罕见,您可能根本不会使用它们。)

现在开始任务:您想要从行到列。 这称为 pivot,可以使用PIVOT关键字来实现,但更常见的是使用条件聚合。 “条件聚合”意味着您聚合您的数据(每人),然后应用条件。 在标准 SQL 中:

SELECT MIN('YES') FILTER (WHERE f.value_needed = 'Postal Address')

您可以在此处使用MINMAX ,并且仅出于语法原因才需要( FILTER子句必须引用某些聚合 function。

在 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 服务器中使用括号。 但更好的是,通过避免名称中的特殊字符来避免它们。

完整查询:

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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM