【问题标题】:MySQL: JOIN query that gets all items with a nullable fieldMySQL:获取所有具有可为空字段的项目的 JOIN 查询
【发布时间】:2018-01-06 04:26:32
【问题描述】:

我有一个item 表,它有一个对tax 表的外键引用。该列是tax_id

我曾经在我的架构中将tax_id 作为NOT NULL,但是我只是更改了它,因为我希望它是可选的,所以现在它在架构中是NULL DEFAULT NULL

这破坏了我的查询。现在,当我查询项目并加入税收时,我只会得到 tax_id 字段匹配的项目。

这是我的查询:

SELECT item.*
FROM item
JOIN user_item
    ON user_item.item_id = item.id
JOIN tax
    ON tax.id = item.tax_id
WHERE user_item.user_id = ?
    AND item.deleted_at IS NULL
    AND user_item.deleted_at IS NULL
    AND tax.deleted_at IS NULL

此查询有效,但是如果我得到以下项目:

+----+--------+--------------------+-------------+-------+---------------------+------------+------------+
| id | tax_id | name               | description | price | created_at          | updated_at | deleted_at |
+----+--------+--------------------+-------------+-------+---------------------+------------+------------+
|  1 |      2 | foo                |             |  1.13 | 2017-07-30 15:20:14 | NULL       | NULL       |
|  2 |   NULL | bar                |             |  0.67 | 2017-07-30 15:20:25 | NULL       | NULL       |
|  3 |   NULL | baz                |             |  1.15 | 2017-07-30 15:22:33 | NULL       | NULL       |
+----+--------+--------------------+-------------+-------+---------------------+------------+------------+

然后查询只返回 id 为 1 的项目。我也想要 id 2 和 3。

如何修改我的查询来实现这一点?

我了解查询的问题是这部分:ON tax.id = item.tax_id

【问题讨论】:

    标签: mysql sql select join null


    【解决方案1】:

    这正是left joins 的用途:

    SELECT item.*
    FROM item
    JOIN user_item
        ON user_item.item_id = item.id
    LEFT JOIN tax -- Here!
        ON tax.id = item.tax_id
    WHERE user_item.user_id = ?
        AND item.deleted_at IS NULL
        AND user_item.deleted_at IS NULL
        AND tax.deleted_at IS NULL
    

    【讨论】:

    • 我明白了。我以前没有使用过左连接。我尝试修改它,但收到此错误:sql: Scan error on column index 1: converting driver.Value type <nil> ("<nil>") to a int: invalid syntax。我认为那是因为我想将NULLINT 进行比较?
    • 是的 - 这可能来自代码调用此查询并尝试将结果中的一列转换为int(当实际返回值时) null
    • @Lansana 我不会将null 转换为00 是一个实际值,而null 有“没有值”的意思。如果一个项目没有任何税收,null 是要走的路(恕我直言)。
    • @Lansana 请注意,如果引用的表中没有这样的值,则不能将 0 用作外键。
    • 好点!谢谢。必须在业务逻辑需要的地方使用NullInt64 并转换为int
    【解决方案2】:

    我认为最好的方法是将deleted_at 条件放在on 子句中。如果您希望 NULL 值在表之间匹配,则将其写为:

    SELECT i.*
    FROM item i JOIN
         user_item ui
         ON ui.item_id = i.id LEFT JOIN
         tax t
         ON NOT (t.id <=> i.tax_id) AND  -- ids are the same or both `NULL`.
            t.deleted_at IS NULL
    WHERE ui.user_id = ? AND
          i.deleted_at IS NULL AND
          ui.deleted_at IS NULL ;
    

    【讨论】:

    • 当我运行这个查询时,我得到了 5 个结果。每个具有 NULL tax_id 字段的 2 个,以及具有当前 tax_id 字段的一个。但我喜欢移动 deleted_at 查询的想法,我仍在研究更好的 SQL 语法。
    • 对 deleted_at 的推荐表示赞同。我将所有 deleted_at 放在我的 WHERE 子句中,但将其放在相应的连接上更有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    • 1970-01-01
    • 2021-01-13
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    • 2020-02-08
    相关资源
    最近更新 更多