基于多个字段的全外连接

4

以下是我面临的情况:

我有两个表格A和B。如果记录在表格A中,而不在表格B中,则需要将它们添加到表格B中。如果记录在表格B中,而不在表格A中,则需要从表格B中删除它们。关键在于它是由两个键的混合组成的独特组合。

Table A    
Operation_Key    Part_Key  
1                1
1                2
2                1
2                3

Table B
Operation_Key    Part_Key  Record_Key
1                1         1
2                1         2
2                3         3
2                4         4

我正在尝试获取正确的查询类型,以便返回的结果看起来像:

Results
Operation_Key        Part_Key  Record_Key   Action
1                    2         NULL         Add
2                    4         4            Delete

我目前的查询类似于这样:

The query I have so far looks like similar to this:

CREATE TABLE #Action_Table
(
  Action VARCHAR(6),
  Action_Bit INT,
  Operation_Key INT,
  Record_Key INT,
  Part_Key INT
)
INSERT INTO #Action_Table
SELECT 
  CASE
    WHEN WS.Operation_Key IS NULL THEN 'Delete'
    WHEN WS.Operation_Key IS NOT NULL THEN 'Add'
  END Action,
  CASE
    WHEN WS.Operation_Key IS NULL THEN '0'
    WHEN WS.Operation_Key IS NOT NULL THEN '1'
  END Action_Bit,
  CASE
    WHEN WS.Operation_Key IS NULL THEN WC.Operation_Key
    WHEN WS.Operation_Key IS NOT NULL THEN WS.Operation_Key
  END Operation_Key,
  CASE
    WHEN WS.Operation_Key IS NULL THEN WC.Record_Key
    WHEN WS.Operation_Key IS NOT NULL THEN NULL
  END Workcenter_Component_Key,
  CASE
    WHEN WS.Operation_Key IS NULL THEN WC.Part_Key
    WHEN WS.Operation_Key IS NOT NULL THEN WS.Part_Key
  END Part_Key
FROM #WS_Part_Table WS
FULL OUTER JOIN #WC_Part_Table WC
  ON WC.Part_Key = WS.Part_Key
 AND WC.Operation_Key = WS.Operation_Key
WHERE (WS.Part_Key IS NULL or WC.Part_Key IS NULL) AND (WS.Operation_Key IS NULL or WC.Operation_Key IS NULL)

#WS_Part_Table和#WC_Part_Table都是我使用查询构建的临时表,但我的困境在于,我必须在我感兴趣的操作键上预先查询#WC_Part_Table查询,否则我会得到太多的结果。

这是我用来创建#WC_Part_Table的查询。

    CREATE TABLE #WC_Part_Table
    (
      Operation_Key INT,
      Record_Key INT,
      Part_Key INT
    )
    -- Workcenter Component Table
    INSERT INTO #WC_Part_Table
    SELECT
      O.Operation_Key,
      WC.Record_Key,
      WC.Part_Key
    FROM Workcenter_Component WC
    JOIN Operation O
      ON O.Default_Workcenter_Key = WC.Workcenter_Key

 /* There is some reason why this next line is needed */
    WHERE O.Operation_Key = 23149

你使用的是哪个关系型数据库管理系统和版本?顺便问一下,你需要一个查询来解释你的操作吗?难道你不能只删除或添加一行吗? - Lamak
这个查询是为了生成一份报告,让人类进去进行编辑(长话短说)。不用说,我没有直接访问数据库来添加/插入/更新/删除记录的权限,只能查询并告诉别人该怎么做。 - NA Slacker
哦,那有点乱了……那你应该采纳@Cybernate的答案。 - Lamak
如果您将WC_Part_TableWS_Part_Table作为视图,并且不使用 WHERE O.Operation_Key = 23149 条件,则可能会发现更好的结果。然后,您可以使用KenTaylor或Cybernate的视图(如果要手动检查并且结果太多,则可以添加任何此类条件)。 - ypercubeᵀᴹ
3个回答

9
尝试以下步骤以获得您发布的结果:
SELECT COALESCE(a.Operation_Key, b.Operation_Key) Operation_Key,
             COALESCE(a.Part_Key, b.Part_Key) Part_Key,
             Record_Key,
             CASE 
                WHEN Record_Key IS NULL THEN 'Add'
                ELSE 'Delete'
            END Action
  FROM TableA a FULL OUTER JOIN TableB b
      ON a.Operation_Key = b.Operation_Key
        AND a.Part_Key = b.Part_Key
 WHERE (a.Operation_Key IS NULL) OR (b.Operation_Key IS NULL)

测试脚本:

CREATE TABLE #TableA     
(       
    Operation_Key INT,       
    Part_Key INT
) 

INSERT INTO #TableA
SELECT 1,1 
UNION
SELECT 1,2 
UNION
SELECT 2,1 
UNION
SELECT 2,3 

CREATE TABLE #TableB
(       
    Operation_Key INT,       
    Part_Key INT,
    Record_Key INT
) 

INSERT INTO #TableB
SELECT 1,1,1 
UNION
SELECT  2,1,2
UNION
SELECT 2,3,3 
UNION
SELECT 2,4,4 


SELECT  COALESCE(a.Operation_Key, b.Operation_Key) Operation_Key,              
                COALESCE(a.Part_Key, b.Part_Key) Part_Key,              
                Record_Key,              
                CASE                  
                    WHEN Record_Key IS NULL THEN 'Add'                 
                    ELSE 'Delete'             
                END Action   
    FROM    #TableA a FULL OUTER JOIN #TableB b       
        ON  a.Operation_Key = b.Operation_Key         
     AND    a.Part_Key = b.Part_Key  
 WHERE (a.Operation_Key IS NULL) OR (b.Operation_Key IS NULL) 

输出:

Operation_Key   Part_Key    Record_Key  Action
1   2   NULL    Add
2   4   4   Delete

重写查询以利用coalesce函数,但仍未起作用。我得到了所有ADD记录,没有DELETE记录。此外,ADD记录包括表中已经存在的所有记录。 - NA Slacker
2
@NA Slacker:我已经添加了测试脚本来检查查询,并得到了所需的结果。请检查一下。 - Chandu
@Ken:我认为可以使用Record_key的Null值来确定记录是应该添加还是删除。我已经发布了测试脚本和结果,得到了期望的输出。 - Chandu
@NA Slacker:你能同时发布WS_Part_Table的代码吗?这可能是相关的。 - ypercubeᵀᴹ
我认为我已经找到了问题的根源。我的查询由于在构建原始TEMP表之一时出现幕后行计数限制而被终止。不幸的是,没有任何错误结果告诉我正在发生什么。因此,我需要从不同的角度来解决这个问题。 - NA Slacker
显示剩余6条评论

2

添加到B:

insert into B (Operation_Key, Part_Key, Record_Key)
values
select Operation_Key, Part_Key, null as Record_Key from A
left join b on a.Operation_Key = b.Operation_Key and
a.Part_Key = b.Part_Key
where b.Part_Key is null

从B中删除:

Delete from B
select * from B left join A on b.Operation_Key = a.Operation_Key and
    b.Part_Key = a.Part_Key
where a.Operation_Key is null

1
我认为他想要生成一个“软插入”或“软删除”的表格。你的查询应该可以解决这个问题,他只需要将它们联合在一起并添加“添加”或“删除”列即可。 - N West

2
您可以通过巧妙地使用SQL中的“COALESCE”运算符来获得您想要的结果表格(参考您的示例设置)。如果您使用以下查询语句:
SELECT
    COALESCE(A.Operation_Key, B.Operation_Key) as Operation_Key,
    COALESCE(A.part_key, B.part_key) as Part_Key,
    B.Record_Key,
    CASE WHEN A.Operation_Key IS NULL THEN
        'Delete'
    ELSE
        'Add'
    END AS [Action] FROM A
FULL OUTER JOIN B 
    ON A.Operation_Key = B.Operation_Key 
        AND A.Part_Key= B.Part_Key
WHERE A.Operation_Key IS NULL 
    OR B.Operation_Key IS NULL

当您按照示例操作后,将会得到与您示例完全相同的结果表格。


可能是数据中还有其他问题,我还没有能够识别出来,因为一旦我对一个数据表进行预过滤,我就能够使用我的原始查询和 coalesce 函数得到想要的结果。 - NA Slacker
@NA Slacker:您所说的预过滤数据表是什么意思?能否详细说明一下? - Chandu
@NA Slacker:数据中的PART_KEY和OPERATION_KEY字段是否已经有空值? - Chandu
它不应该这样,但我认为可能是这种情况。我将花些时间深入研究一下。感谢所有的帮助。我知道我离成功很近了。 - NA Slacker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接