【问题标题】:MySQL - select rows where value = X, or if no matches, where value = nullMySQL - 选择 value = X 的行,或者如果没有匹配,则 value = null
【发布时间】:2018-12-19 13:42:11
【问题描述】:

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

从下表中,我想选择val_a = Xval_b = T 的位置并返回ID:1 所在的行。

如果我选择 val_a = Xval_b = V 的位置并返回 ID:3ID:4 的行。由于行 12 不匹配,我将使用特异性较低但仍匹配 val_a 的行。

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

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

【问题讨论】:

    标签: mysql


    【解决方案1】:

    试试这个查询:

    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));
    

    Demo

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

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

    EXISTS 子句涵盖第二种情况,它断言没有匹配的非 NULL val_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));
    

    Demo

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

    【讨论】:

    • 谢谢!我假设这会进行两次完整的表扫描。如果你可以让 MySQL 只做一个就好了,如果你在那个查询中没有得到任何命中,它会做第二个。 (并不是说我的数据库不会处理两次扫描,非常感谢您的回复!)
    • @AndreasLundgren 我希望 MySQL 优化器足够聪明,可以缓存 EXISTS 子查询,并且只计算一次。然后,MySQL 只需要对表进行一次传递。请记住,EXISTS 子句与外部查询无关。
    • 我也希望它缓存 EXISTS 子查询,否则我们会有一个 ordo n^2 查询,但事实并非如此。但是您仍然有两次扫描,一次用于子查询,一次用于外部查询。例如,如果它首先扫描以查找所有具有 val_b='V' 的内容,并且如果没有命中,则再次扫描空值,这会使其在统计上更快。不确定是否可以使用 IF 语句,我没有设法得到与之“编译”的东西。 :-)
    • @AndreasLundgren 我给了你一个使用 MySQL 8 的选项。我不确定我们是否可以在不使用多个表扫描的情况下编写此查询。
    猜你喜欢
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    • 2016-10-14
    • 1970-01-01
    • 2019-08-24
    • 2022-01-06
    • 2017-05-09
    • 2017-07-23
    相关资源
    最近更新 更多