【问题标题】:Union with join in SQL ServerSQL Server 中的联合与联接
【发布时间】:2023-03-29 13:30:01
【问题描述】:

我的 SQL 代码正在执行以下操作:它获取所有“文本”,其中 (O_Top - 前 O_Top)

表格中的数据:

Text      O_Top        O_Left     
------------------------------
 D         536          654
 5         401          544
 1         392          581
 2         395          609
 K         418          666
 1         329          142
 K         421          711
 H         424          753
 9         228          1194
 5         205          666

SQL 代码:

;WITH cte AS
(
    SELECT 
        [Text], [O_Top], [O_Left], 
        ID = ROW_NUMBER() OVER (ORDER BY [O_Left]) 
    FROM
        MyTableName
)
SELECT * 
FROM cte AS c1
LEFT JOIN CTE c2 ON c1.ID = C2.ID - 1
WHERE ABS(c1.O_Top - c2.O_Top) < 30 
  AND ABS(C1.O_Left - c2.O_Left) < 110
ORDER BY C1.[O_Left]

我得到的结果:

Text    O_Top   O_Left  ID      Text    O_Top   O_Left  ID
-----------------------------------------------------------
5        401    544     2        1       392    581     3
1        392    581     3        2       395    609     4
K        418    666     7        K       421    711     8
K        421    711     8        H       424    753     9

我正在寻找像UNION 这样的结果如下:

Text    O_Top   O_Left  ID
---------------------------
5        401    544     2        
1        392    581     3        
K        418    666     7        
K        421    711     8        
1        392    581     3
2        395    609     4
K        421    711     8
H        424    753     9

我正在寻找一种方法来避免列的重复,如果我可以在同一个 SQL 命令中使用类似 distinct 的东西,那就太棒了,这样会向我显示独特的结果,因为现在重复 ID 像 8 和 3

我想了很多,但我觉得这个命令太复杂了,我的大脑无法处理它

非常感谢您的帮助和支持!

【问题讨论】:

  • 旁注:您的样本值与结果表中的值不匹配。
  • 是的,你是对的。对不起,我现在试着编辑一下

标签: sql sql-server-2008 join union


【解决方案1】:

我看不到您的数据和查询之间的关系。但是,如果您想取消透视结果,可以使用cross apply

With cte as (
      Select [Text],[ O_Top], [O_Left],
             ID = Row_Number() over(order bY [O_Left]) 
      from MyTableName
     )
Select v.*
from cte c1 left join
     cte c2
     on c1.ID = C2.ID - 1 cross apply
     (values (c1.[Text], c1.O_Top, c1.O_Left, c1.id),
             (c2.[Text], c2.O_Top, c2.O_Left, c2.id)
     ) v([Text], O_Top, O_Left, id)
where ABS(c1.O_Top - c2.O_Top) < 30 and
      ABS(C1.O_Left - c2.O_Left) < 110;

【讨论】:

  • 谢谢你的补充,这是我第一次知道交叉申请
【解决方案2】:

在您的查询中,您可以在 cte 之间的自连接条件上添加 OR c1.ID = C2.ID +1,然后仅从 c1 中选择。这样,您将同时比较上一行和下一行。如果您希望获得独特的结果,请添加 distinct。

;With cte as
  (Select [Text],[O_Top],[O_Left], ID = Row_Number() over(order bY [O_Left]) 
    from MyTableName)

 Select distinct c1.* 
 from cte as c1
 left Join cte  c2
 on c1.ID = C2.ID - 1 OR c1.ID = C2.ID +1
 where ABS(c1.O_Top - c2.O_Top) < 30 
 and ABS(C1.O_Left - c2.O_Left) < 110
 order bY C1.[O_Left]

或者用ABS(c1.ID - C2.ID) = 1替换两个OR条件

【讨论】:

    【解决方案3】:

    您可以通过对当前 CTE 的联合查询来实现您想要的。试试这个,看看下面的解释:

    WITH cte2 AS (
        SELECT
            c1.Text AS Text1, c1.O_Top AS O_Top1, c1.O_Left AS O_Left1, c1.ID AS ID1,
            c2.Text AS Text2, c2.O_Top AS O_Top2, c2.O_Left AS O_Left2, c2.ID AS ID2
        FROM cte AS c1
        LEFT JOIN cte c2
            ON c1.ID = c2.ID - 1
        WHERE ABS(c1.O_Top - c2.O_Top)   < 30  AND 
              ABS(c1.O_Left - c2.O_Left) < 110
    ),
    cte3 AS (
        SELECT
            Text1 AS Text, O_Top1 AS O_Top, O_Left1 AS O_Left, ID1 AS ID, 1 AS pos
        FROM cte2
        UNION ALL
        SELECT
            Text2, O_Top2, O_Left2, ID2, 2
        FROM cte2
    )
    
    SELECT *
    FROM cte3
    ORDER BY
        pos,
        O_Left
    

    为了完成这项工作,我进行了以下更改:

    • 为原始 CTE 中的两组列使用显式别名
    • cte3 联合查询中添加了一个计算列,以跟踪正在选择的值集
    • 使用上面的计算列从cte3 中选择,按照您想要的方式对记录进行排序

    【讨论】:

    • 非常感谢,我正在尝试,我会更新你:)
    • Amazing 运行良好:D,我能知道这个额外的字段 pos 是如何工作的吗?
    • pos 字段是一个计算列,我们添加它以跟踪记录的来源。您可以在外部ORDER BY 中看到它是如何工作的。
    猜你喜欢
    • 1970-01-01
    • 2017-09-03
    • 1970-01-01
    • 2022-01-12
    • 2020-10-06
    • 1970-01-01
    • 2013-10-10
    • 2012-12-12
    • 1970-01-01
    相关资源
    最近更新 更多