【问题标题】:SELECT from a table where a a column contains only elements from another column从表中选择一列仅包含另一列中的元素
【发布时间】:2016-04-01 02:18:46
【问题描述】:

在一个绝对错误的代码中,我正在尝试执行以下操作:

SELECT * FROM table2 WHERE
table2.items CONTAINS ONLY ELEMENTS FROM table1.item

这有点令人困惑,但我会尝试解释一下:

我有一个表(table1),它有一列,每行有一个元素(我们称它们为 A、B、C、D)

id - [item]

1 - ["A"]
2 - ["B"]
3 - ["C"]
4 - ["D"]

然后我有另一个表(table2),它的列包含如下字符串:

TABLE2
row# - [items]

row1 - ["A, B"]
row2 - ["A, B, C"]
row3 - ["A, B, C, E"]

我想要的是只从 table2 中选择只包含 table1 中存在的元素的行,在这个例子中是 row1 和 row2。

是否可以在不改变表格结构的情况下做到这一点?否则,我需要进行哪些更改?

---------[编辑]-------------

所以我改变了我的结构,以便能够使用 IN 运算符并且它(几乎)工作得很好! 然而,一个新的问题来了。 由于我的 table2 字符串长度不同,我的新 table2 有一些空单元格。

---[更新]---

所以如果我要检查是否

|item1|item2|item3|item4| row |
|  A  |  B  |  C  |     |  2  |

row2在table1.item中(同上),我要求的条件之一是

WHERE NULL IN table1.item

事实并非如此!我需要的是仅在项目不为 NULL 时检查项目是否在另一个表中。我会尝试使用它

【问题讨论】:

  • 那么新的 table2 结构是什么?对于这个最小的示例,我想您只需要一个唯一标识符 (ID)、一个非唯一值(A、B 或 C 等)和一个 group_id 来关联相关的。

标签: mysql database select optimization database-design


【解决方案1】:

是的,这是可能的。一种简单的方法是使用子查询。应该是这样的:

SELECT * FROM table1 WHERE some_value IN (SELECT some_value from table2);

这将返回 table1 中的所有内容,其中 some_value 存在于 table2 的列 some_value

如果你的 table2 是这样的:

|ID | Value | Group_id|
| 1 |   A   |   1     |
| 2 |   B   |   1     |
| 3 |   C   |   1     |
| 4 |   A   |   2     |
| 5 |   B   |   2     |

这将表示第 1 组中的所有“A、B、C”和第 2 组中的“A、B”。现在,您可以很容易地检索与任何组相关联的所有值,在不同的行中。据我从你最初的问题可以看出,这个表不应该有任何 NULL 值(正如你在更新中提到的那样)

现在,要确定只有 table1 中存在的元素的所有组,您可以:

SELECT group_id FROM table2 WHERE group_id NOT IN (SELECT group_id FROM table2 WHERE value NOT IN (SELECT value from table1));

这会生成一组结果,其中包含 table1 中的所有值,然后返回所有 group_ids 的值超出该组的值,然后取反。有点复杂,可能有更好的方法来做到这一点......

【讨论】:

  • 难道不需要我的 table2 为每个“项目”提供单独的列,而不仅仅是一个包含所有项目的字符串吗?
  • 会的,是的。您需要研究的内容称为标准化。我们希望在任何给定的“单元格”中只有单个值。因此,对于您的示例,您可能希望有第三个表来保存每个值。例如:不是让 Table2.Row1 同时保存 'A' 和 'B' ,您可以为该行分配一个 Group_ID,创建名为 Groups 的第三个表,将两行插入 Group_IDs(每个值一行),并给出这些行与 Table2.Row1 现在将具有的相同 Group_ID 代替值。这是将多个值与一个“父”记录相关联的常用方法
  • 经过一些工作,它几乎可以工作了。介意看看 OP 的编辑部分吗?
  • 我用 IFNULL() 做了一些不那么漂亮的工作。似乎它现在按预期工作!感谢您的帮助、时间和耐心:D
【解决方案2】:

您的数据布局非常糟糕。在 SQL 中,将事物列表存储在行中是一个坏主意。以下是一些原因:

  • 在关系数据模型中,每一列都应该存储一个“事物”。
  • 关系数据库有一种存储列表的好方法。它被称为表格。
  • 数据库无法强制执行外键关系。

有时,您会被其他人的错误设计决策所困扰。 MySQL 有一些可以提供帮助的功能。例如,如果“列表”只是逗号分隔的字符串:

SELECT t2.items
FROM table2 t2 LEFT JOIN
     table1 t1
     ON find_in_set(t1.item, t2.items) > 0
GROUP BY t2.items  -- or this should really be an id column if available
HAVING COUNT(*) = LENGTH(t2.items) - LENGTH(REPLACE(t2.ITEMS, ',', ''));

您的列表格式有空格,因此您需要删除它们:

SELECT t2.items
FROM table2 t2 LEFT JOIN
     table1 t1
     ON find_in_set(t1.item, replace(t2.items, ' ', '')) > 0
GROUP BY t2.items  -- or this should really be an id column if available
HAVING COUNT(*) = LENGTH(t2.items) - LENGTH(REPLACE(t2.ITEMS, ',', ''));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-19
    • 1970-01-01
    • 1970-01-01
    • 2020-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    相关资源
    最近更新 更多