Запрос для отображения списка клиентов только с одним конкретным продуктом

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

Вот как сохраняются данные:

Я хочу, чтобы результат показывал ТОЛЬКО Сару и Шелли.

но лучшее, что я могу придумать, — это Джейн, Сара и Шелли. Как мне отфильтровать результаты Джейн?

SELECT      A.customer_name
FROM        A.Table1
INNER JOIN  B.Table2
ON          A.acct_number = B.acct_number
WHERE       B.account_type = 'savings';

Добро пожаловать в Stack Overflow. Благодарим вас за предоставление примеров данных, однако из-за скриншотов сложнее отвечать на вопросы. Пожалуйста, предоставьте образец данных в виде текста. Вы можете использовать форматирование таблицы, которое можно найти на вкладке «Справка» редактора. А еще лучше создать образец базы данных на dbfiddle, чтобы другие могли его использовать.

Schwern 06.09.2024 01:18

А как насчет клиента, у которого есть 2 сберегательных счета (и больше ничего)?

jarlh 06.09.2024 10:05

Также добавьте тег для используемой базы данных. Как вы видите ниже, разные продукты имеют несколько разную функциональность.

jarlh 06.09.2024 10:13
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
3
50
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете сгруппировать по имени, чтобы получить количество учетных записей каждого, а затем отфильтровать это по людям, у которых только одна учетная запись, используя наличие (это похоже на where, но фильтруется после группировки).

Затем мы также можем проверить, какой тип учетной записи у них есть. Обычно вы не можете сделать это с помощью group by, потому что каждая группа будет иметь несколько строк разных типов. Но поскольку мы ищем людей всего с одной строкой, мы можем использовать max(type), поскольку в каждой группе только один тип, он всегда будет возвращать только type.

(Большинство баз данных также имеют способ объединить все значения в группу, и это может быть лучшим выбором, чем max, но они нестандартны.)

select name
from customers c
left join accounts a on c.account_num = a.account_num
group by name
having count(*) = 1 and max(type) = 'savings'

Демонстрация.

Или вы можете использовать предложение совокупного фильтра, чтобы учитывать только их несберегательные счета. Большинство баз данных поддерживают его, но не MySQL.

select name
from customers c
left join accounts a on c.account_num = a.account_num
group by name
having count(*) filter(where type <> 'savings') = 0

А для более общего случая (например, проверка «кредита», который не является ни максимальным, ни минимальным значением символа) вы можете использовать что-то вроде max(CASE WHEN type='loan' THEN 1 ELSE 0 END) = 1

Fred 06.09.2024 02:01

@JonasMetzler Вероятно, лучше, если база данных поддерживает это. MySQL нет.

Schwern 06.09.2024 07:02

@JonasMetzler Я не знаю, какую базу данных они используют, поэтому я выбрал самое простое и совместимое. Вы можете написать свой собственный ответ, если хотите охватить больше вариантов.

Schwern 06.09.2024 07:08

Я бы использовал условную агрегацию в предложении HAVING и просто подсчитывал все вхождения с экономией типа <>. Если ни один не появится, этот клиент будет выбран.

«Стандартный» способ поддержки всех СУБД.

HAVING COUNT(CASE WHEN type <> 'savings' THEN 1 END) = 0;

Все больше и больше СУБД предоставляют предложение FILTER, они более читабельны:

HAVING COUNT(*) FILTER(WHERE type <> 'savings') = 0;

MySQL предоставляет самый короткий синтаксис, там можно написать SUM(boolean expression):

HAVING SUM(type <> 'savings') = 0;

Таким образом, весь запрос будет:

SELECT 
  c.name
FROM 
  customers c
  LEFT JOIN accounts a --or INNER JOIN, check what you need
    ON c.account_num = a.account_num
GROUP BY 
  c.name
HAVING 
  COUNT(CASE WHEN a.type <> 'savings' THEN 1 END) = 0;
  --replace by FILTER clause if your RDBMS supports it

Вот демо-версия Postgres, которая поддерживает как опцию FILTER, так и опцию CASE.

Другой подход, используйте EXCEPT:

SELECT name FROM customers WHERE type = 'savings'
EXCEPT
SELECT name FROM customers WHERE type <> 'savings'

Однако вернет клиента, имеющего 2 сберегательных счета (и ничего больше).

Другие вопросы по теме