【问题标题】:SQL Server 2005: How to join table rows only onceSQL Server 2005:如何只连接一次表行
【发布时间】:2014-07-16 04:42:06
【问题描述】:

我想我已经看到了有关 MySQL 的类似问题的答案,但我正在努力寻找适用于 SQL Server 2005 的答案。

所以我有一张这样的桌子:

| ID | RelationalID | Year
----------------------------
| 1  | A            | 2014
| 2  | A            | 2014
| 3  | B            | 2014
| 4  | A            | 2015
| 5  | B            | 2015

当我加入 RelationID 匹配但年份不同的同一个表时,我想要这样的结果:

| 2014_ID | 2015_ID | RelationalID |
------------------------------------
| 1       | 4       | A            |
| 2       | NULL    | A            |
| 3       | 5       | B            |

但是标准的 JOIN 最终会得到重复的匹配:

| 2014_ID | 2015_ID | RelationalID |
------------------------------------
| 1       | 4       | A            |
| 2       | 4       | A            |
| 3       | 5       | B            |

有没有办法在 SQL Server 2005 中连接两个表,其中右表中的匹配项只连接一次?

我试过这个查询没有成功:

SELECT * FROM myTable 
LEFT JOIN (SELECT * FROM myTable) AS t ON t.RelationalID = myTable.RelationalID 
WHERE myTable.Year = 2014 and t.Year = 2015

【问题讨论】:

  • 能不能把失效的查询加进去?
  • 示例非工作查询为:SELECT * FROM myTable LEFT JOIN (SELECT * FROM myTable) AS t ON t.RelationalID = myTable.RelationalID WHERE myTable.Year = 2014 和 t.Year = 2015
  • 您能解释一下为什么 {2,4,A} 不是有效输出,而 {1,4,A} 是有效输出吗?
  • 除非您想进行非常复杂的查询,否则基本上这是不可能的。那么接下来的问题是,为什么要以想要查看的形式呈现数据呢?
  • @Anon {2,4,A} 无效,因为 2015_ID 4 已在集合 {1,4,A} 中匹配

标签: sql sql-server sql-server-2005


【解决方案1】:

您可以根据 ROW_NUMBER 获得结果,但您需要一个如何分配它们的规则,我假设它是基于 Id 的。

;WITH cte AS
(SELECT Id,
        RelationalId,
        year,
        row_number() 
        over (partition by RelationalId, year
              order by Id) as rn
FROM [YourTable] 
)
select t1.id as Id_2014,t2.id as Id_2015, t1.RelationalId
from cte as t1 left join cte as t2
on t1.RelationalId = t2.RelationalId
and t1.rn = t2.rn
and t2.year = 2015 
where t1.Year = 2014 

这是基于 TMNT2014 的fiddle

【讨论】:

  • 带有分区的 CTE 方法似乎可以解决问题。此方法比@Kevin Cook 的答案获得更多结果,因此我将其标记为已接受的答案。我不熟悉 PARTITION,所以这很有帮助。谢谢大家的帮助。
【解决方案2】:

下面的 Sql 将为您提供您正在寻找的结果,但正如我之前所说,复杂性将取决于您在表中拥有的原始数据集。这是 SQL Fiddle - http://sqlfiddle.com/#!3/d6300/24 - 祝你好运!

;WITH CTE_Union AS
(SELECT 

    a.Id AS Id2014,
    NULL AS Id2015,
    a.RelationalId
  FROM [YourTable] a
  WHERE a.Year = 2014 
  UNION
  SELECT 
    NULL AS Id2014,
    b.Id AS Id2015,
    b.RelationalId
  FROM [YourTable] b
  WHERE b.Year = 2015)
SELECT Distinct CASE WHEN Id2014 IS NULL THEN (SELECT MIN(Id2014) FROM CTE_Union C WHERE    C.RelationalId =M.RelationalId) ELSE Id2014 END AS ID2014 , 
CASE WHEN Id2015 IS NULL AND Id2014 =  (SELECT MIN(Id2014) FROM CTE_Union C2 WHERE      C2.RelationalId =M.RelationalId) THEN (SELECT MIN(Id2015) FROM CTE_Union C WHERE       C.RelationalId =M.RelationalId) ELSE Id2015 END
,RelationalID
FROM CTE_Union M

【讨论】:

    【解决方案3】:
    DECLARE @MyTable TABLE
     (
        ID INT,
        RelationalID VARCHAR(10),
        [Year] INT
    )
    
    INSERT INTO @MyTable
    VALUES
    ( 1 ,'A', 2014),
    ( 2 ,'A', 2014),
    ( 3 ,'B', 2014),
    ( 4 ,'A', 2015),
    ( 5 ,'B', 2015)
    
    ;WITH TEST AS
    (
        SELECT 
            a.Id AS Id2014,
            NULL AS Id2015,
            a.RelationalId,
            RANK() OVER (PARTITION BY RelationalId ORDER BY ID) Ranked
        FROM @MyTable a
        WHERE a.Year = 2014 
        UNION
        SELECT 
            NULL AS Id2014,
            b.Id AS Id2015,
            b.RelationalId,
            RANK() OVER (PARTITION BY RelationalId ORDER BY ID) Ranked
        FROM @MyTable b
        WHERE b.Year = 2015
    )
    SELECT
        t1.Id2014,
        t2.Id2015,
        t1.RelationalID
    FROM TEST t1
    LEFT JOIN TEST t2
        ON t1.Ranked = t2.Ranked
        AND t1.RelationalID = t2.RelationalID
        AND t2.Id2015 IS NOT NULL
    WHERE t1.Id2014 IS NOT NULL
    ORDER BY t1.Id2014
    

    我使用了一个联合,然后按关系 id 对每一边进行排名,然后加入它们。 这是输出:

    Id2014  Id2015  RelationalID
    1   4   A
    2   NULL    A
    3   5   B
    

    【讨论】:

      【解决方案4】:

      可能有几种方法可以解决这个问题,但下面显示了在查询中使用“派生表”的示例。

      SELECT
        q1.Id AS [2014_Id],
        q2.Id AS [2015_Id],
        q1.RelationalId
      FROM (SELECT 
              MAX(a.Id) AS Id,
              a.RelationalId
            FROM [table] a
            WHERE a.Year = 2014
            GROUP BY 
              a.RelationalId) q1
      INNER JOIN (SELECT 
                    MAX(b.Id) AS Id,
                    b.RelationalId
                  FROM [table] b
                  WHERE b.Year = 2015
                  GROUP BY 
                      b.RelationalId) q2 
        ON q2.RelationalId = q1.RelationalId
      

      【讨论】:

      • 这行不通 - 即使它得到不同的行,它仍然可以多次匹配右表中的同一行。
      • 那么在那种情况下你想要哪个 ID。第一个还是最后一个?或者如果中间有 3 个?有关系吗?
      • @spongesuck 修改了答案。也许这就是你要找的
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-03
      • 2010-09-10
      • 2010-10-31
      相关资源
      最近更新 更多