SQL 在 Where 子句中处理可为空的外键

Posted

技术标签:

【中文标题】SQL 在 Where 子句中处理可为空的外键【英文标题】:SQL Handling Nullible Foreign Keys in Where Clause 【发布时间】:2011-02-14 22:30:40 【问题描述】:

假设我有一个名为 my_table 的表,其中包含 primary_key table_pk 和三个分别名为 X_fk、Y_fk 和 Z_fk 的可空字段(外键),以及另一个名为 data 的字段。表 X、Y 和 Z 都有一个主键字段和一个名称字段(例如 X_pk, X_name, Y_pk, Y_name, Z_pk, Z_name)。

在给定表 X、Y 和 Z 中的名称的情况下,我想要一个从 my_table 中唯一返回一行的查询。

SELECT table_pk 
FROM my_table 
WHERE 
    X_fk = (SELECT X_pk FROM X WHERE X_name = ?) 
  AND 
    Y_fk = (SELECT Y_pk FROM Y WHERE Y_name = ?) 
  AND 
    Z_fk = (SELECT Z_pk FROM Z WHERE Z_name = ?)

当我想找到行 (X_Name, Y_Name, Z_Name) = ('XXX', 'YYY', NULL) 时,这不起作用,因为 Z_fk = NULL 永远不会导致 TRUE。如何修改上述查询以从表中提取一个唯一条目,以说明某些外键为 NULL 的唯一条目?

【问题讨论】:

【参考方案1】:

试试这个:

SELECT min(table_pk)
FROM my_table 
WHERE 
    ((X_fk = (SELECT X_pk FROM X WHERE X_name = ?)) OR (? IS NULL AND X_fk IS NULL))
AND 
    ((Y_fk = (SELECT Y_pk FROM Y WHERE Y_name = ?)) OR (? IS NULL AND Y_fk IS NULL)) 
AND 
    ((Z_fk = (SELECT Z_pk FROM Z WHERE Z_name = ?)) OR (? IS NULL AND Z_fk IS NULL))

【讨论】:

删除我的并给 +1。这似乎是我尝试做的更完整的版本。 您不需要 MIN,因为 FROM 子句中只有一个表 @cyberkiwi:我认为作者只需要一行。如果此字段组合是唯一的,则不需要 min。 非常正确,(X_fk, Y_fk, Z_fk) 元组形成了一个唯一的键......我明天试试,在我看来它应该可以工作!【参考方案2】:

与 LukLed 的答案相同,但输入仅从前端绑定一次

SELECT table_pk 
FROM my_table
cross join (select ? iX, ? iY, ? iZ) i
WHERE 
    ((i.iX is null and X_fk is null) OR X_fk = (SELECT X_pk FROM X WHERE X_name = i.iX))
  AND 
    ((i.iY is null and Y_fk is null) or Y_fk = (SELECT Y_pk FROM Y WHERE Y_name = i.iY))
  AND 
    ((i.iZ is null and Z_fk is null) or Z_fk = (SELECT Z_pk FROM Z WHERE Z_name = i.iZ))

这看起来更短,但对索引没有任何好处(假设 -1 不是有效值)。

SELECT table_pk 
FROM my_table
WHERE 
    Isnull(X_fk,-1) = isnull((SELECT X_pk FROM X WHERE X_name = ?),-1)
  AND 
    Isnull(Y_fk,-1) = Isnull((SELECT Y_pk FROM Y WHERE Y_name = ?),-1)
  AND 
    Isnull(Z_fk,-1) = Isnull((SELECT Z_pk FROM Z WHERE Z_name = ?),-1)

【讨论】:

+1:虽然看起来更糟,但你有使用过一次的参数。 hm...什么是交叉连接? :) @vicatcu,与将单词 cross join 替换为单个 comma 相同。它在两个表之间产生笛卡尔积。由于 i 被定义为单行 3 列的表,因此它仅用于对输入进行列化。

以上是关于SQL 在 Where 子句中处理可为空的外键的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Linq 的 where 条件下从可为空的日期时间中删除时间部分

EF6 - 使用可为空属性(外键,TPH)时的无效 SQL 查询

两个外键引用一个表和可以为空的外键

如何使用 Java 互操作处理可为空的泛型

Math.Max 处理三个可为空的值

在 np.where 条件下使用 pandas 可为空的整数 dtype