SQL Server 如何将记录选择到单行中?

bwitn5fc  于 2023-01-16  发布在  其他
关注(0)|答案(2)|浏览(147)

我曾尝试编写SQL查询来选择一行中的多条记录,但效果不如预期。当前我的表如下所示
| 个人识别码|果实|
| - ------|- ------|
| 1个|苹果|
| 1个|橙|
| 1个|香蕉|
| 第二章|苹果|
| 第二章|橙|
| 三个|苹果|
我尝试过使用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个|是的|是的|是的|
| 第二章|是的|是的||
| 三个|是的|||

neekobn8

neekobn81#

你就快到了,只需要加上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;

| 个人标识|苹果|橙|香蕉|
| - ------|- ------|- ------|- ------|
| 1个|是的|是的|是的|
| 第二章|是的|是的|零|
| 三个|是的|零|零|

kwvwclae

kwvwclae2#

您已经标记了您正在使用的工具(SQL Server Management Studio),该工具可以用于不同的DBMS。由于Microsoft的SQL Server是此工具中最常用的工具,我假设您正在使用该工具。
首先让我们看一下你的表。它看起来有点奇怪。它似乎是一种键-值表(又名EAV)。每行告诉我们一个属性是否需要一个人。现在如何在表中标识一个人?列member是唯一的人ID吗?可能不是,因为那样的话,given_namessurname在该表中的作用是什么?每个条目都可能发生变化。为什么当value_needed为“生日”时,ID为1234的同一个人会被称为John Smith,而当value_needed为“移动”时,该人会被称为“Anne米勒”?这没有多大意义。因此,也许member只是一个标志,无论此人是否是会员,并且一个人由他们的given_namessurname唯一地标识。但是话又说回来,当value_needed是“生日”时,为什么同一个人John Smith是成员,但当value_needed为“Mobile”时不是成员?所以这里有些问题。看起来您的表没有规范化。最好有一个person表和一个属性表。
也就是说,GROUP BY ___表示“我希望每个___有一个结果行"。您可以按人员及其value_needed分组。但您不希望每个人员和value_needed有一个结果行。您希望每个人员有一个结果行。因此,按人员分组。
然后使用SELECT DISTINCT ...。这意味着您要删除重复的行。但是请查看您选择的行。没有重复的行。如果使用GROUP BY,您可以99.99%确定不需要DISTINCT。(确实存在一些罕见的情况,您自愿按列分组,不选择所有列,然后应用DISTINCT,但这些都是非常罕见的,你可能永远不会使用它们。)
现在的任务:您希望从行获取到列。这称为透视,可以使用PIVOT关键字来实现,但更常用的是使用条件聚集。“条件聚集”意味着聚集数据(每个人),然后应用条件。在标准SQL中:

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

在这里可以使用MINMAX,这只是出于语法原因(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;

相关问题