当左连接仅在某些行上加入时选择结果

时间:2013-08-14 03:33:52

标签: sql sql-server-2008

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

  1. 如果table1中的所有行都与表2中的行匹配,那么它应该通过验证
  2. 如果table1中的所有行与table2中的行不匹配,那么它应该通过。
  3. 如果table1中的某些行加入table2而其他行没有加入,那么它应该失败。
  4. 我在下面添加了三个数据集来显示它应该通过和失败的时间

    数据集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与表2中的任何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

2 个答案:

答案 0 :(得分: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时测试通行证。

答案 1 :(得分:0)

这不应该失败吗?因为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时,他可以通过,否则他不会