mysql - 撤消 CTE(公用表表达式)

标签 mysql mariadb common-table-expression

另一位开发人员针对 MariaDB(MySQL 版本 10.x)编写了一个查询,而不是应该为 MySQL 数据库(MySQL 版本 5.6)编写的查询。他们不再可以让他们为 MySQL 5.6 重写它。

有人可以协助进行逆向工程吗?

WITH temptable (column1, column2, column3) 
     AS (SELECT t3.column1, 
                t3.column2, 
                CASE 
                  WHEN t3.column3 = 1 
                       AND t2.column3 = 1 THEN 2 
                  ELSE COALESCE(t2.column3, 0) 
                END AS column3 
         FROM   table1 t1 
                JOIN table2 t2 
                  ON t1.column5 = t2.column5 
                     AND t1.column6 = t2.column6 
                JOIN table3 t3 
                  ON t3.column1 = t2.column1 
         WHERE  t1.column4 = :var1 
                AND t1.column6 = :var2 
                AND t3.column7 = 0)
SELECT column2, 
       column3 
FROM   temptable 
UNION 
SELECT t3.column2, 
       t3.column3 
FROM   table3 t3 
WHERE  t3.column7 = -1 
UNION 
SELECT t3.column2, 
       0 AS column3 
FROM   table3 t3 
       LEFT JOIN temptable temp 
              ON temp.column2 = t3.column2 
WHERE  temp.action IS NULL 
       AND t3.column7 = 0;

表格和列已更改以保护无辜者。

最佳答案

“简单按钮”修复是采用 CTE 的定义并将其用作内联 View ,代替外部查询中对 temptable 的引用。 (这不一定是最佳解决方案,也不一定是编写查询的最佳方法。)

<小时/>

切掉查询的开头,这部分,

WITH temptable 
( column1
, column2
, column3
) 
AS
( SELECT t3.column1
       , t3.column2
       , CASE
           WHEN t3.column3 = 1 AND t2.column3 = 1 THEN 2
           ELSE COALESCE(t2.column3, 0)
         END AS column3 
    FROM table1 t1
    JOIN table2 t2
      ON t1.column5   = t2.column5
     AND t1.column6   = t2.column6
    JOIN table3 t3
      ON t3.column1   = t2.column1
   WHERE t1.column4   = :var1
     AND t1.column6   = :var2 
     AND t3.column7   = 0
)

只剩下这个:

SELECT a.column2
     , a.column3 
  FROM temptable a

 UNION 

SELECT b.column2
     , b.column3 
  FROM table3 b
 WHERE b.column7 = -1

 UNION 

SELECT p.column2
     , 0 AS column3
  FROM table3 p
  LEFT
  JOIN temptable q
    ON q.column2 = p.column2
 WHERE q.action IS NULL
   AND p.column7 = 0

(正如对该问题的评论中所述,对 action 的引用无效,因为 temptable 中没有名为 action 的列。 )

然后将对 CTE temptable 的引用替换为内联 View 定义。

在查询中,这将是别名 aq

像这样:

SELECT a.column2
     , a.column3 
  FROM -- temptable
       ( 
         SELECT t3.column1
              , t3.column2
              , CASE
                  WHEN t3.column3 = 1 AND t2.column3 = 1 THEN 2
                  ELSE COALESCE(t2.column3, 0)
                END AS column3 
           FROM table1 t1
           JOIN table2 t2
             ON t1.column5   = t2.column5
            AND t1.column6   = t2.column6
           JOIN table3 t3
             ON t3.column1   = t2.column1
          WHERE t1.column4   = :var1
            AND t1.column6   = :var2 
            AND t3.column7   = 0
       ) a

 UNION

SELECT b.column2
     , b.column3 
  FROM table3 b
 WHERE b.column7 = -1

 UNION 

SELECT p.column2
     , 0 AS column3
  FROM table3 p
  LEFT
  JOIN -- temptable 
       (
         SELECT t3.column1
              , t3.column2
              , CASE
                  WHEN t3.column3 = 1 AND t2.column3 = 1 THEN 2
                  ELSE COALESCE(t2.column3, 0)
                END AS column3 
           FROM table1 t1
           JOIN table2 t2
             ON t1.column5   = t2.column5
            AND t1.column6   = t2.column6
           JOIN table3 t3
             ON t3.column1   = t2.column1
          WHERE t1.column4   = :var1
            AND t1.column6   = :var2 
            AND t3.column7   = 0
       ) q
    ON q.column2 = p.column2
 WHERE q.action IS NULL
   AND p.column7 = 0

编辑

哦,还有...第二次出现的内联 View 定义中对 :var1:var2 占位符的引用可能需要更改为唯一... :var1b:var2b (至少,使用 PDO 的命名占位符就是这种情况,它们必须是唯一的)

需要为新的绑定(bind)占位符提供为 :var1:var2 提供的值的副本。

跟进

问:这个查询……点击率很高。您提到了“简单的修复”,但代价是什么?

答:在“简单按钮”修复中,两个内联 View aq(替换对 CTE 的引用)分别具体化。内联 View 查询执行两次,结果具体化到两个单独的派生表中。 (EXPLAIN 输出将显示两个单独的派生表,aq)。

关于mysql - 撤消 CTE(公用表表达式),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50937740/

相关文章:

python - 如何通过python将数据存储到MySQL数据库中

php - 获取由选择选项填充的文本值

MySql 类型 char 选择最大数量

mysql - php sql查询在月份和年份之间选择

java - ZeroDateTimeBehavior=convertToNull 在使用 hibernate 的 jdbc url 中不起作用

sql - 递归复制条目

mysql - Debian 上的 MariaDB : Syntax error: How to switch unix socket authentication back to password-based?

mysql - 数据库 : performance of dynamic vs. 表中最新样本的静态查找

sql - PostgreSQL 中的递归 CTE 问题

postgresql - 在不使用 CTE 的情况下,是否有此查询的逻辑等效且有效的版本?