比较SQL中的多个列并确定哪些列是错误的

比较SQL中的多个列并确定哪些列是错误的,sql,oracle,Sql,Oracle,我有两个可以连接的表A和表B。两个表都包含许多列,但两个表中都有6列,它们应该包含相同的值。这些列不是外键或主键。它们只是普通列,可以包含NULL值 假设这些列的名称如下:A_1。。。A_6,B_1。。。B_7 我的任务是比较所有这6列,在答案中写下它们,同时也写下哪些列不匹配 这意味着在查询结果中必须有来自A的6列,来自B的6列,然后是另一列,例如:ERROR is in A_5 我可以这样做: SELECT A_1, A_2, A_3, A_4, A_5, A_6, B_

我有两个可以连接的表A和表B。两个表都包含许多列,但两个表中都有6列,它们应该包含相同的值。这些列不是外键或主键。它们只是普通列,可以包含NULL值

假设这些列的名称如下:A_1。。。A_6,B_1。。。B_7

我的任务是比较所有这6列,在答案中写下它们,同时也写下哪些列不匹配

这意味着在查询结果中必须有来自A的6列,来自B的6列,然后是另一列,例如:ERROR is in A_5

我可以这样做:

SELECT 
    A_1, A_2, A_3, A_4, A_5, A_6, 
    B_1, B_2, B_3, B_4, B_5, B_6,
    CASE
        WHEN A_1 != B_1 THEN 'ERROR is in A_1'
        WHEN A_2 != B_2 THEN 'ERROR is in A_2'
        WHEN A_3 != B_3 THEN 'ERROR is in A_3'
        WHEN A_4 != B_4 THEN 'ERROR is in A_4'
        WHEN A_5 != B_5 THEN 'ERROR is in A_5'
        WHEN A_6 != B_6 THEN 'ERROR is in A_6'
    END
    as ERROR

FROM A
LEFT JOIN B
   ON A.B_CODE = B.CODE
WHERE
   A_1 != B_1 OR A_2 != B_2 OR A_3 != B_3 OR
   A_4 != B_4 OR A_5 != B_5 ORA_6 != B_6;
但是当语句出现时,必须有51个,因为A_1和A_2可能都是错误的,所以我还需要检查所有的对和所有的三,等等

问题是:有没有办法更有效、更干净地做到这一点


整个问题都在错误列中,因为它必须在结果中。您能这样做吗

SELECT
    A_1, A_2, A_3, A_4, A_5, A_6, 
    B_1, B_2, B_3, B_4, B_5, B_6,
    LEFT(ERROR, LEN(ERROR) - 1) AS ERROR
FROM (
SELECT
    A_1, A_2, A_3, A_4, A_5, A_6, 
    B_1, B_2, B_3, B_4, B_5, B_6,
    'Error is in positions ' 
        + CASE WHEN ERROR_1 = 1 THEN '1,' ELSE '' END
        + CASE WHEN ERROR_2 = 1 THEN '2,' ELSE '' END
        + CASE WHEN ERROR_3 = 1 THEN '3,' ELSE '' END
        + CASE WHEN ERROR_4 = 1 THEN '4,' ELSE '' END
        + CASE WHEN ERROR_5 = 1 THEN '5,' ELSE '' END
        + CASE WHEN ERROR_6 = 1 THEN '6,' ELSE '' END AS ERROR
FROM (
SELECT 
    A_1, A_2, A_3, A_4, A_5, A_6, 
    B_1, B_2, B_3, B_4, B_5, B_6,
    CASE WHEN ISNULL(A_1, '') != ISNULL(B_1, '') THEN 1 END AS ERROR_1,
    CASE WHEN ISNULL(A_2, '') != ISNULL(B_2, '') THEN 1 END AS ERROR_2,
    CASE WHEN ISNULL(A_3, '') != ISNULL(B_3, '') THEN 1 END AS ERROR_3,
    CASE WHEN ISNULL(A_4, '') != ISNULL(B_4, '') THEN 1 END AS ERROR_4,
    CASE WHEN ISNULL(A_5, '') != ISNULL(B_5, '') THEN 1 END AS ERROR_5,
    CASE WHEN ISNULL(A_6, '') != ISNULL(B_6, '') THEN 1 END AS ERROR_6
FROM
    A
    LEFT JOIN B ON A.B_CODE = B.CODE
WHERE
   A_1 != B_1 OR A_2 != B_2 OR A_3 != B_3 
   OR A_4 != B_4 OR A_5 != B_5 OR A_6 != B_6) I) O;

首先,使用通用表表达式可能会比使用通用表表达式看起来好得多,但我的Oracle SQL有点生疏,所以我保持简单。

这里我看到的问题是a表和B表没有规范化。这使得以给定的形式比较它们变得很困难-因此,让我们使用公共表表达式来规范化它们注意,这里我也有A和B作为CTE-我太懒了,无法创建实际的表,如果需要,只需删除A和B CTE即可:

WITH A AS (SELECT 99 AS CODE, 1 AS A_1, 2 AS A_2,  3 AS A_3, 4 AS A_4, 5 AS A_5, 6 AS A_6 FROM DUAL),
     B AS (SELECT 99 AS CODE, 1 AS B_1, 2 AS B_2, 13 AS B_3, 4 AS B_4, 5 AS B_5, 6 AS B_6 FROM DUAL),
     A1 AS (SELECT CODE, 1 AS COLNUM_A, A_1 AS VAL_A FROM A),
     A2 AS (SELECT CODE, 2 AS COLNUM_A, A_2 AS VAL_A FROM A),
     A3 AS (SELECT CODE, 3 AS COLNUM_A, A_3 AS VAL_A FROM A),
     A4 AS (SELECT CODE, 4 AS COLNUM_A, A_4 AS VAL_A FROM A),
     A5 AS (SELECT CODE, 5 AS COLNUM_A, A_5 AS VAL_A FROM A),
     A6 AS (SELECT CODE, 6 AS COLNUM_A, A_6 AS VAL_A FROM A),
     B1 AS (SELECT CODE, 1 AS COLNUM_B, B_1 AS VAL_B FROM B),
     B2 AS (SELECT CODE, 2 AS COLNUM_B, B_2 AS VAL_B FROM B),
     B3 AS (SELECT CODE, 3 AS COLNUM_B, B_3 AS VAL_B FROM B),
     B4 AS (SELECT CODE, 4 AS COLNUM_B, B_4 AS VAL_B FROM B),
     B5 AS (SELECT CODE, 5 AS COLNUM_B, B_5 AS VAL_B FROM B),
     B6 AS (SELECT CODE, 6 AS COLNUM_B, B_6 AS VAL_B FROM B)
SELECT 'Error comparing A' || COLNUM_A || ' (value=' || VAL_A || ') to B' || COLNUM_B || ' (value=' || VAL_B || ')' AS ERR_TEXT
  FROM (SELECT * FROM A1 INNER JOIN B1 USING (CODE)
        UNION ALL
        SELECT * FROM A2 INNER JOIN B2 USING (CODE)
        UNION ALL
        SELECT * FROM A3 INNER JOIN B3 USING (CODE)
        UNION ALL
        SELECT * FROM A4 INNER JOIN B4 USING (CODE)
        UNION ALL
        SELECT * FROM A5 INNER JOIN B5 USING (CODE)
        UNION ALL
        SELECT * FROM A6 INNER JOIN B6 USING (CODE))
  WHERE VAL_A <> VAL_B;  
这将使问题从关系数据库中的棘手问题(即比较几行中的一组不同字段)转变为连接表和比较多行中的几列的合理整洁问题


共享和享受。

最好有一个初始脚本来创建表并填充表。这在很大程度上取决于A_1、A_2等列的数据类型。如果它们是小数字,例如1到10,那么解决方案可能比它们都是自由文本要简单得多。遗憾的是,它们都是自由文本。至于最初的剧本,我没有。这些表实际上非常复杂,我已经尽可能地简化了。我不认为你可以在显示原因的同时让它更干净,因为你不能将NULL与不等式进行比较,所以表达式a_1!=B_1将忽略空值我想我喜欢你的方法,但你的甲骨文生锈了!NVL而不是ISNULL,长度不是LEN,您需要SUBSTR而不是LEFT。另外,回想一下Oracle中的空字符串与NULL相同,所以说NVLA_1相当于如果a_1为NULL,则为NULL,这相当于普通的旧A1。共享和享受。是的,但是空值确实需要处理-参见Ben对这个问题的评论。不空!=null的计算结果为false,因此不会返回错误,例如:A_3='abc'和B_3=null我也喜欢它。非常感谢大家。在Oracle中,您还必须将+CASE改为| | CASE。其中decodeVAL_A,VAL_B,1,0=0将处理空值。