SQL self join multiple times

2019-03-01 06:58发布

I have a single database table that stores week entries.

Id        Value     WeekId
1         1.0000    1
2         2.0000    1

There can be up to three entries with the same week.

So I figured using a self join would solve this

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

The problem: It worls fine with the maximum number of entries however it doesn't pull back a row with one or two entries.

Is there a different type of join I can use to pull back a row with only one or two entries or a different way of approaching this?

3条回答
该账号已被封号
2楼-- · 2019-03-01 07:24

You can also use 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
查看更多
神经病院院长
3楼-- · 2019-03-01 07:29

You will need to add in your where clause the possibility that w2.Id is null or w3.id is null

So something like

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)
查看更多
姐就是有狂的资本
4楼-- · 2019-03-01 07:42

These entries are not returning because your WHERE clause explicitly filters them out when the joined tables return NULL values.

This solution adds a sequential rownumber to each record, restarting to 1 for each week. This allows you to use this sequential number in a PIVOT statement

SQL 2000 Statement

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 Statement

;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
查看更多
登录 后发表回答