【问题标题】:MySQL - selecting rows with some values being nullMySQL - 选择一些值为空的行
【发布时间】:2015-02-25 11:14:41
【问题描述】:

我有 'foo'、'bar' 和 'buz' 的值。我想从下表中选择第 1 行和第 3 行:

+----+------+------+------+
| Id | Col1 | Col2 | Col3 |
+----+------+------+------+
|  1 | foo  |      |      |
|  2 | foo  | bar  | buz  |
|  3 |      | bar  | buz  |
+----+------+------+------+

考虑到以下几点,最佳的 MySQL 查询是什么:

  • 空格为空
  • 我有 n 列,其中 4
  • 会有几百行
  • 我将在一行中选择特定的列组合,其中只能设置提供的值,其余的必须为空。例如:我需要这样的查询

SELECT * FROM my_table WHERE Col1 = foo OR (Col2 = bar AND Col3 = buz);

这将只返回第 1 行和第 3 行。

换句话说,我希望有一个查询只返回具有某些值组合的行,而不是 coln = 'some_val' 并且我们不关心其他行的行。

这样做的原因是我想在 1 个查询中有 5 个组合,并且我想避免在任何地方写 (...) coln <> NULL(...)

非常感谢您的建议。

【问题讨论】:

  • 您希望有一个查询返回一条记录,该记录在 col1、col2、col3 三列之一中至少有一个条目?
  • 你能再解释一下你的最后一个要点吗?
  • @blckbird,克里斯:我已经编辑了我的问题
  • 你能再举几个例子吗?特别是,如果有的话,您希望返回以下行中的哪一行:(4, foo, bar, NULL)(5, xyzzy, NULL, NULL)(6, bar, NULL, NULL)(7, NULL, NULL, NULL)?
  • @Ilmari Karonen 我希望数据库假设,对于查询中未提供的每个字段,它需要为 NULL 才能返回整行。即使提供的值匹配。

标签: mysql


【解决方案1】:

您将使用where 子句。要找到三个值:

where 'foo' in (col1, col2, col3, . . . ) or
      'bar' in (col1, col2, col3, . . . ) or
      'buz' in (col1, col2, col3, . . . )

将结果限制为这三个值更加困难。您需要对每一列进行比较:

where ( (col1 in ('foo', 'bar', 'buz') or col1 is null) or
        (col2 in ('foo', 'bar', 'buz') or col2 is null) or
        . . . 
      )

如果您不想全部输入,可以使用电子表格生成代码。

另一种选择是以下组合:

where replace(replace(replace(concat_ws('', col1, col2, col3, . . . ),
                              'foo', ''
                             ), 'bar', ''
                      ), 'buz', ''
             ) = ''

这会将值连接在一起,然后删除您关心的值。如果所有内容都被删除,则该行匹配。

注意:这个问题表明您的数据结构很差。您将内容存储在应该在行中的列中。

【讨论】:

  • 谢谢 Gordon,我正在查看您的回答。只是对最后一句话的评论。我可以将这些详细信息存储在单独的表中,但是我的脚本中会有 x5 db 查询。此外,将有“无限”的行数和有限的列数。
  • @艾伦。 . .您可以将值存储在一个表中,每列一行。也就是说,您将使用规范化的数据格式。
  • 。 .我不确定序列化是否是这里的最佳选择。如果我序列化这些数据,我每次都必须做SELECT *。使用这种结构和WHERE 子句,我将从几百行查询中选择最多 5 个结果。除非这样做更有效率....谢谢你的建议,我得研究一下。
【解决方案2】:

我希望数据库假设,对于查询中未提供的每个字段,它需要为 NULL 才能返回整行。即使提供的值匹配。

在这种情况下,简单的解决方案是:

SELECT * FROM my_table WHERE
  (Col1 = 'foo' AND Col2 IS NULL AND Col3 IS NULL) OR
  (Col1 IS NULL AND Col2 = 'bar' AND Col3 = 'buz') OR
  /* ... */

在许多情况下,这可能是一个非常好的解决方案。但是,由于MySQL's poor index use for OR queries.,它有时会遭受次优性能,特别是,如果您在所有列上都有一个组合索引,并且想要充分利用它,最好将查询重写为使用UNION(或UNION ALL) 而不是OR

SELECT * FROM my_table WHERE
  (Col1 = 'foo' AND Col2 IS NULL AND Col3 IS NULL) UNION ALL
SELECT * FROM my_table WHERE
  (Col1 IS NULL AND Col2 = 'bar' AND Col3 = 'buz') UNION ALL
  /* ... */

请参阅this SQLFiddle 以了解这两种技术的演示,并比较执行计划(执行对于这么小的表毫无意义;您需要更多的行才能看到任何系统差异)。查看 KEY_LEN 和 REF 列,您可以看到,对于 OR 查询,MySQL 最终只使用 Col1 的索引,而对于 UNION ALL,它可以使用整个索引。

【讨论】:

    猜你喜欢
    • 2011-04-01
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    • 2012-01-24
    • 2015-01-12
    • 2017-03-16
    相关资源
    最近更新 更多