【问题标题】:SQL self join multiple timesSQL 自连接多次
【发布时间】:2012-01-15 12:26:24
【问题描述】:

我有一个存储周条目的数据库表。

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

问题:它适用于最大条目数,但它不会拉回包含一个或两个条目的行。

是否可以使用不同类型的连接来拉回只有一个或两个条目的行,或者以不同的方式处理这个问题?

【问题讨论】:

    标签: sql sql-server join sql-server-2000


    【解决方案1】:

    这些条目没有返回,因为当连接表返回 NULL 值时,您的 WHERE 子句将它们显式过滤掉。

    此解决方案为每条记录添加一个连续的行号,每周重新开始为 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
    

    【讨论】:

    • 我试过这个但是它现在带回多行,它应该每周只带回一行 ID
    • @user900566 - 你是对的,我的错。您使用的是什么 DBMS?
    • @user900566 - 我已调整答案以解决该错误。
    • @user900566 - 老实说,我有一种烦人的感觉,它可以简化,但我似乎无法理解。
    • 刚刚发现productino服务器是ms sql 2000,没有row_number()功能
    【解决方案2】:

    您需要在 where 子句中添加 w2.Id is nullw3.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)
    

    【讨论】:

      【解决方案3】:

      你也可以使用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
      

      【讨论】:

      • +1 谢谢马丁,PIVOT 仍然不是我的一杯茶,但我不得不问:如果不使用 CTE 并添加 ROW_NUMBER,是否有更简单的解决方案。
      • @Lieven - 我想不到!
      • 你不知道这对我来说有多舒服 .
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-04
      • 1970-01-01
      • 1970-01-01
      • 2017-06-02
      相关资源
      最近更新 更多