我有一个挂锁表,它(不幸的)由一个带有逗号分隔数据的列组成. 表由挂锁组成,带有给定挂锁的锁类型的信息(以及它是大的还是小的). 给我一把 keys ,它可以解锁某些类型的锁(和大小),我想找出我可以解锁的挂锁.键还具有逗号分隔的Lock类型和大小.

Padlocks

Name Locks Size
A KL, OK, CZ, CZ Small
B OK, OK Small
C OK, CZ, KL Small
D RO, CZ, CZ Small
E OK, OK, KL, KL Small
F OK, OK, CZ, KL Big

(输入)键(‘KL,OK,OK,CZ,CZ’,‘Small’)将返回

Name
A
B
C

请注意,如果一把 keys 只能解锁‘KL’的一个实例,则它不会解锁‘E’,因为它需要两个‘KL,KL’.挂锁‘D’无法解锁,因为它需要‘RO’.挂锁‘F’无法解锁,因为它需要‘Big’ keys .

如果是像C#这样的编程语言,我会做什么,我会将Key的输入拆分成数组[‘KL’,‘OK’,‘OK’,‘CZ’,‘CZ’],对于每一行,我还会将Lock拆分成数组,并比较两个数组

伪码

foreach Lock in Locks
for(i=0;i<UBound(Lock);i++)
 for(j=0;i<UBound(Key);j++)
  If(Lock[i]=Key[j]) Lock[i].Remove Key[j].Remove

如果在某个点上Lock的值为0,则键可以打开该锁.但这远远超出了我在MariaDB中所能做的事情. 我知道FIND_IN_SET(),但它只允许我搜索一个输入,除非有方法可以使用它来满足我的需要

PS SELECT@@Version=10.3.39-MariaDB-0+deb10u2

PS2 正常化有帮助吗?我的意思是,我可以创建一个表Locks,它可以保存所有的锁类型,然后为挂锁创建一个交叉引用表-Locks.有没有一个SQL语句可以让我得到我需要的东西?

推荐答案

通过将锁规范化到新表是非常简单的:

create table paddocks (
pd char(1),
sz enum('Small', 'Big'),
key (sz));
create table locks (
pd char(1),
lk char(2),
key (pd,lk));
insert into paddocks values
('A', 'Small'),
('B', 'Small'),
('C', 'Small'),
('D', 'Small'),
('E', 'Small'),
('F', 'Big')
insert into locks values ('A', 'KL'),('A', 'OK'),('A', 'CZ'),('A', 'CZ'),
('B', 'OK'),('B', 'OK'),
('C', 'OK'),('C', 'CZ'), ('C', 'KL'),
('D', 'RO'),('D', 'CZ'), ('D', 'CZ'),
('E', 'OK'),('E', 'OK'), ('E', 'KL'), ('E', 'KL'),
('F', 'OK'),('F', 'OK'), ('F', 'CZ'), ('F', 'KL');

然后为您拥有的密钥创建一个临时表:

create temporary table ky (
lk char(2),
key (lk));
insert into ky values
('KL'),('OK'),('CZ'),('OK'),('CZ')

这构成了中间查询的一部分,以计算出每个围场每次有多少锁.

select pd, locks.lk, count(locks.lk)
from paddocks
join locks using (pd)
where sz = 'Small'
group by pd, locks.lk

pd lk count(locks.lk)
A CZ 2
A KL 1
A OK 1
B OK 2
C CZ 1
C KL 1
C OK 1
D CZ 2
D RO 1
E KL 2
E OK 2

将此与我们拥有的每种类型的密钥数量进行比较:

SELECT pd,
       p.lk,
       p.c,
       count(ky.lk) AS kc
FROM
  (SELECT pd,
          locks.lk AS lk,
          count(locks.lk) AS c
   FROM paddocks
   JOIN locks USING (pd)
   WHERE sz = 'Small'
   GROUP BY pd,
            locks.lk) p
LEFT JOIN ky USING (lk)
GROUP BY pd,
         lk
pd lk c kc
A CZ 2 2
A KL 1 1
A OK 1 2
B OK 2 2
C CZ 1 2
C KL 1 1
C OK 1 2
D CZ 2 2
D RO 1 0
E KL 2 1
E OK 2 2

现在再次按pd分组,并 Select 那些所有锁的 keys 比锁多的锁.count(pd)是锁的数量.如果没有足够的密钥,则c <= kc是布尔0,如果有足够的密钥,则为1.对于所有类型的锁,都应该有足够的 keys .

SELECT pd
FROM
  (SELECT pd,
          p.lk,
          p.c,
          count(ky.lk) AS kc
   FROM
     (SELECT pd,
             locks.lk AS lk,
             count(locks.lk) AS c
      FROM paddocks
      JOIN locks USING (pd)
      WHERE sz = 'Small'
      GROUP BY pd,
               locks.lk) p
   LEFT JOIN ky USING (lk)
   GROUP BY pd,
            lk) p
GROUP BY pd
HAVING count(pd) = sum(c <= kc)
pd
A
B
C

参考文献:fiddle

Sql相关问答推荐

按CTE创建任务表

从2个表中查找每条记录的唯一最接近的日期匹配

在SQL中创建一个计数器,根据BigQuery/SQL中的条件递归地添加行值

为什么在postgres中,横向连接比相关子查询快?

从依赖于其他表的值的XREF表中的值分组获得正确的计数?

获得第三名或最老的记录

将所有XML文件导入到SQL Server中

将SQL Server查询改进为;线程安全;

具有多个表 JOINS 的 STRING_AGG 的替代方法 (SQL Server 2016)

两个具有 NULL 值的表达式结果之间的差异

如何从三个连接表中获取数据,并始终显示第一个表中的数据,以及第三个表中的空值或现有记录?

SQL的左连接在多对多关系情况下使用

BigQuery导航函数计算ID

如何从一张表中获取值在至少三行相同的记录

在给定的日期范围内填写缺失的日期

在 MS Access 中连接相关记录

在给定列中具有特定值的行与 SQL 中的总行数的比率

如何在 RavenDB Studio (RQL) 中插入更新文档

SQL 查询以填充单个列中的所有值

Oracle SQL 查询自行运行,但在包装到select count(*) from ()时失败