Oracle SQL Альтернатива UNION - PullRequest
0 голосов
/ 08 мая 2020

Я использую ORACLE SQL (11g), допустим, у нас есть таблица с именем TRANSMISSIONS, в которой есть поле, содержащее 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 предложения.

Is есть ли способ лучше сделать это?

Ответы [ 4 ]

3 голосов
/ 08 мая 2020

Вы ищите совокупные суммы. Я думаю, что я бы go для:

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, предполагая, что это минимально возможное значение, но код может отрегулируйте, если это не так.

3 голосов
/ 08 мая 2020

Вы можете попробовать следующее:

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

Тем не менее, вы можете изменить ограничения.

2 голосов
/ 08 мая 2020

Предполагая, что вы сохраните максимальные размеры и соответствующие метки в небольшой таблице (например, показанной ниже), и у вас будет строка 'ALL' для всех файлов (даже тех, которые больше самого большого размера в вашем списке максимальных размеры - включая файлы с размером файла 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, не подходит для столбца name; я добавил подчеркивание в конце.)

0 голосов
/ 08 мая 2020

Мы можем записать оператор 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...