Выбор строк на основе значений столбцов

#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
 

db<>скрипка

Комментарии:

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