PLSQL:子查询之外的条件

Posted

技术标签:

【中文标题】PLSQL:子查询之外的条件【英文标题】:PLSQL : where condition outside of subquery 【发布时间】:2018-11-23 12:33:52 【问题描述】:

我有一个这样的查询(原来的要复杂得多)

select 0, 999, count(case when cond = 'aa' then 1 end) val1, sum(case when cond = 'aa' then amount else 0 end) amount1,
   count(case when cond = 'bb' then 1 end) val2, sum(case when cond = 'bb' then amount else 0 end) amount2
from myTable
where amount between 0 and 999
union
select 1000, 2999, count(case when cond = 'aa' then 1 end) val1, sum(case when cond = 'aa' then amount else 0 end) amount1,
   count(case when cond = 'bb' then 1 end) val2, sum(case when cond = 'bb' then amount else 0 end) amount2
from myTable
where amount between 1000 and 2999
union
...

有多个联合,选择更复杂。

我想简化它。为此,我使用了 with 子句

with q1 as(
    select case when cond = 'aa' then 1 end val1, case when cond = 'aa' then amount else 0 end amount1,
           case when cond = 'bb' then 1 end val2, case when cond = 'bb' then amount else 0 end amount2
)
select 0, 999, sum(val1) val1, sum(amount1) amount1, sum(val2) val2, sum(amount2) amount2
from q1 where amount between 0 and 999
union
select 1000, 2999, sum(val1) val1, sum(amount1) amount1, sum(val2) val2, sum(amount2) amount2
from q1 where amount between 1000 and 2999
union
....

但就我而言,这仍然很长。 plsql中是否有可能这样写

with q1 as (
   select minVal, maxVal, count(case when cond = 'aa' then 1 end) val1, sum(case when cond = 'aa' then amount else 0 end) amount1,
      count(case when cond = 'bb' then 1 end) val2, sum(case when cond = 'bb' then amount else 0 end) amount2
   from myTable
   where amount between minVal and maxVal
)
      select * from q1 insideWhere minVal=0 and maxVal=999
union select * from q1 insideWhere minVal=1000 and maxVal=2999
union ...

或者任何其他解决方案?

【问题讨论】:

如果您能更详细地描述您的实际问题,您可能会得到一些更好的答案。 IE。原始查询寻址有什么问题?这样,我们或许能够为您提供更好的选择,而不仅仅是盲目地尝试遵循您唯一的方向(如果可能的话,这不一定是最好的)。 它与第一个查询大致相同,但(cond = 'aa' then 1 end 时的情况)条件更复杂,有超过 20 个 case 甚至更多 union 更多的数量步骤(在 x 和 y 之间)将根据所要求的内容而改变,并且我的表已经是 with 子句的结果 【参考方案1】:

这听起来应该是一个单一的聚合查询,例如:

SELECT min_val,
       max_val,
       COUNT(CASE WHEN cond = 'aa' THEN 1 END) val1,
       SUM(CASE WHEN cond = 'aa' THEN amount ELSE 0 END) amount1,
       COUNT(CASE WHEN cond = 'bb' THEN 1 END) val2,
       SUM(CASE WHEN cond = 'bb' THEN amount ELSE 0 END) amount2,
FROM   (SELECT cond,
               amount,
               CASE WHEN amount BETWEEN 0 AND 999 THEN 0
                    WHEN amount BETWEEN 1000 AND 2999 THEN 1000
               END min_val,
               CASE WHEN amount BETWEEN 0 AND 999 THEN 999
                    WHEN amount BETWEEN 1000 AND 2999 THEN 2999
               END max_val
        FROM   mytable) -- using a subquery here to avoid repeating the case statement in both the select column list and the group by column list
GROUP BY min_val,
         max_val;

【讨论】:

【参考方案2】:

要执行您正在尝试的操作,您需要将最小/最大组显示为类似表格的结构。您已经完成了大部分工作:最简单的方法是使用WITH 子句。

WITH value_groups AS
         (SELECT 0 AS min_val, 999 AS max_val FROM DUAL
          UNION ALL
          SELECT 1000, 2999 FROM DUAL),
     q1 AS
         (SELECT *
          FROM   my_table
                 PIVOT
                     (COUNT (*) FOR cond IN ('aa' AS aa, 'bb' AS bb)))
SELECT   min_val,
         max_val,
         COUNT (aa) as val1,
         SUM (aa * amount) as amount1,
         COUNT (bb) as val2,
         SUM (bb * amount) as amount2 
FROM     q1 JOIN value_groups ON amount BETWEEN min_val AND max_val
GROUP BY min_val, max_val

我还将您的 CASE 语句转换为数据透视表。这将对匹配的计数/数量集进行分组(即,如果有两个数量为 100 的 'aa' 行,将返回为数量 = 100,计数 = 2),这就是为什么我将两者相乘得到正确的总和。

【讨论】:

以上是关于PLSQL:子查询之外的条件的主要内容,如果未能解决你的问题,请参考以下文章

PLSQL:如果变量 IN 子查询

plsql子查询查出多行怎么修改

MySQL数据库学习笔记----MySQL多表查询之外键表连接子查询索引

数据库学习笔记6--MySQL多表查询之外键表连接子查询索引

PLSQL 的简单命令之四

ORA-02292: 违反完整约束条件 处理