Суммируйте уникальную комбинацию значений полей, найденных в таблице - PullRequest
0 голосов
/ 14 декабря 2018

Как суммировать, сколько записей возвращено из всех комбинаций 2 полей, где каждое поле имеет 3 возможных значения (Y, N, NULL)?

Целью является таблицакак ниже и запрос, чтобы быстро восстановить его, чтобы мы могли проверить усилия по очистке.(т.е. ограниченный И явно не конфиденциальный является недействительным статусом, эти записи должны быть исследованы).Важно знать, какие комбинации возвращают ноль записей.Отсутствие всех комбинаций, представленных в примере, является упущением (и демонстрирует, почему поиск не ручного решения является хорошей идеей!).

Я знаю, как получить каждую строку таблицы результатов отдельноно не за один раз.Исходная БД доступна только для чтения, поэтому я не могу создавать представления или новые таблицы.Я использую Dbeaver для своего анализа.

SELECT x.*,x.ROWID FROM table.PROJECT x
WHERE CONFIDENTIAL = 'Y'

затем

SELECT x.*,x.ROWID FROM table.PROJECT x
WHERE CONFIDENTIAL = 'Y' AND RESTRICTED = NULL

... и т. Д.

Таблица желаемых результатов (не нужно иметь 'Описание', это только для контекста):

+------------+--------------+-------------+--------------------------------------------------+
| RESTRICTED | CONFIDENTIAL | Num records |                   Description                    |
+------------+--------------+-------------+--------------------------------------------------+
| {any}      | {any}        |         586 | any status, i.e. "all records"                   |
|            |              |             |                                                  |
| Y          | {any}        |         191 | Restricted, assumed not confidential             |
| Y          | N            |         184 | Restricted, not confidential                     |
| Y          | Y            |           7 | Restricted, is confidential                      |
| Y          | NULL         |           0 | Restricted, assumed not confidential             |
|            |              |             |                                                  |
| N          | {any}        |         395 | Not restricted, any confidential                 |
| N          | N            |         329 | Not restricted, not confidential                 |
| N          | Y            |           7 | Not restricted, is confidential                  |
| N          | NULL         |           0 | Not restricted, assumed not confidential         |
|            |              |             |                                                  |
| {any}      | N            |         513 | Assumed not restricted, not confidential         |
| {any}      | Y            |           7 | Assumed not restricted, is confidential          |
| {any}      | NULL         |          66 | Assumed not restricted, assumed not confidential |
|            |              |             |                                                  |
| NULL       | {any}        |           0 | Assumed not restricted, assumed not confidential |
+------------+--------------+-------------+--------------------------------------------------+

Ответы [ 4 ]

0 голосов
/ 14 декабря 2018

Используйте CUBE в группировке:

Установка Oracle :

CREATE TABLE project ( restricted, confidential ) AS
  SELECT 'Y',  'Y'  FROM DUAL CONNECT BY LEVEL <=   7 UNION ALL
  SELECT 'Y',  'N'  FROM DUAL CONNECT BY LEVEL <= 184 UNION ALL
  SELECT 'Y',  NULL FROM DUAL WHERE 1 = 0             UNION ALL
  SELECT 'N',  'Y'  FROM DUAL CONNECT BY LEVEL <=   7 UNION ALL
  SELECT 'N',  'N'  FROM DUAL CONNECT BY LEVEL <= 329 UNION ALL
  SELECT 'N',  NULL FROM DUAL CONNECT BY LEVEL <=  59 UNION ALL
  SELECT NULL, 'Y'  FROM DUAL CONNECT BY LEVEL <=   1 UNION ALL
  SELECT NULL, 'N'  FROM DUAL CONNECT BY LEVEL <=   2 UNION ALL
  SELECT NULL, NULL FROM DUAL WHERE 1 = 0;

Запрос :

SELECT CASE GROUPING( restricted )
       WHEN 1 THEN 'any'
       ELSE restricted
       END AS restricted,
       CASE GROUPING( confidential )
       WHEN 1 THEN 'any'
       ELSE confidential
       END AS confidential, COUNT(*)
FROM   project
GROUP BY CUBE( restricted, confidential )
ORDER BY 1 NULLS FIRST, 2 NULLS FIRST;

Вывод :

RESTRICTED  CONFIDENTIAL    COUNT(*)
----------  ------------    --------
 -          N               2
 -          Y               1
 -          any             3
N            -              59
N           N               329
N           Y               7
N           any             395
Y           N               184
Y           Y               7
Y           any             191
any          -              59
any         N               515
any         Y               15
any         any             589

Запрос 2 : Получить все комбинации:

WITH options ( value ) AS (
  SELECT 'Y' FROM DUAL UNION ALL
  SELECT 'N' FROM DUAL UNION ALL
  SELECT NULL FROM DUAL
)
SELECT CASE GROUPING( r.value )
       WHEN 1 THEN 'any'
       ELSE r.value
       END AS restricted,
       CASE GROUPING( c.value )
       WHEN 1 THEN 'any'
       ELSE c.value
       END AS confidential,
       COUNT( p.n )
FROM   options r
       CROSS JOIN options c
       LEFT OUTER JOIN ( SELECT p.*, 1 AS n FROM project p ) p
       ON     ( p.restricted   = r.value OR ( p.restricted   IS NULL AND r.value IS NULL ) )
          AND ( p.confidential = c.value OR ( p.confidential IS NULL AND c.value IS NULL ) )
GROUP BY CUBE( r.value, c.value )
ORDER BY 1 NULLS FIRST, 2 NULLS FIRST;

Вывод :

RESTRICTED  CONFIDENTIAL    COUNT(P.N)
----------  ------------    ----------
 -           -              0
 -          N               2
 -          Y               1
 -          any             3
N            -              59
N           N               329
N           Y               7
N           any             395
Y            -              0
Y           N               184
Y           Y               7
Y           any             191
any          -              59
any         N               515
any         Y               15
any         any             589
0 голосов
/ 14 декабря 2018

Используйте cross join для генерации строк, а затем left join и group by для вычисления количества:

with vals as (
      select 'Y' as val from dual union all
      select 'N' as val from dual union all
      select NULL as val from dual
     )
select vc.val as confidential, vr.val as restricted,
       count(p.rowid)
from vals vc cross join
     vals vr left join
     table p
     on (p.confidential = vc.val or p.confidential is null and vc.val is null) and
        (p.restricted = vr.val or p.restricted is null and vr.val is null)
group by vc.val, vr.val;
0 голосов
/ 14 декабря 2018

Специально для этого сценария в Oracle DB имеется инструмент.
Это операция CUBE предложения GROUP BY.Мы можем использовать его здесь с помощью функции GROUPING, чтобы различать значение raw NULL и значение NULL, представляющее сводку.(Запрос был бы намного проще, если бы столбцы restricted и confidential не были бы обнуляемыми.)

Это выглядит так:

SELECT DECODE(GROUPING(t.restricted), 1, '{any}', t.restricted) AS restricted,
       DECODE(GROUPING(t.confidential), 1, '{any}', t.confidential) AS confidential,
       COUNT(*)
  FROM project t
 GROUP BY CUBE(t.restricted, t.confidential);

Некоторое объяснение:
Использование CUBE изменяет поведение GROUP BY, чтобы не только выполнять агрегации для групп, определенных по заданным столбцам, но также и создавать сводные группы (в основном путем исключения всех комбинаций столбцов из критериев группировки, включая исключение всех, для итоговой сводки).
Группам сводок будет присвоено значение NULL в столбцах, исключенных из сводки.Если этот столбец может иметь значение NULL, то БД Oracle сможет различать обычную группу со значением NULL и сводную группу.Вы можете получить доступ к этой информации, используя функцию GROUPING, которая вернет 1, если это сводная группа для столбца, переданного этой функции, и 0 в противном случае.

Редактировать:
Важное замечание: запрос не будет (так же, как с обычным GROUP BY) возвращать все комбинации restricted и confidential, только те, которые фактически встречаются в данных (и сводках), поэтому производить их (с нулем)считать), вам необходимо настроить запрос.
Вы перечислили некоторые из таких случаев, например:

+------------+--------------+-------------+--------------------------------------------------+
| RESTRICTED | CONFIDENTIAL | Num records |                   Description                    |
+------------+--------------+-------------+--------------------------------------------------+
| Y          | NULL         |           0 | Restricted, assumed not confidential             |
| N          | NULL         |           0 | Not restricted, assumed not confidential         |
| NULL       | {any}        |           0 | Assumed not restricted, assumed not confidential |
+------------+--------------+-------------+--------------------------------------------------+

, но не все, например:

+------------+--------------+-------------+
| RESTRICTED | CONFIDENTIAL | Num records |
+------------+--------------+-------------+
| NULL       | N            |           0 |
| NULL       | Y            |           0 |
| NULL       | NULL         |           0 |
+------------+--------------+-------------+

Редактировать 2:
Чтобы покрыть нулевые значения в результате, вы можете попробовать что-то вроде этого (обратите внимание SUM на пользовательский столбец, заменяющий COUNT строк):

WITH v AS (
  SELECT 'Y' AS val FROM DUAL UNION ALL
  SELECT 'N' AS val FROM DUAL UNION ALL
  SELECT NULL AS val FROM DUAL
),
s AS (
  SELECT id, restricted, confidential, 1 AS cnt
    FROM project
  UNION ALL
  SELECT NULL, r.val, c.val, 0
    FROM v r
   CROSS JOIN v c
)
SELECT DECODE(GROUPING(s.restricted), 1, '{any}', s.restricted) AS restricted, 
       DECODE(GROUPING(s.confidential), 1, '{any}', s.confidential) AS confidential, 
       SUM(s.cnt) AS cnt
  FROM s
 GROUP BY CUBE(s.restricted, s.confidential)

Однако в нем будут перечислены все нулевые строки, а не только те, которые вы перечислили, как ожидалось.

0 голосов
/ 14 декабря 2018

Разве обычная агрегация не сделает работу?Например:

SQL> with project (id, confidential, restricted) as
  2    (select 1, 'y', null  from dual union all
  3     select 2, 'n', null  from dual union all
  4     select 3, null, 'y'  from dual union all
  5     select 4, null, null from dual union all
  6     select 5, 'n', 'n'   from dual union all
  7     select 6, 'y', 'y'   from dual union all
  8     select 7, 'y', 'n'   from dual union all
  9     select 8, 'y', 'y'   from dual
 10    )
 11  select restricted, confidential, count(*)
 12  from project
 13  group by restricted, confidential;

R C   COUNT(*)
- - ----------
             1
y y          2
  y          1
n y          1
  n          1
y            1
n n          1

7 rows selected.

SQL>
...