Oracle SQL UNION 替代

Oracle SQL UNION alternative

我正在使用 ORACLE SQL (11g),假设我们有一个名为 TRANSMISSIONS 的 table,它的字段包含 file sizes

我想针对不同的文件大小 partitions 执行各种聚合函数。但是我希望分区是累积的。 因此 10 KB 文件将同时位于 <=500000 bytes 分区和 <=2000000000 分区中。 因此,如果我有 5 个文件 <=500000 和 5 个文件 > 50000 && < 2000000000 那么我将得到以下结果:

   label       | number
---------------|-------
<=500000       | 5
<=2000000000   | 10

所以基本上最初的方法是像这样进行联合:

SELECT '<=500000' as label,
       COUNT(1) AS numberFiles,
       round(avg(tra.TRA_SIZE)) as averageSize,
       sum(tra.TRA_SIZE) as totalSize
FROM TRANSMISSION tra
where tra.TRA_SIZE <= 500000

UNION

SELECT '<=2000000000' as label,
       COUNT(1) AS numberFiles,
       round(avg(tra.TRA_SIZE)) as averageSize,
       sum(tra.TRA_SIZE) as totalSize
FROM TRANSMISSION tra
where tra.TRA_SIZE <= 2000000000;

然而,如果我有几个这样的 partitions,我这样做会导致一个巨大的无法维护的查询,其中唯一改变的基本上是 labelwhere 子句.

有更好的方法吗?

我们可以把CASE语句写成

SELECT CASE WHEN tra_size <= 500000 THEN '<=500000' 
                      WHEN tra_size <= 2000000000 THEN  '<=2000000000'
                      END AS label,
COUNT(1) AS numberfiles,
round(AVG(tra_size)) AS averagesize,
SUM(tra_size) AS totalsize
FROM TRANSMISSION
GROUP BY CASE WHEN tra_size <= 500000 THEN '<=500000' 
                      WHEN tra_size <= 2000000000 THEN  '<=2000000000'
                      END;

您正在寻找累计金额。我想我会选择:

SELECT l.label, 
       COUNT(*) AS numberfiles,
       ROUND(AVG(t.tra_size), 2) AS averagesize,
       SUM(t.tra_size) AS totalsize
FROM #TRANSMISSION t JOIN
     (SELECT 1 as ord, '<=500000' as label, 0 as lo, 500000 as hi FROM DUAL UNION ALL
      SELECT 2 as ord, '<=2000000000' as label, 0 as lo, 2000000000 as hi FROM DUAL
     ) l
     ON t.tra_size BETWEEN l.lo AND l.hi
GROUP BY l.label, l.ord
ORDER BY l.ord;

这使您可以完全灵活地选择所需的范围——我从 0 开始,假设这是可能的最小值,但如果不是这种情况,则可以调整代码。

你可以试试这个:

WITH limits(n) AS (
SELECT 500000 FROM DUAL
UNION ALL 
SELECT n+500000 FROM limits 
WHERE n < 10000000
)
SELECT
   '<=' || to_char(n,'00000000') AS label,
   round(avg(tra.TRA_SIZE)) as averageSize,
   sum(tra.TRA_SIZE) as totalSize
FROM TRANSMISSION tra
CROSS JOIN limits
WHERE tra.TRA_SIZE <= n
GROUP BY n
ORDER BY n

不过,您可能想要更改限制。

假设您将最大大小和相应的标签存储在一个小的 table 中(如下图所示),并且所有文件(甚至那些大于最大大小列表中的最大大小 - 包括文件大小为 null 的文件),你可以这样做:

with
  sample_file_data (file_id, file_size) as (
    select 1001,   10000 from dual union all
    select 1083,   50000 from dual union all
    select 1130,  340000 from dual union all
    select 2323, 1435832 from dual union all
    select 3200,    null from dual union all
    select 1039,   34200 from dual union all
    select 4832, 4320933 from dual
  )
, groups (label, max_size) as (
    select '<=   50000',   50000 from dual union all
    select '<=  200000',  200000 from dual union all
    select '<= 1000000', 1000000 from dual union all
    select 'ALL'       ,    null from dual
  )
-- end of simulated input data; query begins BELOW THIS LINE
select label, count(*) as number_
from   sample_file_data join groups on file_size <= max_size or max_size is null
group  by max_size, label
order  by max_size
;

LABEL         NUMBER_
---------- ----------
<=   50000          3
<=  200000          3
<= 1000000          4
ALL                 7

(注意 - NUMBER 是一个 Oracle 关键字,不适合用作列名;我在末尾添加了下划线。)