2012-01-15 2 views
1

У меня есть одна таблица базы данных, в которой хранятся записи недели.SQL self join несколько раз

Id  Value  WeekId 
1   1.0000 1 
2   2.0000 1 

В течение одной недели может быть до трех записей.

Так что я решил, используя автообъединение бы решить эту

SELECT w1.Value, w2.Value, w3.Value 
FROM [List].[dbo].[testWeekEntries] as w1 
LEFT OUTER JOIN [List].[dbo].[testWeekEntries] as w2 ON w1.WeekId = w2.weekId 
LEFT OUTER JOIN [List].[dbo].[testWeekEntries] as w3 ON w2.WeekId = w3.WeekId 
WHERE w1.Id < w2.Id AND w2.Id < w3.Id 

Проблема: Это Worls штраф с максимальным количеством записей, однако он не тянет обратно строку с одним или двумя входами.

Есть ли другой тип соединения, который я могу использовать, чтобы вытащить строку только с одной или двумя записями или другим способом приблизиться к этому?

ответ

2

Эти записи не возвращаются, потому что ваш пункт WHERE явно фильтрует их, когда объединенные таблицы возвращают значения NULL.

Это решение добавляет к каждой записи последовательный номер рулона, перезапуская до 1 на каждую неделю. Это позволяет использовать этот порядковый номер в PIVOT заявлении

SQL 2000 Заявление

SELECT * 
FROM (
      SELECT (SELECT COUNT(*) 
        FROM testWeekEntries 
        WHERE Id <= we.Id 
          AND WeekId = we.WeekId) as rn 
        , Value 
        , WeekId 
      FROM testWeekEntries we 
     ) q 
PIVOT (MAX(Value) FOR rn IN ([1],[2],[3])) AS PVT 

SQL 2008 Заявление

;WITH q AS (
SELECT rn = ROW_NUMBER() OVER (PARTITION BY WeekId ORDER BY Id) 
     , Id 
     , Value 
     , WeekId 
FROM [testWeekEntries] as w1 
) 
SELECT Value 
     , (SELECT Value FROM q q1 WHERE q1.rn = q.rn + 1 AND q1.WeekId = q.WeekId) 
     , (SELECT Value FROM q q2 WHERE q2.rn = q.rn + 2 AND q2.WeekId = q.WeekId) 
FROM q 
WHERE q.rn = 1 
+0

Я попробовал это, однако, теперь он возвращает несколько строк, где он должен только вернуть одну строку в неделю Id – user900566

+0

@ user900566 - ты прав , виноват. Какие СУБД вы используете? –

+0

Ms SQL server 2008 – user900566

1

Вам нужно будет добавить в ваш где клаузулы о возможность, что w2.Id is null или w3.id is null

Так что-то вроде

WHERE 
    (w2.Id is null and w3.id is null) or 
    (w3.id is null and w1.id < w2.id) or 
    (w1.id < w2.id and w2.id < w3.id) 
1

Вы можете также использовать PIVOT

;WITH CTE AS 
(
SELECT Value, 
     WeekId, 
     ROW_NUMBER() OVER (PARTITION BY WeekId ORDER BY Id) AS RN 
FROM [List].[dbo].[testWeekEntries]  
) 
SELECT * 
FROM CTE 
PIVOT (MAX(Value) FOR RN IN ([1],[2],[3])) AS PVT 
+0

+1 Thx Martin, PIVOT все еще не моя чашка чая, но я должен спросить: не существует более легкого решения для этого, не прибегая к CTE и добавляя ROW_NUMBER. –

+0

@Lieven - Не то, чтобы я могу думать! –

+1

Вы не представляете, как утешительно это для меня . –