Как выбрать все строки, в которых идентификатор элемента не связан с указанным идентификатором c в ассоциативной таблице - PullRequest
0 голосов
/ 08 февраля 2020

У меня есть две таблицы, которые мы назовем product и customer.

У меня также есть ассоциативная таблица product_customer, объединяющая идентификаторы продуктов и клиентов во множество ко многим отношения.

Например:

 PRODUCT          CUSTOMER             JOIN TABLE
id | name        id | name       product_id | customer_id
----------       ----------      ------------------------
1  | apple       1  | bill       1          | 2
2  | orange      2  | bob        2          | 1
                 3  | ben        2          | 2

Я пытаюсь написать запрос SQL, который выберет все продукты, которые не связаны с конкретным клиентом, например,

  • для клиента 1, запрос будет возвращать только строку orange, поскольку клиент 1 связан с продуктом 2

  • для клиента 2, запрос не будет возвращать строк, так как клиент 2 связан как с продуктом 1, так и 2

  • для клиента 3, запрос вернет все строки, так как клиент 3 не связан ни с одним из продуктов

Любая помощь будет принята с благодарностью!

Не уверен, что конкретный бренд SQL важно, но я использую базу данных H2, но использую встроенную аннотацию весенней загрузки @Query.

Ответы [ 3 ]

1 голос
/ 08 февраля 2020

Используйте cross join для генерации всех комбинаций клиентов и продуктов. Затем используйте left join / not exists или операцию на основе набора, чтобы отфильтровать те, которые существуют:

select c.name, p.name
from customer c cross join
     product p left join
     jointable jt
     on c.id = jt.customer_id and p.id = jt.product_id
where jt.customer_id is null;
0 голосов
/ 08 февраля 2020

Я бы подошел к этой проблеме, сначала сгенерировав всех возможных клиентов-продуктов путем декартовой связи между продуктами и клиентами. (Блок prod_customer)

После этого я бы сравнил комбинации (prod, customer) в join_table и показать только недостающие, используя левое соединение, как показано ниже

with prod_customer
  as (select p.id as p_id,c.id as c_id,c.name as cust_name,p.name as prod_name
        from products p
        join customers c
          on 1=1
      )
   select pc.c_id,pc.cust_name,pc.prod_name,pc_pid
     from prod_customer pc
left join join_table jt
       on pc.p_id=jt.product_id
      and pc.c_id=jt.customer_id
    where jt.customer_id is null 
0 голосов
/ 08 февраля 2020

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

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

with PRODUCT as (select 1 as ID, 'Apple'as name
                  union all 
                  select 2 as ID, 'Orange'as name), 
customer as (select 1 as ID, 'bill' as name union all 
             select 2 as ID, 'bob' as name union all 
             select 3 as ID, 'ben' as name ), 
jointbl as (select 1 as Product_id, 2 as Customer_id union all  
            select 2 as Product_id, 1 as Customer_id union all  
            select 2 as Product_id, 2 as Customer_id)

select distinct  c.id as Customer_id ,c.name as Customer_name, p.name as Fruit_name, 
  p.ID as Product_id  
 from customer c 
left join jointbl j on c.ID = j.Customer_id 
cross join PRODUCT p  
where isnull(p.ID,-1) <> isnull(j.Product_id,-1) and not exists (select 1 from PRODUCT  p1 
join jointbl j1  on p1.ID = j1.Product_id 
 where p.ID = p1.id and j1.Customer_id = c.ID)
order by 1

Вывод:

enter image description here

...