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
,我这样做会导致一个巨大的无法维护的查询,其中唯一改变的基本上是 label
和 where
子句.
有更好的方法吗?
我们可以把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 关键字,不适合用作列名;我在末尾添加了下划线。)
我正在使用 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
,我这样做会导致一个巨大的无法维护的查询,其中唯一改变的基本上是 label
和 where
子句.
有更好的方法吗?
我们可以把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 关键字,不适合用作列名;我在末尾添加了下划线。)