#oracle
#Oracle
Вопрос:
У меня проблема, когда для одного значения может быть максимум две строки. Я должен выбрать только одну строку на основе значения столбца.Приведенный ниже пример может показать мои данные и то, чего я пытаюсь достичь.
Table Item with the following information
Item Dist_Building Country_Building
I123 B123 B245
I980 B980 B345
I780 B780 B445
Table item_info with the following columns
Item_number Building_Nbr Building_Area Value
I123 B123 District 10
I123 B245 Country 20
I980 B980 District 50
I780 B445 Country 20
Выберите элементы из таблицы элементов и проверьте наличие соответствующей информации о здании, представленной в таблице Item_info. Если для определенного элемента значения присутствуют на уровне округа и страны, тогда выберите ЗНАЧЕНИЕ уровня округа, иначе выберите ЗНАЧЕНИЕ уровня страны (т. Е. Строка с областью округа будет иметь приоритет над страной)
Item_number Value
I123 10
I980 50
I780 20
Ответ №1:
Dist_Building
важны ли здесь , Country_Building
, и Building_Nbr
? Похоже, что это не так, и в этом случае, если вы создадите новую таблицу из item_info
таблицы следующим образом…
select
item_number
, building_nbr
, sum(case when building_area = 'District' then value end) as District_Val
, sum(case when building_area = 'Country' then value end) as Country_Val
, coalesce(District_Val, Country_Val) as Value
into new_item_info
from item_info
group by
1,2
вы должны иметь возможность просто слева присоединить его к item
таблице.
(я не очень хорошо знаком с Oracle SQL, поэтому вам, возможно, придется разбить приведенный выше код на два шага)
Комментарии:
1. Oracle не позволяет вам использовать псевдоним столбца на том же уровне запроса, на котором он был определен, поэтому вы
coalesce
получите «недопустимый идентификатор». Вам нужно будет использовать подзапрос. (Я думаю, что это ограничение SQL, которое верно для всех баз данных, но не на 100% уверен). Вы также не можете использовать номера позиций столбцов вgroup by
предложении; иinto
здесь это не так. Это довольно далеко от использования для вопроса с тегом Oracle.
Ответ №2:
Один из способов сделать это — присоединиться к любому зданию, а затем сохранить то, у которого «более высокое» значение области (которое здесь работает как сортировка «Район» после «Страна»):
select i.item,
max(ii.value) keep (dense_rank last order by ii.building_area) as value
from item i
join item_info ii on ii.item_number = i.item
and (
(ii.building_nbr = i.dist_building and ii.building_area = 'District')
or (ii.building_nbr = i.country_building and ii.building_area = 'Country')
)
group by i.item;
ITEM VALUE
---- ----------
I123 10
I780 20
I980 50
Вы могли бы сделать это более явным с помощью выражения case в предложении order-by, если вы не хотите полагаться на этот порядок сортировки.
Вы также можете выполнить два внешних соединения и использовать coalesce
для выбора нужного:
select i.item,
coalesce(iid.value, iic.value) as value
from item i
left join item_info iid on iid.item_number = i.item
and iid.building_nbr = i.dist_building
and iid.building_area = 'District'
left join item_info iic on iic.item_number = i.item
and iic.building_nbr = i.country_building
and iic.building_area = 'Country';
ITEM VALUE
---- ----------
I123 10
I780 20
I980 50
Комментарии:
1. Привет, как вы предлагаете использовать оператор CASE в предложении order by?
2. @sqlpractice — я имел в виду предложение order-by в
keep
; Я не имел в виду общий порядок для всего оператора. Итак, что-то вродеmax(ii.value) keep (dense_rank last order by case ii.building_area when 'Country' then 1 when 'District' then 2 end) as value
. Это более явно и гибко, но, возможно, излишне в этом запросе.
Ответ №3:
Вы можете достичь своей цели, просто используя подзапросы и функцию NVL:
SELECT Item
, NVL((SELECT VALUE FROM item_info ii
WHERE ii.item_number = i.item
AND ii.Building_Nbr = i.Dist_Building)
,(SELECT VALUE FROM item_info ii
WHERE ii.item_number = i.item
AND ii.Building_Nbr = i.Country_Building)) VALUE
FROM Item i