MySQL过程:通过计算输入参数在存在和不存在之间进行更改?
我正在开发一个MySQL程序。我在做这样的事情:MySQL过程:通过计算输入参数在存在和不存在之间进行更改?,mysql,sql,Mysql,Sql,我正在开发一个MySQL程序。我在做这样的事情: IF aninputparam = 1 THEN SELECT blah FROM blah JOIN etc etc WHERE EXISTS (SELECT mysubquery) ELSE SELECT allthesamestuff FROM allthesametables JOIN allthesamejoins WHERE NOT EXISTS (SELECT sam
IF aninputparam = 1 THEN
SELECT blah
FROM blah
JOIN etc etc
WHERE EXISTS (SELECT mysubquery)
ELSE
SELECT allthesamestuff
FROM allthesametables
JOIN allthesamejoins
WHERE NOT EXISTS (SELECT samesubquery)
END IF
这是可行的,但它冒犯了我的艺术敏感性,并且违背了枯燥的原则,更不用说剪切粘贴的建筑反模式的例子了。我能做点像这样的事吗
@x = concat(
'SELECT blah FROM blah JOIN etc WHERE ',
IF(aninputparam = 1, 'EXISTS', 'NOT EXISTS'),
' (SELECT mysubquery)'
);
PREPARE stmt1 FROM @x;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
如果是这样,那么以这种方式动态准备SQL语句有什么缺点吗?(有没有更好的方法来实现这一点,我不知道?以下是您选择不编写动态查询的几个原因:
此外,我不会说您的第一个代码示例违反了DRY原则。这两个查询做两件不同的事情。但是,您的第二个示例很可能违反KISS原则。您可以使用计数来处理存在和不存在的情况:
select foo
from bar
where @param = (select case when count(*) > 1 then 1 else 0 end from ...)
问题是,这些灵活的查询并不总是产生最优的计划,它们也经常混淆意图。动态sql的替代方案也有很多缺点。(我现在明白了这是你的主要问题。)因此,尽管担心重复你自己,但这通常只是更好的方法。实现这一目标的一种方法是通过加入
JOIN
s:
架构设置:
CREATE TABLE foo (x INTEGER);
INSERT INTO foo VALUES (1);
INSERT INTO foo VALUES (2);
CREATE TABLE bar (x INTEGER);
INSERT INTO bar VALUES (1);
不相关条件:
对于不相关的情况,请使用交叉连接:
SELECT
f.*
FROM
foo f
CROSS JOIN (
SELECT
SIGN(COUNT(1)) n
FROM
bar b
) a
WHERE
a.n = 1 -- 1: EXISTS, 0: NOT EXISTS
| x |
|---|
| 1 |
| 2 |
SELECT
f.*
FROM
foo f
LEFT JOIN (
SELECT
b.x, SIGN(COUNT(1)) n
FROM
bar b
GROUP BY
b.x
) a ON (
a.x = f.x
)
WHERE
COALESCE(a.n, 0) = 0 -- 1: EXISTS, 0: NOT EXISTS
| x |
|---|
| 2 |
相关条件:
如果需要将条件与驾驶台关联,请使用左连接
:
SELECT
f.*
FROM
foo f
CROSS JOIN (
SELECT
SIGN(COUNT(1)) n
FROM
bar b
) a
WHERE
a.n = 1 -- 1: EXISTS, 0: NOT EXISTS
| x |
|---|
| 1 |
| 2 |
SELECT
f.*
FROM
foo f
LEFT JOIN (
SELECT
b.x, SIGN(COUNT(1)) n
FROM
bar b
GROUP BY
b.x
) a ON (
a.x = f.x
)
WHERE
COALESCE(a.n, 0) = 0 -- 1: EXISTS, 0: NOT EXISTS
| x |
|---|
| 2 |
很好的观察结果,谢谢。既然你提到了,接吻比通常的干吻更重要。这很有趣。我正在查找foo中所有在bar中的记录,或者foo中所有不在bar中的记录(用例是从父实体添加或删除子关系,向用户提供可以添加的记录或可以删除的记录的列表),其结果由相关条件给出。我会研究一下,找出原因。
SIGN(COUNT(1))
的具体功能是什么?SIGN(COUNT(1))
在bar
中有一行或多行用于键时返回1
(当COUNT(1)>为0时,可以写成CASE,当COUNT(1)>为0时,则1其他0结束
)。如果键在栏中没有行
,则左连接
返回NULL
,这就是为什么在相关情况下需要合并
,而不是像在不相关情况下那样直接与0
进行比较。好的,我明白了。我以前从未使用过符号,所以我查了一下。很简单。我以前也没见过计数(1)
;关于它是否真的是COUNT(*)
的优化版本的争论似乎仍在继续。不错的选择,谢谢你发布。我找到你的小提琴,检查了WHERE existing
备选方案的执行计划。它们是完全不同的,因此在更大的上下文中,检查两种方法的计划是明智的。我一直不喜欢使用*
版本,可能是因为如果你在进行计数(条件为1结束时的情况下)
等条件计数,使用1
会更直接一些,但我不相信任何现代数据库会以任何不同的方式对待它(总有一天必须检查!)。另外,我同意我的查询计划会有很大的不同,DB供应商不太可能像在显式存在的情况下那样直接优化它。