如何在 MySQL 中存储具有属性的唯一列表

How to store unique list with properties in MySQL

我想像下面这样存储数据,唯一的是 user_idlids,在 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

我的查询模式是:

基本上,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 人际关系

您有两个实体,recordslids。他们有many-to-many关系

让我们将您的第二个 table 称为 records_lids,以表明它是记录和盖子之间的 many-to-many 关联 table。它有两列,record_idlid。当 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 本质上是一种用于操作集合的语言。这里的设计手法是

  1. 找出你的实体
  2. 找出它们之间的关系
  3. 弄清楚如何获得所需的实体集
  4. 检索您需要匹配集合的行