Выражения регистра в Oracle SQL (конструктор отчетов Pentaho)

Мне нужно получить возраст клиентов и разбить результаты на категории (18–21, 22–35, 36–50 и т. д.).

Использование Pentaho Report Designer, основанного на Oracle.

Я могу получить подсчет определенного возраста, но хочу, чтобы подсчет отражал возрастные диапазоны, а не один возраст. Попытка завершить это с помощью оператора case, но постоянно получаю ошибки.

Минимальное воздействие SQL, новое для Pentaho/Oracle, новое для этого веб-сайта.

--SQL для возраста и количества.

SELECT COUNT(*), "CLIENT_TABLE"."AGE"
FROM "CLIENT_TABLE"
GROUP BY "CLIENT_TABLE"."AGE"
ORDER BY "CLIENT_TABLE"."AGE"

--Это мое выражение CASE.

CASE
    WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
    WHEN "CLIENT_TABLE"."AGE" > 18 AND <= 21 THEN '19 - 21'
    WHEN "CLIENT_TABLE"."AGE" > 21 AND <= 35 THEN '22 - 35'
END AS Age

Я поместил выражение CASE в предложения SELECT и WHERE, но постоянно получаю эти два сообщения об ошибках... "Ключевое слово FROM не найдено там, где ожидается" и "Отсутствует выражение".

Обновленный код выдает ошибку «не группа по выражению».

SELECT COUNT(*),
      (CASE
        WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
        WHEN "CLIENT_TABLE"."AGE" <= 21 THEN '18 - 21'
        WHEN "CLIENT_TABLE"."AGE" <= 35 THEN '22 - 35'
        WHEN "CLIENT_TABLE"."AGE" <= 50 THEN '36 - 50'
        WHEN "CLIENT_TABLE"."AGE" <= 64 THEN '51 - 64'
        WHEN "CLIENT_TABLE"."AGE" >= 65 THEN '65+'
       END) AS AgeRange
FROM "CLIENT_TABLE"
GROUP BY (CASE
        WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
        WHEN "CLIENT_TABLE"."AGE" <= 21 THEN '18 - 21'
        WHEN "CLIENT_TABLE"."AGE" <= 35 THEN '22 - 35'
        WHEN "CLIENT_TABLE"."AGE" <= 50 THEN '36 - 50'
        WHEN "CLIENT_TABLE"."AGE" <= 64 THEN '51 - 64'
        WHEN "CLIENT_TABLE"."AGE" >= 65 THEN '65+'
       END)
ORDER BY "CLIENT_TABLE"."AGE"

person Steve Butka    schedule 14.08.2019    source источник
comment
case выражение не утверждение. Кроме того, вы имеете что-то против 18-летних?   -  person Gordon Linoff    schedule 14.08.2019
comment
обновите свой вопрос и покажите код sql, который вы действительно используете.. не только часть   -  person scaisEdge    schedule 14.08.2019
comment
Если у вас нет данных в одном из диапазонов, например. никто старше 64, вы ожидаете, что вообще не увидите этот диапазон или увидите нулевой счет для этого диапазона?   -  person Alex Poole    schedule 14.08.2019
comment
В идеале «0» для любого диапазона, который не возвращает данных. Кроме того, я должен иметь ELSE в CASE для нулевых значений.   -  person Steve Butka    schedule 14.08.2019


Ответы (3)


Давайте упростим это:

SELECT AGERANGE, COUNT(1) AS CNT FROM
SELECT (CASE
        WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
        WHEN "CLIENT_TABLE"."AGE" <= 21 THEN '18 - 21'
        WHEN "CLIENT_TABLE"."AGE" <= 35 THEN '22 - 35'
        WHEN "CLIENT_TABLE"."AGE" <= 50 THEN '36 - 50'
        WHEN "CLIENT_TABLE"."AGE" <= 64 THEN '51 - 64'
        WHEN "CLIENT_TABLE"."AGE" >= 65 THEN '65+'
       END) AS AgeRange
FROM "CLIENT_TABLE")
GROUP BY AGERANGE
ORDER BY CASE AGERANGE
WHEN 'Under 18' THEN 1 
WHEN '18 - 21' THEN 2
WHEN '22 - 35' THEN 3
WHEN '36 - 50' THEN 4
WHEN '51 - 64' THEN 5
WHEN '65+' THEN 6 
ELSE 7 END;

Ваше здоровье!!

person Popeye    schedule 15.08.2019
comment
Спасибо, Теджаш! Это именно то, что я искал. Я ценю помощь и руководство. - person Steve Butka; 23.08.2019
comment
Если этот ответ решил вашу проблему, пожалуйста, примите его, чтобы он был помечен как решенный. - person Popeye; 23.08.2019

Я думаю, вы хотите:

SELECT COUNT(*),
       (CASE WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
             WHEN "CLIENT_TABLE"."AGE" <= 21 THEN '19 - 21'
             WHEN "CLIENT_TABLE"."AGE" <= 35 THEN '22 - 35'
        END) AS Age
FROM "CLIENT_TABLE"
GROUP BY (CASE WHEN "CLIENT_TABLE"."AGE" < 18 THEN 'Under 18'
               WHEN "CLIENT_TABLE"."AGE" <= 21 THEN '19 - 21'
               WHEN "CLIENT_TABLE"."AGE" <= 35 THEN '22 - 35'
           END)
ORDER BY "CLIENT_TABLE"."AGE"

Заметки:

  • В Oracle вам нужно повторить выражение в GROUP BY.
  • Я упростил логику условий в выражении case. Условия оцениваются по порядку.
  • При этом 18-летние включены - теперь в группу '19 - 21'. Включить их куда-нибудь кажется более правильным, чем помещать их в группу NULL.
person Gordon Linoff    schedule 14.08.2019
comment
Имеет ли это смысл - person scaisEdge; 14.08.2019

Ваш «обновленный код», основанный на ответе @Gordon, получает «ORA-00979: не выражение GROUP BY», потому что вы пытаетесь упорядочить по "CLIENT_TABLE"."AGE", а этого столбца нет в предложении GROUP BY. Вы, вероятно, хотите:

ORDER BY MIN("CLIENT_TABLE"."AGE")

Однако это покажет вам только те диапазоны, в которых есть совпадающие данные. Если вы хотите увидеть все диапазоны, включая нулевые значения, вы можете сгенерировать диапазоны как встроенное представление или CTE и внешнее соединение с вашими реальными данными, например:

WITH "RANGES" ("MIN_AGE", "MAX_AGE", "LABEL") AS (
  SELECT 0, 17, 'Under 18' FROM "DUAL"
  UNION ALL
  SELECT 18, 21, '18 - 21' FROM "DUAL"
  UNION ALL
  SELECT 22, 35, '22 - 35' FROM "DUAL"
  UNION ALL
  SELECT 36, 50, '36 - 50' FROM "DUAL"
  UNION ALL
  SELECT 51, 64, '51 - 64' FROM "DUAL"
  UNION ALL
  SELECT 65, NULL, '65+' FROM "DUAL"
)
SELECT COUNT("CLIENT_TABLE"."AGE"),
       "RANGES"."LABEL" AS AgeRange
FROM "RANGES"
LEFT JOIN "CLIENT_TABLE"
ON "CLIENT_TABLE"."AGE" >= "RANGES"."MIN_AGE"
AND ("RANGES"."MAX_AGE" IS NULL OR "CLIENT_TABLE"."AGE" <= "RANGES"."MAX_AGE")
GROUP BY "RANGES"."MIN_AGE", "RANGES"."LABEL"
ORDER BY "RANGES"."MIN_AGE"

db‹>скрипка

Вы можете сгенерировать метки из минимального/максимального возраста или даже только из минимального возраста (используя лид, чтобы найти максимальный), и есть другие варианты, которые вы можете изучить.

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


У меня должно быть ELSE в CASE для нулевых значений.

COUNT() игнорирует нули, поэтому COUNT("CLIENT_TABLE"."AGE") вернет ноль, если они равны нулю. Вместо этого вам нужно будет подсчитать любой ненулевой столбец в таблице; и потребуется еще одна фиктивная строка в RANGES CTE и измененная логика для включения строк без установленного возраста; например.:

with ranges (min_age, max_age, label) as (
  select 0, 17, 'Under 18' from dual
  union all
  select 18, 21, '18 - 21' from dual
  union all
  select 22, 35, '22 - 35' from dual
  union all
  select 36, 50, '36 - 50' from dual
  union all
  select 51, 64, '51 - 64' from dual
  union all
  select 65, null, '65+' from dual
  union all
  select null, null, 'Unknown' from dual
)
select count(client_table.id), -- count any not-null column from this table
       ranges.label as agerange
from ranges
left join client_table
on ((ranges.min_age is null and client_table.age is null)
  or client_table.age >= ranges.min_age)
and (ranges.max_age is null or client_table.age <= ranges.max_age)
group by ranges.min_age, ranges.label
order by ranges.min_age

db‹>скрипка

person Alex Poole    schedule 14.08.2019