#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;
Как это работает?
- Я извлекаю все филиалы, расположенные в городах небольших банковских корпораций. Таким образом, я получаю сами филиалы Small Bank Corporation плюс филиалы всех других компаний в тех же городах.
- Затем я агрегирую по компаниям, чтобы получить количество филиалов компаний в этих городах. Мне нужно
COUNT(DISTINCT city)
здесь, потому что у компании может быть два или более офисов в одном городе. - Я упорядочиваю компании по количеству совпадающих городов и сохраняю только те компании, у которых максимальное количество (т. Е. Все города). Это, конечно, относится к небольшой банковской корпорации и, возможно, к другим компаниям — компаниям, которые мы ищем.
Комментарии:
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)
в обоих местах.