Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL过程:通过计算输入参数在存在和不存在之间进行更改?_Mysql_Sql - Fatal编程技术网

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

我正在开发一个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 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语句有什么缺点吗?(有没有更好的方法来实现这一点,我不知道?

以下是您选择不编写动态查询的几个原因:

  • 在存储过程中编写动态查询会使您更有可能创建SQL注入漏洞。您的代码示例似乎并非如此,但如果您开始大规模编写动态查询,这肯定是一个风险

  • MySQL预编译存储过程的执行计划,并从缓存执行查询。这提供了最佳性能。动态查询不能以这种方式缓存,因为它们必须在运行时为每个请求生成

  • 当出现问题时,调试动态查询可能会更加困难。您可以在运行时获得语法错误,否则静态存储过程会在编译时捕获这些错误

  • 它可能会使用更多的代码行,但您的第一个示例很好。它比您的第二个示例更容易理解,并且没有我上面列出的任何缺点


    此外,我不会说您的第一个代码示例违反了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供应商不太可能像在显式
    存在的情况下那样直接优化它。