SQL“加入”空值

时间:2009-11-18 19:22:17

标签: sql oracle null

由于我无法控制的原因,我需要连接两个表,我需要空值来匹配。我能想到的最好的选择是吐出一个UUID并将其用作我的比较值,但它似乎很难看

SELECT * FROM T1 JOIN T2 ON nvl(T1.SOMECOL,'f44087d5935dccbda23f71f3e9beb491') = 
   nvl(T2.SOMECOL,'f44087d5935dccbda23f71f3e9beb491')

我怎样才能做得更好?如果重要的话,这是在Oracle上,并且上下文是一个应用程序,其中必须将一批用户上载的数据与一批现有数据进行比较,以查看是否有任何行匹配。回想起来,我们应该阻止任一数据集中的任何连接列包含空值,但我们没有,现在我们必须忍受它。

编辑:要清楚,我不仅仅关注空值。如果列不为null,我希望它们匹配实际值。

14 个答案:

答案 0 :(得分:39)

也许这会奏效,但我从来没有尝试过:

SELECT * 
FROM T1 JOIN T2 
ON T1.SOMECOL = T2.SOMECOL OR (T1.SOMECOL IS NULL AND T2.SOMECOL IS NULL)

答案 1 :(得分:6)

在SQL Server中我使用过:

WHERE (a.col = b.col OR COALESCE(a.col, b.col) IS NULL)

显然效率不高,因为OR,但除非有保留值,否则你可以将NULL映射到两边而不会产生歧义或折叠,这是你可以做的最好的(如果有的话,为什么在你的设计...)

答案 2 :(得分:3)

你不能做得更好,但是你所拥有的JOIN不会以任何方式进行实际的“加入”(T1.SOMECOL和T2.SOMECOL之间不会有任何关联,除了它们都有一个NULL该列的值)。基本上这意味着您将无法在NULL上使用JOIN来查看行是否匹配。

NULL永远不会等于另一个NULL。一些未知价值的东西如何等于其他未知价值呢?

答案 3 :(得分:3)

对于这类任务,Oracle内部使用未记录的函数sys_op_map_nonnull(),您的查询将成为:

SELECT *
FROM T1 JOIN T2 ON sys_op_map_nonnull(T1.SOMECOL) = sys_op_map_nonnull(T2.SOMECOL)

没有记录,所以如果你走这条路线要小心。

答案 4 :(得分:3)

简单,利用COALESCE,它将返回其第一个非空参数:

SELECT * FROM T1 JOIN T2 ON 
  COALESCE(T1.Field, 'magic string') = 
     COALESCE(T2.Field, 'magic string')

您唯一需要担心的是,“魔术字符串”不能成为任何一个表中连接字段的合法值。

答案 5 :(得分:1)

如果值为null,您真的希望能够加入表吗?你不能只在连接谓词中排除可能的空值吗?我发现很难知道两个表中的行可以通过空值相关联。如果table1.col_a中有100个空值,table2.col_b中有100个空值,那么只有具有null的行才会返回10000行。这听起来不对。

然而,你确实说过你需要它。我可以建议将空列合并为较小的字符串,因为字符比较相对较贵。更好的是,如果列中的数据将是文本,则将空值合并为一个整数。然后,您可以非常快速地进行“比较”,并且您不太可能与现有数据发生冲突。

答案 6 :(得分:0)

只是抛弃它 - 有没有办法可以将这些空值合并为一个已知值,如空字符串?不太了解你的桌子是如何布局的意味着我不能确定你是否会失去那种意义 - 即有一个空字符串代表“用户拒绝输入电话号码”而NULL是“我们忘记了询问它“或类似的东西?

可能性是不可能的,我敢肯定,但如果确实如此,你就会知道要比较的值,你可以通过这种方式获得合法的加入。

答案 7 :(得分:0)

是否与检查两列中是否存在空值不一样?

SELECT * FROM T1, T2 WHERE T1.SOMECOL IS NULL and T2.SOMECOL IS NULL

SELECT * FROM T1 CROSS JOIN T2 WHERE T1.SOMECOL IS NULL and T2.SOMECOL IS NULL

答案 8 :(得分:0)

为什么不这样:

SELECT * FROM T1 JOIN T2 ON nvl(T1.SOMECOL,'null')=    NVL(T2.SOMECOL, '空')

我不知道你为什么使用UUID。您可以使用列中不存在的任何字符串,例如字符串“null”,以减少内存占用。使用nvl的解决方案比使用Eric Petroelje提出的or ... is null的解决方案要快得多。

答案 9 :(得分:0)

您可以尝试使用以下查询。

SELECT *
FROM TABLEA TA
JOIN TABLEB TB ON NVL(TA.COL1,0)=NVL(TB.COL2,0);

答案 10 :(得分:0)

我相信你仍然可以使用nvl()进行加入:

SELECT *
FROM T1
JOIN T2 ON NVL(T2.COL1,-1)=NVL(T1.COL1,-1);

但是您需要在列col1

上添加基于函数的索引
CREATE INDEX IND_1 ON T1 (NVL(COL1,-1));
CREATE INDEX IND_2 ON T2 (NVL(COL1,-1));

索引应该显着提高NVL(..)上的连接速度。

答案 11 :(得分:0)

您可以使用decode连接空值:

    SELECT * FROM T1 JOIN T2 ON DECODE(T1.SOMECOL, T2.SOMECOL, 1, 0) = 1

decode将null视为相等,因此在没有“魔术”数字的情况下也可以使用。两列必须具有相同的数据类型。

它不会使代码更具可读性,但可能仍比t1.id = t2.id or (t1.id is null and t2.id is null)

答案 12 :(得分:0)

@Sarath Avanavu

这不是最好的方法。如果TA.COL1的值保持为0,而TB.COL2为NULL,则它将联接这些记录,这是不正确的。

SELECT *
FROM TABLEA TA
JOIN TABLEB TB ON NVL(TA.COL1,0)=NVL(TB.COL2,0);

答案 13 :(得分:-2)

您还可以使用CASE替换子查询中的空值,然后加入结果:

SELECT T1.COL1 FROM
(
   (SELECT (CASE WHEN COL1 IS NULL THEN 'X' ELSE COL1 END) AS COL1 FROM TABLE1) T1
   JOIN
   (SELECT (CASE WHEN COL1 IS NULL THEN 'X' ELSE COL1 END) AS COL1 FROM TABLE2) T2
)
ON T1.COL1=T2.COL1