问题描述
我想在MysqL中存储如下数据,它们分别在user_id
和lids
上存储
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的长度和宽度
基本上,盖子的输入可以以任何顺序进行搜索,但仍应提供正确的长度和宽度。
因此,我们不应该将逗号分隔的值存储在RDBMS中。
问题-我应该如何构造数据库以使其具有不连续的user_id/lids
组合,这些组合可以提供正确的长度和广度而无需太多的字符串操作?
select * from table1 where find_in_set('l2',lids) AND find_in_set('l1',lids);
然后在代码中,确定计数准确为2个盖子。但这不是完美的解决方案。需要指导。
AddOn-不需要编写本机SQL查询的特定于SpringBoot + JPA(休眠)的解决方案
根据注释,如果我为lids
创建表-
recordid(fk) lid
----------------------------------
1 l1
1 l2
2 l1
3 l1
3 l3
3 l2
4 l2
4 l3
那我将如何确保只有一种独特的盖子组合可供用户使用? 我的选择查询是什么?会是这样吗?
select * from table1,lids where main.recordid = lids.recordid and lid IN ('l2','l3');
IN
运算符将运行OR
而不是AND
查询,这也会产生错误的结果。
我是否必须基于recordid
表中的lids
进行分组,然后应用where
条件?抱歉,我读过许多与之相关的文章并分心了,我对此感到非常困惑。
好的,问题基本上可以归结为这个问题-How to find if a list/set is exactly within another list
我想找到具有 EXACT 个要搜索的盖子的记录ID。
解决方法
tl; dr:针对此类设计问题,请考虑实体。 relationships ,amd sets 。
您有两个实体,records
和lids
。他们有一个多对多关系。
让我们调用第二个表records_lids
,以表明它是记录和盖子之间的多对多关联表。它有两列record_id
和lid
。如果该表中存在一行,则意味着所提到的record_id
带有所提到的lid
。
该表的主键应由其两个列(record_id,lid)
组成。由于主键是唯一的,因此可以防止任何记录多次具有相同的盖子。
现在,找到带有盖子l1
的record_id值集很容易。您甚至不需要第一张桌子。
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表服务器品牌都具有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_ids集,就可以将其加入到另一个表中。 (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','l3')
GROUP BY record_id
HAVING COUNT(*) = 3
)
编辑:我不完全理解您的问题。您想排除没有* exactly(匹配的盖子的记录。请尝试(https://www.db-fiddle.com/f/cLf4b6LDwMH9eFRTTheZJr/4)。这取决于MySQL的一个怪癖,即lid IN ('l1','l2')
之类的布尔表达式为false时,值为0。如果为true,则为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本质上是一种用于操纵集合的语言。这里的设计技巧是
- 弄清楚您的实体
- 弄清楚它们之间的关系
- 弄清楚如何获取所需的实体集
- 检索需要与集合匹配的行