【问题标题】:Joining on non unique columns加入非唯一列
【发布时间】:2016-02-02 23:47:09
【问题描述】:

表 1

1 A 1 1
2 A 1 2
5 A 1 1
6 B 2 1

表 2

1 1 12
2 2 45
3 5 22
4 6 21

table1.col1 是 table2.col2 的 FK

你想复制 col2 = A 的值,并且 col2 = AA :

1 A  1 1
2 A  1 2
5 A  1 1
6 B  2 1
7 AA 1 1   <- New
8 AA 1 2   <- New
9 AA 1 1   <- New

如何将表 2 连接到新结果集,以使 A 存在的值也存在于 AA?

想要的结果:

1 A  1 1 | 1 1 12
2 A  1 2 | 2 2 45
5 A  1 1 | 3 5 22
6 B  2 1 | 4 6 21
7 AA 1 1 | 1 1 12
8 AA 1 2 | 2 2 45
9 AA 1 1 | 3 5 22

【问题讨论】:

  • 可以将 7,8,9 添加到 table1 还是仅在运行时导出 AA 值?基于现有数据?您可以在 table1 中为 parentID 添加一列并使用递归吗?
  • AA 的值是派生的运行时,两个表的第 1 列是自动增量标识列。不,我不能在表 1 中添加一列,但我可以创建一个子查询并使用它进行解析

标签: sql sql-server join


【解决方案1】:

未经测试:

逻辑似乎很可靠,但我没有数据,测试环境可以尝试这个...... 您可以使用联合和(内联视图或公用表表达式)来完成此操作。

首先,我们使用两组所需数据构建 table1(下面的内联视图 A)。这种方法使连接变得简单。这是使用联合语句和硬编码 AA 值来完成的,同时将集合限制为仅 A,然后在基集中联合。

然后我们像往常一样加入回 table2。

我使用 row_number() 并按 col 2 排序来识别单个值以增加最大 ID。 1 表示 a 的第一行,2 表示 a 的第二行,3 表示 a 的第三行,基于种子 6,这是 table1 中的最大值。

我使用 parent_ID 始终标识要加入 table2 的相关记录。

内嵌视图

Select *  --(though you should spell out desired columns)
from (Select ROW_NUMBER() OVER(ORDER BY Col2)+C.mID, 'AA', col3, col4, col1 as Parent_ID
      from table1
      CROSS JOIN (select max(col1) mID from table1) C  
      where table1.col2 = 'A'
  record 
      UNION ALL
      Select col1, Col2, col3, col4, col1 as Parent_ID
      from table1)  A

INNER JOIN table2
 on table2.col2 = A.parent_ID

CTE:

With cte as (Select  ROW_NUMBER() OVER(ORDER BY Col2)+C.mID col1, 'AA' col2, col3, col4, col1 as Parent_Id
    FROM table1
    CROSS JOIN (select max(col1) mID from table1) C
    WHERE table1.col2 = 'A'
    UNION ALL
    SELECT col1, Col2, col3, col4, col1 as Parent_Id
    from table1) 

 SELECT * --(though you should spell out desired columns)
 FROM cte
 INNER JOIN table2
   on table2.col2 = cte.Parent_Id

【讨论】:

    【解决方案2】:
        declare @maxCol1 int
    
        select @maxCol1 = max(col1)
        from table1
    
    
        select a.col1,
        a.col2,
        a.col3,
        a.col4,
        b.col1,
        b.col2,
        b.col3
        from table1 a
        join table2 b
        on a.col1 = b.col2
    
        union all
    
        select a.col1 + @maxCol1 as col1,
        a.col2 + a.col2 as col2,
        a.col3,
        a.col4,
        b.col1,
        b.col2,
        b.col3
        from table1 a
        join table2 b
        on a.col1 = b.col2
        where a.col2 = 'A'
    

    【讨论】:

      【解决方案3】:

      单独考虑每个值 A/B/AA,并使用窗口函数查找 col3 和 col4 上的滞后超前

      将每个“prev_col3、col3、next_col3、prev_col4、col4、next_col4”视为唯一的“上下文”标识符并加入。这就是我们可以避免混淆数据中的第 7 行和第 9 行的方法;对于 col3 和 col4,它们具有不同的 prev/next 滞后/领先值。

      我们需要控制 null 情况(我将 null 设置为 -1)以使连接起作用。

      您可以将其复制/粘贴到 SQL Server 中以查看它的工作原理:

      CREATE TABLE #TABLE1 (col1 INT, col2 varchar(5), col3 INT, col4 INT)
      CREATE TABLE #TABLE2 (col1 INT, col2 INT, col3 INT)
      
      INSERT INTO #TABLE1
      select 1 col1,'A' col2, 1 col3, 1 col4 union
      select 2 col1,'A' col2, 1 col3, 2 col4 union
      select 5 col1,'A' col2, 1 col3, 1 col4 union
      select 6 col1,'B' col2, 2 col3, 1 col4 union
      select 7 col1,'AA' col2, 1 col3, 1 col4 union
      select 8 col1,'AA' col2, 1 col3, 2 col4 union
      select 9 col1,'AA' col2, 1 col3, 1 col4 
      
      INSERT INTO #TABLE2
      select 1 col1, 1 col2, 12 col3 union
      select 2 col1,2 col2, 45 col3 union
      select 3 col1,5 col2, 22 col3 union
      select 4 col1,6 col2, 21 col3
      
      
      select 
          Bu.col1, bu.col2, bu.col3, bu.col4, t2.col1, t2.col2, t2.col3
      from 
         (
          select 
             col1, col2,
             lag(col3) over (order by col1 asc) prev_col3,
             col3,
             lead(col3) over (order by col1 asc) next_col3,
             lag(col4) over (order by col1 asc) prev_col4,
             col4,
             lead(col4) over (order by col1 asc) next_col4
          from 
             #TABLE1 t1 where col2 in ('A')
          ) A   
          join 
         ( /*bu big union*/
          select 
             col1, col2,
             lag(col3) over (order by col1 asc) prev_col3,
             col3,
             lead(col3) over (order by col1 asc) next_col3,
             lag(col4) over (order by col1 asc) prev_col4,
             col4,
             lead(col4) over (order by col1 asc) next_col4
          from 
             #TABLE1 t1 where col2 in ('A')
          UNION
          select 
             col1, col2,
             lag(col3) over (order by col1 asc) prev_col3,
             col3,
             lead(col3) over (order by col1 asc) next_col3,
             lag(col4) over (order by col1 asc) prev_col4,
             col4,
             lead(col4) over (order by col1 asc) next_col4
          from 
             #TABLE1 t1 where col2 in ('AA')
          ) bu
          on 
         ( 
          a.col3 = bu.col3 and isnull(a.prev_col3,-1) = isnull(bu.prev_col3,-1) and 
          isnull(a.next_col3,-1) = isnull(bu.next_col3,-1) and 
          a.col4 = bu.col4 and isnull(a.prev_col4,-1) = isnull(bu.prev_col4,-1) and 
          isnull(a.next_col4,-1) = isnull(bu.next_col4 ,-1)
          )
          join
          #TABLE2 t2
          on 
          a.col1 = t2.col2
          UNION
          select 
             t1.col1, t1.col2, t1.col3, t1.col4,
             t2.col1, t2.col2, t2.col3
          from 
             #TABLE1 t1 
             join #TABLE2 t2 on t1.col1 = t2.col2
          where t1.col2 = 'B'
          order by 1 asc
      
      drop table #TABLE1
      drop table #TABLE2
      

      【讨论】:

        猜你喜欢
        • 2021-04-25
        • 2021-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多