TERADATA逗号分隔列比较

时间:2016-11-03 07:22:19

标签: sql teradata

我在Teradata 15.10.03.01中面临以下问题。这是关于逗号分隔列比较。考虑下面提到的数据和预期结果。

CREATE MULTISET TABLE TESTDB.TESTTABLE1 ,NO FALLBACK ,
         NO BEFORE JOURNAL,
         NO AFTER JOURNAL,
         CHECKSUM = DEFAULT,
         DEFAULT MERGEBLOCKRATIO
         (
          A VARCHAR(250) CHARACTER SET LATIN NOT CASESPECIFIC,
          B VARCHAR(250) CHARACTER SET LATIN NOT CASESPECIFIC,
          C VARCHAR(250) CHARACTER SET LATIN NOT CASESPECIFIC)
    PRIMARY INDEX ( A );

    CREATE MULTISET TABLE TESTDB.TESTTABLE2 ,NO FALLBACK ,
         NO BEFORE JOURNAL,
         NO AFTER JOURNAL,
         CHECKSUM = DEFAULT,
         DEFAULT MERGEBLOCKRATIO
         (
          A VARCHAR(250) CHARACTER SET LATIN NOT CASESPECIFIC,
          B VARCHAR(250) CHARACTER SET LATIN NOT CASESPECIFIC,
          C VARCHAR(250) CHARACTER SET LATIN NOT CASESPECIFIC)
    PRIMARY INDEX ( A );



    INSERT INTO TESTDB.TESTTABLE1 VALUES('A1','B1','C1');
    INSERT INTO TESTDB.TESTTABLE1 VALUES('A2','B2','C2');
    INSERT INTO TESTDB.TESTTABLE1 VALUES('A3',NULL,'C3');
    INSERT INTO TESTDB.TESTTABLE1 VALUES('A4',NULL,'C4');
    INSERT INTO TESTDB.TESTTABLE1 VALUES(NULL,'B5','C5');
    INSERT INTO TESTDB.TESTTABLE1 VALUES(NULL,'B6','C6');
    INSERT INTO TESTDB.TESTTABLE1 VALUES(NULL,NULL,'C7');
    INSERT INTO TESTDB.TESTTABLE1 VALUES(NULL,NULL,'C8');

    INSERT INTO TESTDB.TESTTABLE2 VALUES('A1','B1','C1');
    INSERT INTO TESTDB.TESTTABLE2 VALUES('A3',NULL,'C3');
    INSERT INTO TESTDB.TESTTABLE2 VALUES(NULL,'B5','C5');
    INSERT INTO TESTDB.TESTTABLE2 VALUES(NULL,NULL,'C7');

    SELECT * FROM TESTDB.TESTTABLE1;

    A    B     C
   -------------
    A1   B1    C1
    A2   B2    C2
    A3         C3
    A4         C4
         B5    C5
         B6    C6
               C7
               C8

    SELECT * FROM  TESTDB.TESTTABLE2;          
    A    B     C
    ------------     
    A1   B1    C1
    A3         C3
         B5    C5
               C7

预期结果:

    A    B     C
   -------------
    A2   B2    C2
    A4         C3
         B6    C6

我尝试使用以下查询,但它没有返回任何记录。

    SELECT T1.A,T1.B,T1.C
    FROM TESTDB.TESTTABLE1 T1
    WHERE (T1.A,T1.B)
    NOT IN
    (
    SELECT T2.A,T2.B
    FROM TESTDB.TESTTABLE2 T2
    )
    ;

如何构建查询?

为什么我的查询没有返回任何记录?

2 个答案:

答案 0 :(得分:3)

手册中有一些信息:Behavior of Nulls for NOT IN,但根据标准SQL,此行为不正确。

您的查询不应返回任何行,因为与NULL的任何比较都会导致UNKNOWN,因此子查询返回的单个NULL将导致空结果。

因此,只需按照每个DBMS的基本推荐,永远不要将NOT IN用于NULLable列

通常的重写基于NOT EXISTS

SELECT T1.A,T1.B,T1.C
FROM TESTDB.TESTTABLE1 T1
WHERE NOT EXISTS
(
SELECT *
FROM TESTDB.TESTTABLE2 T2
WHERE T1.A = T2.A
  AND T1.B = T2.B
)
;

但在你的情况下,这也不会返回你的预期结果,因为NULL不等于NULL。

您需要一个设置操作,EXCEPT(或MINUS),它将NULL视为等于:

SELECT * FROM TESTDB.TESTTABLE1
EXCEPT
SELECT * FROM TESTDB.TESTTABLE2

编辑:

EXCEPT可能无法提供正确的结果,因为它会比较所有三列而不是两列,它会对您的示例数据起作用,但可能会因您的实际数据而失败。

来自@DavidCram的solution使用COALESCE(当然你需要选择一个保证不存在的值),另一个基于外部联接,但是你需要一个在第二个表中定义为NOT NULL的列:

SELECT T1.*
FROM TESTDB.TESTTABLE1 T1
LEFT JOIN TESTDB.TESTTABLE2 T2
  ON (T1.A = T2.A OR (T1.A IS NULL AND T2.A IS NULL))
 AND (T1.B = T2.B OR (T1.B IS NULL AND T2.B IS NULL))
WHERE T2.C IS NULL
;

这可以避免COALESCE,并且仍然可以加入主索引。

答案 1 :(得分:1)

比较它们时需要合并空值

SELECT T1.A,T1.B,T1.C
FROM TESTTABLE1 T1
WHERE (COALESCE(T1.A,''),COALESCE(T1.B,''))
NOT IN
(
SELECT COALESCE(T2.A,''),COALESCE(T2.B,'')
FROM TESTTABLE2 T2
)
;