[英]How do I select records into a single row?
I've tried writing my sql query to select multiple records on to one row but it isn't working the way I expected it to Currently my table looks something like this我试过将 sql 查询写入 select 多条记录到一行,但它没有按照我预期的方式工作 目前我的表看起来像这样
person id![]() |
fruit![]() |
---|---|
1 ![]() |
apple![]() |
1 ![]() |
orange![]() |
1 ![]() |
banana![]() |
2 ![]() |
apple![]() |
2 ![]() |
orange![]() |
3 ![]() |
apple![]() |
I've tried using CASE and GROUP BY but it just gave extra records and didn't display the way I wanted it to and is displaying like this我试过使用 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
person id![]() |
apple![]() |
orange![]() |
banana![]() |
---|---|---|---|
1 ![]() |
yes![]() |
||
1 ![]() |
yes![]() |
||
1 ![]() |
yes![]() |
How do I write the query so it looks more like this?如何编写查询使其看起来更像这样?
person id![]() |
apple![]() |
orange![]() |
banana![]() |
---|---|---|---|
1 ![]() |
yes![]() |
yes![]() |
yes![]() |
2 ![]() |
yes![]() |
yes![]() |
|
3 ![]() |
yes![]() |
You are almost there, just needed to add the max and group by to aggregate it.你几乎就在那里,只需要添加最大值和分组依据来聚合它。 This used to be a typical interview question back then.
这曾经是一个典型的面试问题。 Some thing like this if I understood correctly
如果我理解正确的话,这样的事情
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;
person_id![]() |
apple![]() |
orange![]() |
banana![]() |
---|---|---|---|
1 ![]() |
yes![]() |
yes![]() |
yes![]() |
2 ![]() |
yes![]() |
yes![]() |
NULL ![]() |
3 ![]() |
yes![]() |
NULL ![]() |
NULL ![]() |
You have tagged the tool that you are using (SQL Server Management Studio) which can be used with different DBMS.您已经标记了您正在使用的工具 (SQL Server Management Studio),它可以与不同的 DBMS 一起使用。 As Microsoft's SQL Server is the most typical used in this tool, I assume your are using that.
由于 Microsoft 的 SQL Server 是该工具中最典型的服务器,因此我假设您正在使用它。
First let's look at your table.首先让我们看看你的桌子。 It seems a bit weird.
似乎有点奇怪。 It seems to be a kind of key-value table (aka EAV).
它似乎是一种键值表(又名 EAV)。 Each row tells us for an attribute whether it is needed for a person.
每行告诉我们一个人是否需要一个属性。 Now how to identify a person in the table?
现在如何识别表中的一个人? Is the column
member
a unique person ID?列
member
是唯一的人员 ID 吗? Probably not, because then, what would be given_names
and surname
be for in that table, that can change with every entry.可能不会,因为那样的话,该表中的
given_names
和surname
会随着每个条目而改变。 Why would the same person with the ID 1234 be called John Smith when the value_needed
is 'Birthday', but be called 'Anne Miller' when value_needed
is 'Mobile'?为什么 ID 为 1234 的同一个人在
value_needed
为“生日”时被称为 John Smith,而在value_needed
为“移动”时被称为“Anne Miller”? That wouldn't make much sense.那没有多大意义。 So maybe
member
is just a flag, whether a person is a member or not, and a person is uniquely identified by their given_names
and surname
.所以也许
member
只是一个标志,一个人是否是一个成员,一个人由他们的given_names
和surname
唯一标识。 But then again, why would the same person John Smith be a member when value_needed
is 'Birthday', but not a member when value_needed
is 'Mobile'?但是话又说回来,为什么当
value_needed
是“生日”时同一个人约翰·史密斯会成为会员,而当value_needed
是“移动”时却不是会员? So something is amiss here.所以这里有些不对劲。 It seems your table is not normalized.
看来你的表没有规范化。 Better have one person table and one table for the attributes.
最好有一张人表和一张属性表。
That being said, GROUP BY ___
means "I want one result row per ___".话虽如此,
GROUP BY ___
的意思是“我希望每个 ___ 有一个结果行”。 You group by the person and their value_needed
.你按人和他们的
value_needed
。 But you don't want one result row per person and value_needed
.但是您不希望每个人和
value_needed
一个结果行。 You want one resut row per person.你想要每人一个结果行。 Hence, group by person.
于是,以人为本。
Then you SELECT DISTINCT...
.那么你
SELECT DISTINCT...
This means you want to remove duplicate rows.这意味着您要删除重复的行。 But look at the rows you are selecting.
但是看看你选择的行。 There are no duplicates.
没有重复项。 If you use
GROUP BY
, you can be 99.99% sure you don't need DISTINCT
.如果您使用
GROUP BY
,您可以 99.99% 确定不需要DISTINCT
。 (There do exist rare situations where you voluntarily group by columns, don't select all of them and then apply DISTINCT
, but these are so rare that you probably won't ever use them at all.) (确实存在您自愿按列分组的罕见情况,不要 select 所有这些然后应用
DISTINCT
,但这种情况非常罕见,您可能根本不会使用它们。)
Now to the task: You want to get from rows to columns.现在开始任务:您想要从行到列。 This is called pivot and can be achieved with the
PIVOT
keyword, but it is more common to use conditional aggregation.这称为 pivot,可以使用
PIVOT
关键字来实现,但更常见的是使用条件聚合。 "Conditional aggregation" means that you aggregate your data (per person) and then apply a condition. “条件聚合”意味着您聚合您的数据(每人),然后应用条件。 In standard SQL:
在标准 SQL 中:
SELECT MIN('YES') FILTER (WHERE f.value_needed = 'Postal Address')
You can use MIN
or MAX
here, and it is only required for syntax reasons (the FILTER
clause must refer to some aggregation function.您可以在此处使用
MIN
或MAX
,并且仅出于语法原因才需要( FILTER
子句必须引用某些聚合 function。
In SQL Server there is no FILTER
clause, so you use a CASE
expression instead:在 SQL Server 中没有
FILTER
子句,因此您使用CASE
表达式代替:
SELECT MIN(CASE WHEN f.value_needed = 'Postal Address' THEN 'YES' END)
If you want the empty string ''
instead of NULL, apply COALESCE
:如果您想要空字符串
''
而不是 NULL,请应用COALESCE
:
SELECT COALESCE(MIN(CASE WHEN f.value_needed = 'Postal Address' THEN 'YES' END), '')
Columns aliases containing special characters like |
包含特殊字符的列别名,如
|
require quoting.需要报价。 But not single quotes, as these denote string literals.
但不是单引号,因为它们表示字符串文字。 In standard SQL use double quotes, in SQL Server use brackets.
在标准 SQL 中使用双引号,在 SQL 服务器中使用括号。 But better, just avoid them alltogether, by avoiding special characters in names.
但更好的是,通过避免名称中的特殊字符来避免它们。
The complete query:完整查询:
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.