【问题标题】:Why doesn't my MySql-Query work the way I would like it to work?为什么我的 MySql-Query 不能按照我希望的方式工作?
【发布时间】:2021-05-29 01:13:06
【问题描述】:

我有一个 MySQL-DB,它有三个表:药物、成分(两者都有 m:n 关系)和一个链接表/关联表。所以很明显一种药物可以有多种成分,并且成分可以存在于多种药物中。我想创建一个网站,我的用户可以在其中选择

DROP procedure IF EXISTS `getMeds`;

DELIMITER $$
USE `epharmacy`$$
CREATE PROCEDURE `getMeds` (IN all1 VARCHAR(10), IN all2 VARCHAR(10), IN all3 VARCHAR(10), 
                            IN unall1 VARCHAR(10), IN unall2 VARCHAR(10), IN unall3 VARCHAR(10))
BEGIN
SELECT m_id, m_name, i_id, i_name FROM epharmacy.`mi_med-ing` INNER JOIN epharmacy.`m_medication` 
INNER JOIN epharmacy.`i_ingredients` 
ON mi_m_id = m_id AND mi_i_id = i_id

#Allowed
WHERE (i_id = all1 OR all1 = '') 
AND (i_id = all2 OR all2 = '')
AND (i_id = all3 OR all3 = '') 

#Unallowed
AND ((i_id!= unall1 OR unall1 = '') 
AND (i_id != unall2 OR unall2 = '') 
AND (i_id != unall3 OR unall3 = ''))

ORDER BY m_id ASC;
END
$$
DELIMITER ;

call getMeds('I005', 'I006', 'I007', 'I001', 'I002', 'I003');

但这不知何故不起作用。我应该得到两种药物作为回报,但我什么也没得到。我尝试了很多东西,比如子查询和其他 JOINS,但没有帮助。希望你能:)

编辑: 这就是我的数据库的样子: m_medication:

CREATE TABLE IF NOT EXISTS `m_medication` (
  `m_id` varchar(10) NOT NULL,
  `m_name` varchar(500) DEFAULT NULL,
  PRIMARY KEY (`m_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `m_medication` (`m_id`, `m_name`) VALUES('M00001', 'drug1');
INSERT INTO `m_medication` (`m_id`, `m_name`) VALUES('M00002', 'drug2');

i_ingredients:

CREATE TABLE IF NOT EXISTS `i_ingredients` (
  `i_id` varchar(10) NOT NULL,
  `i_name` varchar(500) DEFAULT NULL,
  PRIMARY KEY (`i_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `i_ingredients` (`i_id`, `i_name`) VALUES('I005', 'ingredient1');
INSERT INTO `i_ingredients` (`i_id`, `i_name`) VALUES('I006', 'ingredient2');
INSERT INTO `i_ingredients` (`i_id`, `i_name`) VALUES('I007', 'ingredient3');

mi_med-ing:

CREATE TABLE IF NOT EXISTS `mi_med-ing` (
  `mi_id` varchar(10) NOT NULL,
  `mi_i_id` varchar(10) DEFAULT NULL,
  `mi_m_id` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`mi_id`),
  KEY `mi_i_id` (`mi_i_id`),
  KEY `mi_m_id` (`mi_m_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI001', 'I005', 'M00001'); 
INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI002', 'I006', 'M00001'); 
INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI003', 'I007', 'M00001'); 
INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI004', 'I005', 'M00002'); 
INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI005', 'I006', 'M00002'); 
INSERT INTO mi_med-ing (mi_id, mi_i_id, mi_m_id) VALUES('MI006', 'I007', 'M00002');

外键:

ALTER TABLE `mi_med-ing`
  ADD CONSTRAINT `mi_med-ing_ibfk_1` FOREIGN KEY (`mi_i_id`) REFERENCES `i_ingredients` (`i_id`),
  ADD CONSTRAINT `mi_med-ing_ibfk_2` FOREIGN KEY (`mi_m_id`) REFERENCES `m_medication` (`m_id`);

【问题讨论】:

  • 要添加样本数据和预期输出neebs..
  • 您正在尝试匹配同一行中的多个成分 ID,而不是按药物对行进行分组。
  • 请参阅stackoverflow.com/questions/16704290/…,了解如何获得包含所有成分的药物。
  • 然后使用NOT IN过滤掉不需要的药物
  • @P.Salmon 我有一些,这就是为什么我期待两个结果。

标签: mysql database stored-procedures subquery


【解决方案1】:

一共有三个表:

  • m_medication = 药物
  • i_ingredients = 成分
  • mi_med-ing = m:n 关系的桥接表

您想退回药品及其所有成分,以下适用于药品:

  • 所有需要的成分都在药物中
  • 药物中没有不良成分

两步:

  1. 汇总每种药物的桥接表以查找满足所有要求的所有药物。
  2. 选择所有由此找到的药物及其成分。

程序:

CREATE PROCEDURE getMeds (IN all1 VARCHAR(10), IN all2 VARCHAR(10), IN all3 VARCHAR(10), 
                          IN unall1 VARCHAR(10), IN unall2 VARCHAR(10), IN unall3 VARCHAR(10))
BEGIN
  SELECT m.*, i.*
  FROM epharmacy.m_medication m
  JOIN epharmacy.`mi_med-ing` mi ON mi.mi_m_id = m.m_id
  JOIN epharmacy.i_ingredients i ON i.i_id = mi.mi_i_id
  WHERE m.m_id IN
  (
    SELECT mi_m_id
    FROM epharmacy.`mi_med-ing`
    GROUP BY mi_m_id
    HAVING (all1   = '' OR SUM(mi_i_id = all1)   > 0)
       AND (all2   = '' OR SUM(mi_i_id = all2)   > 0)
       AND (all3   = '' OR SUM(mi_i_id = all3)   > 0)
       AND (unall1 = '' OR SUM(mi_i_id = unall1) = 0)
       AND (unall2 = '' OR SUM(mi_i_id = unall2) = 0)
       AND (unall3 = '' OR SUM(mi_i_id = unall3) = 0)
  )
  ORDER BY m.m_id, i.i_id;
END

聚合的工作原理:在 MySQL 中,true = 1 和 false = 0。我将布尔表达式相加,因此当根本没有匹配时得到 0,或者当组中有匹配时得到 > 0。

演示:https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=2e623f39daac369e3ac58ff1b18d992b

【讨论】:

    【解决方案2】:

    要查找具有所有所需成分的所有药物,您需要在连接表中执行分组查询;见How to return rows that have the same column values in MySql

    要排除不允许的成分,请使用返回包含这些成分的任何药物的子查询,然后使用m_id NOT IN (subquery) 将它们过滤掉。

    CREATE PROCEDURE `getMeds` (IN all1 VARCHAR(10), IN all2 VARCHAR(10), IN all3 VARCHAR(10), 
                                IN unall1 VARCHAR(10), IN unall2 VARCHAR(10), IN unall3 VARCHAR(10))
    BEGIN
    DECLARE all_count INT DEFAULT (all1 != '') + (all2 != '') + (all3 != '');
    SELECT m_id, m_name, i_id, i_name
    FROM (SELECT mi_m_id
          FROM `mi_med-ing`
          WHERE mi_i_id IN (all1, all2, all3)
          GROUP BY mi_m_id
          HAVING COUNT(*) = all_count) AS a
    INNER JOIN `mi_med-ing` AS mi ON mi.mi_m_id = a.mi_m_id
    INNER JOIN `m_medication` ON mi.mi_m_id = m_id
    INNER JOIN `i_ingredients` ON mi.mi_i_id = i_id
    WHERE m_id NOT IN (
        SELECT mi_m_id
        FROM `mi_med-ing`
        WHERE mi_i_id IN (unall1, unall2, unall3)
    )
    ORDER BY m_id ASC;
    END
    

    【讨论】:

    • 我收到第一个 SELECT 的语法错误。它表示“SELECT”在该位置无效。
    • 确保; 位于DECLARE 行的末尾。
    • 如果您使用该错误消息搜索其他问题,通常是由于缺少分隔符。
    • 我刚刚编辑了DEFAULT值中的括号,我认为我之前的版本优先级不正确。
    • 我认为问题不在于 DECLARE 行,因为我在删除 SELECT 时没有收到任何错误。但是我在 SELECT 语句中搜索了缺少的括号,但找不到。
    猜你喜欢
    • 2017-07-14
    • 2022-11-12
    • 2022-12-13
    • 1970-01-01
    • 2022-11-12
    • 2015-04-29
    • 2018-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多