首页 > 解决方案 > MySQL - 选择 value = X 的行,或者如果没有匹配,则 value = null

问题描述

如何在val_b具有特定值的表中找到所有行,但如果不存在这样的行,我想看看是否存在匹配度较低的行,因此 val_b 在哪里null

从下表中,我想选择位置val_a = Xval_b = T获取ID:1后面的行。

如果我选择where val_a = Xand val_b = Vget row with ID:3and ID:4back。由于 row 1and 2didn't match,我将解决那些特异性较低但仍然 match 的行val_a

| ID | val_a | val_b |
| -- | ----- | ----- |
| 1  | X     | T     |
| 2  | X     | U     |
| 3  | X     | null  |
| 4  | X     | null  |
| 5  | Y     | null  |

这可以直接在数据库查询中执行吗?类似于语法左关联XOR运算符...

标签: mysql

解决方案


试试这个查询:

SELECT ID, val_a, val_b
FROM yourTable
WHERE
    val_a = 'X' AND (val_b = 'V' OR
                     (NOT EXISTS (SELECT 1 FROM yourTable
                              WHERE val_a = 'X' AND val_b = 'V') AND val_b IS NULL));

在此处输入图像描述

演示

这里的逻辑是,如果以下条件之一为真,我们将保留一条记录:

  • val_b匹配预期的(非 NULL)值,或
  • val_b为 NULL并且没有匹配的非 NULLval_b记录

EXISTS子句涵盖了第二种情况,它断言没有匹配的非 NULLval_b记录。

搜索时,val_a = 'X'使用上述查询val_b = 'T'仅返回记录。ID:1

如果您使用的是 MySQL 8+,那么我们可以在这里使用分析函数:

WITH cte AS (
    SELECT ID, val_a, val_b,
        COUNT(CASE WHEN val_a = 'X' AND val_b = 'V' THEN 1 END)
            OVER () cnt
    FROM yourTable
)

SELECT ID, val_a, val_b
FROM cte
WHERE val_a = 'X' AND (val_b = 'V' OR (val_b IS NULL AND cnt = 0));

演示

但请注意,即使在这种情况下,我们仍然需要使用子查询。


推荐阅读