【问题标题】:Select a result when left join only joins on some rows左连接仅在某些行上连接时选择结果
【发布时间】:2013-08-14 12:43:16
【问题描述】:

我需要实现一个检查 2 个表的内容的业务验证规则。该规则有 3 个部分:

  1. 如果 table1 中的所有行都与 table 2 中的行匹配,那么它应该通过验证
  2. 如果 table1 中的所有行都不匹配 table2 中的行,那么它应该通过。
  3. 如果 table1 中的某些行连接到 table2 而其他行没有连接,那么它应该会失败。

我在下面添加了三个数据集来显示它应该何时通过和失败

数据集 1(这应该通过):

Table1
ID   Other Column
1    xxxx
2    xxxx
3    xxxx
4    xxxx

Table2
ID    FK   OtherColumn
1     1    xxxx
2     2    xxxx
3     3    xxxx
4     4    xxxx

数据集 2(这应该通过):

Table1
ID   Other Column
1    xxxx
2    xxxx
3    xxxx
4    xxxx

Table2
ID    FK   OtherColumn
1     5    xxxx
2     6    xxxx
3     7    xxxx
4     8    xxxx

数据集 3(这应该会失败,因为 table1 中的 ID 2 和 3 与 Table2 中的任何 FK 都不匹配):

Table1
ID   Other Column
1    xxxx
2    xxxx
3    xxxx
4    xxxx

Table2
ID    FK   OtherColumn
1     1    xxxx
2     5    xxxx
3     6    xxxx
4     4    xxxx

您可以通过执行以下操作来连接这两个表:

SELECT *
FROM Table1
INNER JOIN Table2
ON Table1.ID = Table2.FK

Table2 对于Table1 中的每条记录将有 0 或 1 条记录

到目前为止,我弄清楚如何做到这一点的唯一方法是选择并比较行数:

SELECT COUNT(Table1.ID)
FROM Table1
INNER JOIN Table2
ON Table1.ID = Table2.FK

和比较

SELECT COUNT(Table1.ID)
FROM Table1

我认为它有效,但感觉应该有更简单的方法来做到这一点。

如果有区别,数据库是 Microsoft SQL 2008

【问题讨论】:

  • 为什么你有时写one,有时写1,却从不写two,只写2
  • @vol7ron - 既然你提到了,我停下来想一想,我可能经常这样做,但我不知道为什么。

标签: sql sql-server-2008


【解决方案1】:

你可以这样做:

SELECT count(distinct t1.id) as NumInT1, count(distinct t2.fk) as NumInT2andT1
FROM Table1 t1 left join
     Table2 t2
     ON t1.ID = t2.FK;

如果您知道Table2 没有FK 的重复值,您可以将其简化为:

SELECT count(t1.id) as NumInT1, count(t2.fk) as NumInT2andT1
FROM Table1 t1 left join
     Table2 t2
     ON t1.ID = t2.FK;

NumInT2andT1 等于NumInT10 时,您测试通过。

【讨论】:

    【解决方案2】:

    这不应该失败吗?因为 ID 4 匹配,并且是唯一匹配的

    Dataset 2 (This should pass):
    
    Table1
    ID   Other Column
    1    xxxx
    2    xxxx
    3    xxxx
    4    xxxx
    
    Table2
    ID    FK   OtherColumn
    1     4    xxxx
    2     5    xxxx
    3     6    xxxx
    4     7    xxxx
    

    好的,无论如何,您可以通过 COUNT 行来控制它。我将制作一个伪代码,您可以在过程或触发器中使用它

    DECLARE @matchRows int;
    DECLARE @normalRows int;
    
    SELECT @matchRows=COUNT(*)
    FROM Table1 t1 JOIN Table2 t2 ON t1.id = t2.FK
    
    SELECT @normalRows=COUNT(*)
    FROM Table1 t1
    
    IF(@matchRows>0)
    BEGIN
         IF(@matchRows<@normalRows)
         BEGIN
              -Here your code in case of fail!
         END
    END
    

    你可能会做

    DECLARE @booleanControl BIT;
    
    SELECT @booleanControl = CAST(
       CASE WHEN EXISTS(SELECT *
                        FROM Table1 t1 LEFT JOIN Table2 t2 ON t1.ID = t2.KF
                        WHERE COUNT(t1.ID) = COUNT(t2.FK) OR COUNT(t2.FK) = 0
                        ) THEN 1 
                        ELSE 0 
       END 
       AS BIT)
    

    当这个 booleanControl 返回 TRUE 时他可以通过,否则他不会通过

    【讨论】:

    • 你对数据集 2 的权利。对不起,我塞满了测试数据。查看最新编辑。您的伪代码本质上就是我现在正在做的事情。我一直在寻找更好的方法。
    • 好的,看看新答案能不能帮到你
    猜你喜欢
    • 2013-08-22
    • 1970-01-01
    • 2017-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多