如何在 MySQL 中存储具有属性的唯一列表
How to store unique list with properties in MySQL
我想像下面这样存储数据,唯一的是 user_id
和 lids
,在 MySQL:
recordid user_id lids length breadth
------------------------------------------------------------
1 1 l1,l2 10 5
2 1 l1 7 5
3 1 l1,l3,l2 10 10
4 1 l2,l3 25 15
我的查询模式是:
- 给我长度和宽度,其中盖子是 l2,l1
- 给我长度和宽度,其中盖子是 l2,l3
基本上,lids的输入可以按任意顺序来搜索,但它应该提供正确的长度、宽度。
因为,我们不应该在 RDBMS 中存储逗号分隔值。
问题 - 我应该如何构造数据库以具有独特的 user_id/lids
组合,无需太多字符串操作即可提供正确的长度和宽度?
我想出了一个像这样查询数据库的解决方案 -
select * from table1 where find_in_set('l2', lids) AND find_in_set('l1', lids);
然后在代码中,将盖子的数量确定为 2 个。但这不是完美的解决方案。需要相关指导。
AddOn - SpringBoot + JPA (Hibernate) 特定的解决方案会很棒,不需要编写本机 sql 查询
根据评论,如果我为 lids
-
创建一个 table
recordid(fk) lid
----------------------------------
1 l1
1 l2
2 l1
3 l1
3 l3
3 l2
4 l2
4 l3
那么我如何确保只有 1 个独特的盖子组合 应该可供用户使用?
我的 select 查询是什么?会不会像下面这样?
select * from table1, lids where main.recordid = lids.recordid and lid IN ('l2','l3');
IN
运算符将 运行 查询 OR
而不是 AND
,这也会给出错误的结果。
是否必须根据 lids
table 中的 recordid
进行分组,然后应用 where
条件?抱歉,我很困惑,因为我已经阅读了很多与它相关的文章并且分心了。
好的,问题基本上可以深入到这个 -
我想找到具有 EXACT 个盖子列表的 recordid 来搜索。
tl;dr:对于这样的设计问题,请考虑 entities。 人际关系,amd 人际关系。
您有两个实体,records
和 lids
。他们有many-to-many关系
让我们将您的第二个 table 称为 records_lids
,以表明它是记录和盖子之间的 many-to-many 关联 table。它有两列,record_id
和 lid
。当 table 中存在一行时,表示提到的 record_id
提到了 lid
。
table 的主键应该由它的两个列 (record_id, lid)
组成。因为主键是唯一的,所以这可以防止任何记录多次具有相同的盖子。
现在,找到带有盖子 l1
的 record_id 值集很容易。你甚至不需要你的第一个 table.
SELECT record_id FROM records_lids WHERE lid = `l1`
要查找具有多个盖子的记录,您需要获取记录集与每个盖子的逻辑交集。您可以这样做:(https://www.db-fiddle.com/f/cLf4b6LDwMH9eFRTTheZJr/0)
SELECT record_id
FROM (SELECT record_id FROM records_lids WHERE lid = 'l1') l1
NATURAL JOIN (SELECT record_id FROM records_lids WHERE lid = 'l2') l2
NATURAL JOIN (SELECT record_id FROM records_lids WHERE lid = 'l3') l3
NATURAL JOIN 操作处理交集操作;结果仅包含具有匹配 record_id
值的行。 (其他一些 SQL table 服务器有 INTERSECT 运算符,但 MySQL 没有,但是...)
你也可以这样做(https://www.db-fiddle.com/f/cLf4b6LDwMH9eFRTTheZJr/1)。
SELECT record_id
FROM records_lids
WHERE lid IN ('l1','l2','l3')
GROUP BY record_id
HAVING COUNT(*) = 3
HAVING 子句是您坚持想要所有三个盖子的记录的方式。
一旦你有了一组 record_id,你就可以将它加入你的另一组 table。 (https://www.db-fiddle.com/f/cLf4b6LDwMH9eFRTTheZJr/2)
SELECT records.*
FROM (SELECT record_id FROM records_lids WHERE lid = 'l1') l1
NATURAL JOIN (SELECT record_id FROM records_lids WHERE lid = 'l2') l2
NATURAL JOIN (SELECT record_id FROM records_lids WHERE lid = 'l3') l3
NATURAL JOIN records
或(https://www.db-fiddle.com/f/cLf4b6LDwMH9eFRTTheZJr/3)
SELECT *
FROM records
WHERE record_id IN (
SELECT record_id
FROM records_lids
WHERE lid IN ('l1','l2','l3')
GROUP BY record_id
HAVING COUNT(*) = 3
)
编辑:我没有完全理解你的问题。您想要排除没有*精确(匹配的盖子集的记录。试试这个(https://www.db-fiddle.com/f/cLf4b6LDwMH9eFRTTheZJr/4)。它取决于 MySQL 的一个怪癖,即像 lid IN ('l1', 'l2')
这样的布尔表达式具有假时值为 0,真时值为 1。
SELECT *
FROM records
WHERE record_id IN (
SELECT record_id
FROM records_lids
GROUP BY record_id
HAVING SUM(lid IN ('l1', 'l2')) = 2
AND COUNT(*) = 2
)
SQL 本质上是一种用于操作集合的语言。这里的设计手法是
- 找出你的实体
- 找出它们之间的关系
- 弄清楚如何获得所需的实体集
- 检索您需要匹配集合的行
我想像下面这样存储数据,唯一的是 user_id
和 lids
,在 MySQL:
recordid user_id lids length breadth
------------------------------------------------------------
1 1 l1,l2 10 5
2 1 l1 7 5
3 1 l1,l3,l2 10 10
4 1 l2,l3 25 15
我的查询模式是:
- 给我长度和宽度,其中盖子是 l2,l1
- 给我长度和宽度,其中盖子是 l2,l3
基本上,lids的输入可以按任意顺序来搜索,但它应该提供正确的长度、宽度。
因为,我们不应该在 RDBMS 中存储逗号分隔值。
问题 - 我应该如何构造数据库以具有独特的 user_id/lids
组合,无需太多字符串操作即可提供正确的长度和宽度?
我想出了一个像这样查询数据库的解决方案 -
select * from table1 where find_in_set('l2', lids) AND find_in_set('l1', lids);
然后在代码中,将盖子的数量确定为 2 个。但这不是完美的解决方案。需要相关指导。
AddOn - SpringBoot + JPA (Hibernate) 特定的解决方案会很棒,不需要编写本机 sql 查询
根据评论,如果我为 lids
-
recordid(fk) lid
----------------------------------
1 l1
1 l2
2 l1
3 l1
3 l3
3 l2
4 l2
4 l3
那么我如何确保只有 1 个独特的盖子组合 应该可供用户使用? 我的 select 查询是什么?会不会像下面这样?
select * from table1, lids where main.recordid = lids.recordid and lid IN ('l2','l3');
IN
运算符将 运行 查询 OR
而不是 AND
,这也会给出错误的结果。
是否必须根据 lids
table 中的 recordid
进行分组,然后应用 where
条件?抱歉,我很困惑,因为我已经阅读了很多与它相关的文章并且分心了。
好的,问题基本上可以深入到这个 -
我想找到具有 EXACT 个盖子列表的 recordid 来搜索。
tl;dr:对于这样的设计问题,请考虑 entities。 人际关系,amd 人际关系。
您有两个实体,records
和 lids
。他们有many-to-many关系
让我们将您的第二个 table 称为 records_lids
,以表明它是记录和盖子之间的 many-to-many 关联 table。它有两列,record_id
和 lid
。当 table 中存在一行时,表示提到的 record_id
提到了 lid
。
table 的主键应该由它的两个列 (record_id, lid)
组成。因为主键是唯一的,所以这可以防止任何记录多次具有相同的盖子。
现在,找到带有盖子 l1
的 record_id 值集很容易。你甚至不需要你的第一个 table.
SELECT record_id FROM records_lids WHERE lid = `l1`
要查找具有多个盖子的记录,您需要获取记录集与每个盖子的逻辑交集。您可以这样做:(https://www.db-fiddle.com/f/cLf4b6LDwMH9eFRTTheZJr/0)
SELECT record_id
FROM (SELECT record_id FROM records_lids WHERE lid = 'l1') l1
NATURAL JOIN (SELECT record_id FROM records_lids WHERE lid = 'l2') l2
NATURAL JOIN (SELECT record_id FROM records_lids WHERE lid = 'l3') l3
NATURAL JOIN 操作处理交集操作;结果仅包含具有匹配 record_id
值的行。 (其他一些 SQL table 服务器有 INTERSECT 运算符,但 MySQL 没有,但是...)
你也可以这样做(https://www.db-fiddle.com/f/cLf4b6LDwMH9eFRTTheZJr/1)。
SELECT record_id
FROM records_lids
WHERE lid IN ('l1','l2','l3')
GROUP BY record_id
HAVING COUNT(*) = 3
HAVING 子句是您坚持想要所有三个盖子的记录的方式。
一旦你有了一组 record_id,你就可以将它加入你的另一组 table。 (https://www.db-fiddle.com/f/cLf4b6LDwMH9eFRTTheZJr/2)
SELECT records.*
FROM (SELECT record_id FROM records_lids WHERE lid = 'l1') l1
NATURAL JOIN (SELECT record_id FROM records_lids WHERE lid = 'l2') l2
NATURAL JOIN (SELECT record_id FROM records_lids WHERE lid = 'l3') l3
NATURAL JOIN records
或(https://www.db-fiddle.com/f/cLf4b6LDwMH9eFRTTheZJr/3)
SELECT *
FROM records
WHERE record_id IN (
SELECT record_id
FROM records_lids
WHERE lid IN ('l1','l2','l3')
GROUP BY record_id
HAVING COUNT(*) = 3
)
编辑:我没有完全理解你的问题。您想要排除没有*精确(匹配的盖子集的记录。试试这个(https://www.db-fiddle.com/f/cLf4b6LDwMH9eFRTTheZJr/4)。它取决于 MySQL 的一个怪癖,即像 lid IN ('l1', 'l2')
这样的布尔表达式具有假时值为 0,真时值为 1。
SELECT *
FROM records
WHERE record_id IN (
SELECT record_id
FROM records_lids
GROUP BY record_id
HAVING SUM(lid IN ('l1', 'l2')) = 2
AND COUNT(*) = 2
)
SQL 本质上是一种用于操作集合的语言。这里的设计手法是
- 找出你的实体
- 找出它们之间的关系
- 弄清楚如何获得所需的实体集
- 检索您需要匹配集合的行