我想为针对具有多行的数据源的查询返回单个任意选择的值。
user_id account role
paa2013 52501050 PD/PI
paa2013 52501050 Principal Investigator
user_id account role
paa2013 52501050 PD/PI
select distinct
user_id,
account,
case
when role = 'PD/PI' then 'PD/PI'
when role = 'Principal Investigator' then 'Principal Investigator'
end
from table
where account = '52501050'
group by
user_id,
account,
case
when role = 'PD/PI' then 'PD/PI'
when role = 'Principal Investigator' then 'Principal Investigator'
end
user_id account role
paa2013 52501050 PD/PI
paa2013 52501050 Principal Investigator
谢谢你的帮助!
要从字面上回答你的问题,你只需要使用MAX()
,因为PD
来自Pr
。
SELECT
user_id,
account,
MAX(role) AS max_role
FROM
table
WHERE
account = '52501050'
GROUP BY
user_id,
account
更广泛地说,有很多选择。
WITH
roles AS
(
SELECT 1 AS rank, 'PD/PI' AS role
UNION ALL
SELECT 2 AS rank, 'Principal Investigator' AS role
UNION ALL
SELECT 3 AS rank, 'another' AS role
),
grouped_data AS
(
SELECT
table.user_id,
table.account,
MIN(roles.rank) AS min_role_rank
FROM
table
INNER JOIN
roles
ON roles.role = table.role
GROUP BY
table.user_id,
table.account
)
SELECT
*
FROM
grouped_data
INNER JOIN
roles
ON roles.role = grouped_data.min_role_rank
要么...
WITH
ranked_data AS
(
SELECT
table.*,
ROW_NUMBER() OVER (PARTITION BY table.user_id,
table.account
ORDER BY role_rank.id
)
AS user_role_rank
FROM
table
CROSS APPLY
(
SELECT
CASE table.role
WHEN 'PD/PI' THEN 1
WHEN 'Principal Investigator' THEN 2
WHEN 'an other' THEN 3
ELSE 4
END
AS id
)
role_rank
)
SELECT
*
FROM
ranked_data
WHERE
user_role_rank = 1
要么...
WITH
roles AS
(
SELECT 1 AS rank, 'PD/PI' AS role
UNION ALL
SELECT 2 AS rank, 'Principal Investigator' AS role
UNION ALL
SELECT 3 AS rank, 'another' AS role
),
ranked_data AS
(
SELECT
table.*,
ROW_NUMBER() OVER (PARTITION BY table.user_id,
table.account
ORDER BY roles.rank
)
AS user_role_rank
FROM
table
INNER JOIN
roles
ON roles.role = table.role
)
SELECT
*
FROM
ranked_data
WHERE
user_role_rank = 1
在一个更完美的世界中,你会有一个user
或account
表,这是受限制的,所以这不会发生。然后是第二个user_role
表,用于与用户/帐户关联的0..many角色。
id | account user_id | role_id
----+--------- ---------+---------
11 | aaaaaaa 11 | 1
22 | bbbbbbb 11 | 2
22 | 2
22 | 3
然后你会有一个role
表,其中包括排名序列....
role_id | rank | name | etc
---------+------+------+-----
1 | 30 | aa | ???
2 | 10 | bb | ???
3 | 20 | cc | ???
然后查询变得相对简洁......
SELECT
*
FROM
user
CROSS APPLY
(
SELECT TOP 1 role.*
FROM user_role
JOIN role ON role.id = user_role.role_id
WHERE user_role.user_id = user.user_id
ORDER BY role.rank
)
AS role
(这表明了不同的结构和不同的方法,其中一个或两个可能对您有所帮助)
编辑:
我也注意到SQL SERVER
现在支持WITH TIES
到另一种方法。 *(类似于ROW_NUMBER()
方法,代码略短......
SELECT TOP(1) WITH TIES
table.*
FROM
table
CROSS APPLY
(
SELECT
CASE table.role
WHEN 'PD/PI' THEN 1
WHEN 'Principal Investigator' THEN 2
WHEN 'an other' THEN 3
ELSE 4
END
AS id
)
role_rank
ORDER BY
ROW_NUMBER() OVER (PARTITION BY table.user_id,
table.account
ORDER BY role_rank.id
)
起初这可能令人困惑。它根据TOP(1)
选择第一行(ORDER BY
)以及与之绑定的所有行。因此,它在功能上与执行WHERE ROW_NUMBER() = 1
相同(但SQL Server不允许ROW_NUMBER()
在WHERE
子句中。)
您可以将row_number()
与ORDER BY
子句一起使用,在该子句中为角色分配优先级。
SELECT user_id,
account,
role
FROM (SELECT user_id,
account,
role,
row_number() OVER (PARTITION BY user_id,
account
ORDER BY CASE role
WHEN 'PD/PI' THEN
1
WHEN 'Principal Investigator' THEN
2
...
END) rn
FROM table) x
WHERE rn = 1;
如果要保留给定选择列的顶行,只需使用“限制”功能。 Limit函数旁边的参数是针对满足给定查询应返回的行数。
select user_id, account, role from raw_data limit 1;
但是,如果要保留给定userid-account-role组合的第一个条目,请将数据子集化为给定条件并使用该限制。例如,下面的补丁会将选择查询限制为特定帐户(= 52501050)并返回顶行。
select user_id, account, role from raw_data where account = '52501050' limit 1;