Попытка найти элегантный способ фильтрации запроса, используя BITAND
, где значения and
ed предоставляются параметром с несколькими значениями.
Данные тестирования:
WITH
patient as
(
select 1 patient_id, 'foo' patient_name from dual
union all
select 2 patient_id, 'bar' patient_name from dual
union all
select 3 patient_id, 'baz' patient_name from dual
union all
select 4 patient_id, 'zoo' patient_name from dual
)
,
-- each organ is a power of 2
organ as
(
select 2 organ_id, 'Lung' organ_name from dual
union all
select 4 organ_id, 'Pancreas' organ_name from dual
union all
select 8 organ_id, 'Liver' organ_name from dual
union all
select 16 organ_id, 'Kidney' organ_name from dual
)
,
patient_organ as
(
-- patient with a multi-organ transplant
select 1 patient_id, 4 organ_id from dual
union all
select 1 patient_id, 16 organ_id from dual
union all
-- patient with a single-organ transplant
select 2 patient_id, 4 organ_id from dual
union all
-- patient with a multi-organ transplant
select 3 patient_id, 8 organ_id from dual
union all
select 3 patient_id, 16 organ_id from dual
union all
-- patient with a single-organ transplant
select 4 patient_id, 2 organ_id from dual
)
Этот запрос:
select p.patient_id, p.patient_name
,po.bits,po.organs
from patient p
inner join (
SELECT patient_id, sum(organ_id) AS BITS
,listagg(organ, '; ') within group (order by organ_id) ORGANS
FROM (
SELECT patient_id, po.organ_id, o.organ_name || ' [' || o.organ_id || ']' organ
FROM patient_organ po
INNER JOIN organ o ON po.organ_id = o.organ_id
)
GROUP BY patient_id
) po on p.patient_id=po.patient_id
Генерирует требуемый набор данных;отображаются несколько органов (например, Pancreas [4]; Kidney [16]
):
PATIENT_ID, PATIENT_NAME, BITS, ORGANS
1 foo 20 Pancreas [4]; Kidney [16]
2 bar 4 Pancreas [4]
3 baz 24 Liver [8]; Kidney [16]
4 zoo 2 Lung [2]
Я хочу иметь возможность указать значение параметра 4,8
и получить следующие результаты:
PATIENT_ID, PATIENT_NAME, BITS, ORGANS
1 foo 20 Pancreas [4]; Kidney [16]
2 bar 4 Pancreas [4]
3 baz 24 Liver [8]; Kidney [16]
ЕслиУ меня есть одно значение (смоделированное с :organ
= 4), я могу использовать BITAND
и получить значения для многих органов:
select p.patient_id, p.patient_name
,po.bits,po.organs
from patient p
inner join (
SELECT patient_id, sum(organ_id) AS BITS
,listagg(organ, '; ') within group (order by organ_id) ORGANS
FROM (
SELECT patient_id, po.organ_id, o.organ_name || ' [' || o.organ_id || ']' organ
FROM patient_organ po
INNER JOIN organ o ON po.organ_id = o.organ_id
)
GROUP BY patient_id
) po on p.patient_id=po.patient_id
WHERE bitand(bits,:organ)=:organ
Сохранение нескольких органов:
PATIENT_ID, PATIENT_NAME, BITS, ORGANS
1 foo 20 Pancreas [4]; Kidney [16]
2 bar 4 Pancreas [4]
Я могу использовать параметр с несколькими значениями (имитируется &organs
= 4,8):
select p.patient_id, p.patient_name
,po.bits,po.organs
from patient p
inner join (
SELECT patient_id, sum(organ_id) AS BITS
,listagg(organ, '; ') within group (order by organ_id) ORGANS
FROM (
SELECT patient_id, po.organ_id, o.organ_name || ' [' || o.organ_id || ']' organ
FROM patient_organ po
INNER JOIN organ o ON po.organ_id = o.organ_id
WHERE po.organ_id IN (&organs)
)
GROUP BY patient_id
) po on p.patient_id=po.patient_id
Но это приводит к потере результатов для многих органов:
PATIENT_ID, PATIENT_NAME, BITS, ORGANS
1 foo 4 Pancreas [4]
2 bar 4 Pancreas [4]
3 baz 8 Liver [8]
В идеалеЯ мог бы использовать функцию BITAND
с оператором IN
, но это синтаксически недопустимо.
Есть ли другой непроцедурный подход?
**edit **
Чтобы уточнить, я ссылаюсь на этот SQL в инструменте отчетности (Crystal Reports).Инструмент позволяет выбрать одно или несколько значений параметров: вы видели organ_name
, но поставляется organ_id
.Кроме того, значения параметра предоставляются в виде массива или строки, разделенной запятыми (сложно сказать, какой), а не суммируются в одно значение (как предлагается в ответе и комментариях).Именно эта архитектура делает это трудным.