2013-06-14 3 views
1

Учитывая (упрощенно) таблица называется Ответы, какЗапроса на возврат одной строки на человек

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' 

, а затем рассматривает в коде, который Первоочередные столбцы являются ненулевыми, но возвращает дополнительную строку для Тома

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 

Я уверен, что, должно быть, я пропустил что-то простое, но не могу наложить на него свой палец.

Что мне не хватает? Есть ли лучший способ подойти к этой проблеме?

+0

Используйте DISTINCT заявления? – Edper

ответ

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.

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

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' 
+0

Это возвращает лишние, нежелательные строки. Кроме того, он не выполняется, потому что имена столбцов неоднозначны (я заменил * на тест). –

+0

Вот почему я явственен в столбцах, так что он не будет двусмысленным, поэтому вместо него будет помечена звездочка, что сделает его неоднозначным. – Edper

0

, если я правильно понять вам, что вы должны получить желаемый результат от

SELECT * 
FROM (SELECT * FROM Answers WHERE Priority = 'Low') aLow 
FULL JOIN (SELECT * FROM Answers WHERE Priority = 'High') aHigh 
    ON aLow.Person = aHigh.Person 
+0

Нет, это возвращает только две строки, где левый приоритет - «Низкий». Кроме того, сторона соединения должна быть указана в SQL Server. Я предполагаю, что вы имели в виду «LEFT OUTER JOIN». –

+0

На самом деле я имел в виду полное вступление - извините, исправлено. Я не понимал, что у вас может быть более одной высокой или низкой записи на человека. –

Смежные вопросы