查询每人返回一行

时间:2013-06-14 22:52:21

标签: sql sql-server

给出一个名为Answers的(简化)表,如

Id  Person      Answer      Priority
1   Tom         France      Low       
2   Tom         Germany     High      
3   Fred        England     Low       
4   Amy         Italy       High      

我想编写一个SQL查询,每个人返回一行,表明他们的最高优先级答案。我的想法是使用自我加入

SELECT *
FROM Answers aLow
LEFT OUTER JOIN Answers aHigh 
    ON aLow.Person = aHigh.Person 
       AND aLow.Priority = 'Low' 
       AND aHigh.Priority = 'High'

然后在代码中检查哪些优先级列是非空的,但是为Tom

返回一个额外的行
Id  Person      Answer      Priority    Id      Person  Answer  Priority
1   Tom         France      Low         2       Tom     Germany High      
2   Tom         Germany     High        NULL    NULL    NULL    NULL
3   Fred        England     Low         NULL    NULL    NULL    NULL
4   Amy         Italy       High        NULL    NULL    NULL    NULL

使用这种方法,所需的输出将是

Id  Person      Answer      Priority    Id      Person  Answer  Priority
1   Tom         France      Low         2       Tom     Germany High      
3   Fred        England     Low         NULL    NULL    NULL    NULL
4   Amy         Italy       High        NULL    NULL    NULL    NULL

我确信我必须遗漏一些简单的东西,但不能指责它。

我错过了什么?有没有更好的方法来解决这个问题?

4 个答案:

答案 0 :(得分:1)

您可以使用带有ROW_NUMBER窗口函数的公用表表达式:

WITH cte 
     AS (SELECT [id], 
                [person], 
                [answer], 
                [priority], 
                RN = Row_number() 
                       OVER ( 
                         partition BY person 
                         ORDER BY CASE WHEN priority = 'High' THEN 0 ELSE 1 END 
                       ASC) 
         FROM   dbo.answers) 
SELECT [id], 
       [person], 
       [answer], 
       [priority] 
FROM   cte 
WHERE  rn = 1 

DEMO

ID  PERSON  ANSWER   PRIORITY
4   Amy     Italy    High
3   Fred    England  Low
2   Tom     Germany  High

Ranking Functions

答案 1 :(得分:1)

这是一种方法:

with priorityRank as
(
  select *
    , priorityRank = row_number() over (partition by Person
        order by case Priority when 'High' then 1 when 'Low' then 2 end
          , Id)
  from
  Answers
)
select Id
  , Person
  , Answer
  , Priority
from priorityRank
where priorityRank = 1

SQL Fiddle with demo

答案 2 :(得分:0)

您是否尝试使用DISTINCT:

SELECT DISTINCT id, Person,Answer, Priority
FROM Answers aLow
LEFT OUTER JOIN Answers aHigh 
ON aLow.Person = aHigh.Person 
   AND aLow.Priority = 'Low' 
   AND aHigh.Priority = 'High'

答案 3 :(得分:0)

如果我正确理解你,你应该从

获得理想的结果
SELECT *
FROM (SELECT * FROM Answers WHERE Priority = 'Low') aLow
FULL JOIN (SELECT * FROM Answers WHERE Priority = 'High') aHigh 
    ON aLow.Person = aHigh.Person