从表中选择,其中列仅包含来自另一列的元素

时间:2015-12-26 16:19:56

标签: mysql database select optimization database-design

在一个绝对错误的代码中,我尝试做类似的事情:

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时检查项目是否在另一个表格中。我试着玩那个

2 个答案:

答案 0 :(得分:2)

是的,有可能。一个简单的方法是使用子查询。这将是这样的:

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中只包含ONLY元素的所有组,您可以:

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_id,其值超出该集合,然后取消该值。有点复杂,有可能更好的方法来做到这一点......

答案 1 :(得分: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, ',', ''));