You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MariaDB查询:用多值逗号分隔钥匙匹配可解锁挂锁

解决挂锁钥匙匹配问题(MariaDB 10.3)

一、基于现有非规范化表的实现

你的场景中,Locks列用逗号分隔存储锁型,要实现按锁型数量匹配的逻辑,可借助MariaDB 10.3支持的递归CTE拆分字符串,统计各锁型的出现次数后对比:

完整查询语句

WITH RECURSIVE key_locks AS (
    -- 拆分输入的钥匙锁型字符串
    SELECT 
        SUBSTRING_INDEX('KL, OK, OK, CZ, CZ', ',', 1) AS lock_type,
        TRIM(SUBSTRING_INDEX('KL, OK, OK, CZ, CZ', ',', 1)) AS trimmed_lock,
        SUBSTRING('KL, OK, OK, CZ, CZ', LENGTH(SUBSTRING_INDEX('KL, OK, OK, CZ, CZ', ',', 1)) + 2) AS remaining
    UNION ALL
    SELECT 
        SUBSTRING_INDEX(remaining, ',', 1),
        TRIM(SUBSTRING_INDEX(remaining, ',', 1)),
        SUBSTRING(remaining, LENGTH(SUBSTRING_INDEX(remaining, ',', 1)) + 2)
    FROM key_locks
    WHERE remaining != ''
),
key_lock_counts AS (
    -- 统计钥匙中每个锁型的数量
    SELECT trimmed_lock, COUNT(*) AS count
    FROM key_locks
    GROUP BY trimmed_lock
),
padlock_locks AS (
    -- 拆分挂锁表中符合尺寸条件的Locks列
    SELECT 
        p.Name,
        p.Size,
        TRIM(SUBSTRING_INDEX(p.Locks, ',', 1)) AS trimmed_lock,
        SUBSTRING(p.Locks, LENGTH(SUBSTRING_INDEX(p.Locks, ',', 1)) + 2) AS remaining
    FROM Padlocks p
    WHERE p.Size = 'Small'
    UNION ALL
    SELECT 
        pl.Name,
        pl.Size,
        TRIM(SUBSTRING_INDEX(pl.remaining, ',', 1)),
        SUBSTRING(pl.remaining, LENGTH(SUBSTRING_INDEX(pl.remaining, ',', 1)) + 2)
    FROM padlock_locks pl
    WHERE pl.remaining != ''
),
padlock_lock_counts AS (
    -- 统计每个挂锁的各锁型数量
    SELECT 
        Name,
        trimmed_lock,
        COUNT(*) AS count
    FROM padlock_locks
    GROUP BY Name, trimmed_lock
)
-- 筛选符合条件的挂锁
SELECT DISTINCT plc.Name
FROM padlock_lock_counts plc
JOIN key_lock_counts klc ON plc.trimmed_lock = klc.trimmed_lock
WHERE plc.count <= klc.count
-- 确保挂锁没有钥匙不包含的锁型
AND NOT EXISTS (
    SELECT 1
    FROM padlock_lock_counts plc2
    WHERE plc2.Name = plc.Name
    AND NOT EXISTS (
        SELECT 1
        FROM key_lock_counts klc2
        WHERE klc2.trimmed_lock = plc2.trimmed_lock
    )
)
ORDER BY plc.Name;

这个查询会返回A、B、C,完全符合需求:

  • 自动过滤尺寸不匹配的挂锁F
  • 排除包含钥匙没有的锁型(如RO)的挂锁D
  • 拒绝钥匙锁型数量不足的挂锁E(钥匙只有1个KL,挂锁E需要2个)

二、数据库规范化方案(推荐)

逗号分隔的列会导致查询复杂、性能低下,还容易出现数据格式错误,更合理的做法是规范化数据库结构:

1. 创建规范化表结构

-- 挂锁主表:存储基本信息
CREATE TABLE Padlocks (
    PadlockID INT AUTO_INCREMENT PRIMARY KEY,
    Name VARCHAR(50) NOT NULL,
    Size ENUM('Small', 'Big') NOT NULL
);

-- 锁型字典表:统一管理锁型(可选,但能避免字符串不一致问题)
CREATE TABLE LockTypes (
    LockTypeID INT AUTO_INCREMENT PRIMARY KEY,
    TypeCode VARCHAR(10) NOT NULL UNIQUE
);

-- 关联表:记录挂锁的每个锁型(重复锁型对应多条记录)
CREATE TABLE Padlock_LockTypes (
    Padlock_LockID INT AUTO_INCREMENT PRIMARY KEY,
    PadlockID INT NOT NULL,
    LockTypeID INT NOT NULL,
    FOREIGN KEY (PadlockID) REFERENCES Padlocks(PadlockID),
    FOREIGN KEY (LockTypeID) REFERENCES LockTypes(LockTypeID)
);

2. 插入示例数据

比如挂锁A的锁型是KL, OK, CZ, CZ,就向Padlock_LockTypes插入4条记录,分别对应KL、OK、CZ、CZ的LockTypeID。

3. 简化的查询逻辑

对于输入的钥匙锁型,先统计各锁型数量,再查询符合条件的挂锁:

-- 创建临时表存储钥匙的锁型统计
CREATE TEMPORARY TABLE KeyLockCounts (
    LockTypeID INT,
    Count INT
);

-- 插入钥匙的锁型数据(示例:KL×1、OK×2、CZ×2)
INSERT INTO KeyLockCounts (LockTypeID, Count)
SELECT lt.LockTypeID, COUNT(*)
FROM (
    SELECT 'KL' AS TypeCode UNION ALL
    SELECT 'OK' UNION ALL
    SELECT 'OK' UNION ALL
    SELECT 'CZ' UNION ALL
    SELECT 'CZ'
) key_types
JOIN LockTypes lt ON key_types.TypeCode = lt.TypeCode
GROUP BY lt.LockTypeID;

-- 查询可解锁的挂锁
SELECT p.Name
FROM Padlocks p
JOIN Padlock_LockTypes plt ON p.PadlockID = plt.PadlockID
JOIN LockTypes lt ON plt.LockTypeID = lt.LockTypeID
WHERE p.Size = 'Small'
GROUP BY p.PadlockID, p.Name
HAVING 
    -- 挂锁所有锁型都存在于钥匙中
    SUM(CASE WHEN EXISTS (SELECT 1 FROM KeyLockCounts klc WHERE klc.LockTypeID = lt.LockTypeID) THEN 0 ELSE 1 END) = 0
    -- 挂锁每个锁型的数量不超过钥匙的对应数量
    AND MAX(CASE WHEN (SELECT klc.Count FROM KeyLockCounts klc WHERE klc.LockTypeID = lt.LockTypeID) >= COUNT(lt.LockTypeID) THEN 1 ELSE 0 END) = 1;

规范化后的结构不仅让查询更简洁,还能提升性能、降低数据出错概率,是长期维护的最优方案。

内容的提问来源于stack exchange,提问作者cantorre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 09:15:30