Каким будет SQL-запрос для следующего?

#sql #oracle #oracle18c

#sql #Oracle #oracle18c

Вопрос:

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

Запрос: Предположим, что компании могут быть расположены в нескольких городах. Найдите все компании, расположенные в каждом городе, в котором находится «Корпорация малого банка».

Я попытался :
select cname from company c where (select city from company c2 where c2.cname='Small Bank Corporation' MINUS select city from company where cname=c.cname) is null;

и несколько подобных вариантов, но это вообще не работает. Моя идея состоит в том, чтобы сгенерировать набор A и набор B. Набор B — это все города, в которых находится компания Small bank. Скажем, Set B = {Мумбаи, Пуна} . Теперь я пытался сгенерировать set A для каждой компании в таблице company. Скажем, для первого цикла cname = ‘FBC’, затем Set A будет содержать все города, в которых находится FBC.
Теперь установите B — Установите A, если эта часть становится нулевой, это означает, что A, по крайней мере, находится во всех городах как SBC, и я пытался напечатать название компании этого набора A. Но по какой-то причине это не работает, и я не могу в этом разобраться.

Ошибка Oracle: однострочный подзапрос возвращает более одной строки.

Есть мысли по этому поводу? Спасибо Вам

Ответ №1:

Прежде всего: модель данных немного неуместна, потому что таблица company не содержит одной строки на компанию. Лучшим именем было company_branch_office бы, например. Мы должны иметь это в виду при написании запроса, потому что запрос может отличаться от того, что он на самом деле делает. (Если вы можете, измените имя таблицы.)

В любом случае, получение компаний, у которых есть филиал в каждом городе, где находится Небольшая банковская корпорация, тоже непростая задача. Самый простой способ, о котором я могу думать, это:

 select company_name
from company
where city in
(
  select city
  from company
  where company_name = 'Small Bank Corporation'
)
group by company_name
order by count(distinct city) desc
fetch first row with ties;
 

Как это работает?

  1. Я извлекаю все филиалы, расположенные в городах небольших банковских корпораций. Таким образом, я получаю сами филиалы Small Bank Corporation плюс филиалы всех других компаний в тех же городах.
  2. Затем я агрегирую по компаниям, чтобы получить количество филиалов компаний в этих городах. Мне нужно COUNT(DISTINCT city) здесь, потому что у компании может быть два или более офисов в одном городе.
  3. Я упорядочиваю компании по количеству совпадающих городов и сохраняю только те компании, у которых максимальное количество (т. Е. Все города). Это, конечно, относится к небольшой банковской корпорации и, возможно, к другим компаниям — компаниям, которые мы ищем.

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

1. Мне потребовалось очень много времени, чтобы понять это, поскольку это сложно для меня; но это блестящее решение использовать предложение ‘IN’, а затем фильтровать полученные результаты с помощью orderby, count и выборки первой строки со связями. Спасибо! Хотя мы не можем добавить «where cname! =’SBC’ » вместе с «city in», поскольку это дает неверные результаты, поскольку результаты зависят от количества SBCcities. В этом случае мы можем просто создать представление как (результат — SBC) !

2. @SpawnN . , , Это хороший — и умный — ответ. Однако это не обязательно сработает, если у вас есть where предложение во внешнем запросе. Этот запрос всегда будет возвращать строки, в которых есть хотя бы один город перекрытия. Эта версия работает, потому что «Корпорация малого банка» гарантированно будет в результирующем наборе, поэтому она будет вверху списка, поэтому есть хотя бы одна строка со словами «все города».

3. Я думаю, это то, что говорил SpawN. Вам нужно select * from (query) where company_name <> 'Small Bank Corporation' исключить SBC из результатов.

Ответ №2:

Вы можете добиться этого, используя EXISTS :

 SELECT * FROM
COMPANY
WHERE 
name != 'Small Bank Corporation'
AND EXISTS
(SELECT 1 FROM 
COMPANY as SBC WHERE 
SBC.name= 'Small Bank Corporation'
AND SBC.city = COMPANY.city)
 

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

1. Я боюсь, что это дает мне неправильные результаты: ( , я даже получаю название компании, которое не является надмножеством городов SBC

2. @SpawN: Да, Neo неправильно истолковал задачу. Запрос выдает вам все компании, у которых есть хотя бы один филиал в каком-либо городе SBC.

Ответ №3:

Ответ Торстена подходит для заданного вами вопроса, но я думаю, что запрос хрупкий. Если у вас есть фильтр во внешнем запросе и «Корпорация малого банка» не включена, то запрос вернет компании с наиболее перекрывающимися городами — даже если не может быть ни одного, который перекрывал бы все.

Я бы выполнил явную проверку, используя HAVING предложение:

 select c.company_name
from company c
where exists (select 1
              from company c2
              where c2.city = c.city and
                    c2.name = 'Small Bank Corporation'
             )
group by c.company_name
having count(*) = (select count(*)
                   from company c2
                   where c2.name = 'Small Bank Corporation'
                  );
 

Обратите COUNT(*) внимание, что при этом используется предположение, что компании не имеют нескольких строк в городе. Если это возможно, то используйте count(distinct city) в обоих местах.