2012-05-18 2 views
0

У меня есть 3 стола: Products,, Properties. Мне нужно получить все продукты, которые не имеют «Property B». Таблицы:Получить записи, которые не имеют связи

# Products   # Join table     # Properties 
+----+-----------+ +------------+-------------+ +-------------+---------------+ 
| id | name  | | product_id | property_id | | property_id | property_name | 
+----+-----------+ +------------+-------------+ +-------------+---------------+ 
| 1 | Product 1 | |   1 |   1 | |   1 | Propeprty A | 
| 2 | Product 2 | |   1 |   2 | |   2 | Propeprty B | 
| 3 | Product 3 | |   2 |   1 | +-------------+---------------+ 
+----+-----------+ |   2 |   2 | 
        |   3 |   1 | 
        +------------+-------------+ 

В данном случае Я ожидаю, что продукт 3 должен быть возвращен.

Возможно ли получить все необходимые продукты в пределах одного запроса одного db? Какой наименьший запрос можно достичь?

Отредактировано. Запросы с подзапросами рассмотрены bad.

ответ

0

Похоже, вы хотите OUTER JOIN, а затем ИНЕКЕ, чтобы вернуть не-соответствие свойств. Это проверялось, но:

SELECT Products.* FROM 
Products RIGHT OUTER JOIN Join_Table 
    ON Products.ID = Join_Table.Product_ID 
    AND Join_Table.Property_ID = 2 
WHERE Products.ID IS NULL 
+0

Это просто «ol» не будет работать. Продукты.Идентификатор никогда не будет NULL - так как это таблица, в которой находится предложение FROM, и нет НИКАКИХ ссылок RIGHT/FULL. –

+0

Марк, ты прав. Ответ Lester имеет опечатку: в строке 5 она должна быть 'Join_Table.Property_ID' вместо' Products.ID'. – gmile

+0

Да, я предполагаю, что я имел в виду ПРАВИЛЬНОЕ ПРИСОЕДИНЕНИЕ, конечно, но мне лучше перешагнуть его перед редактированием. – LesterDove

1
select * from Products P where not exists (select * from ProductProperties 
inner join Properties on ProductProperties .property_id = Properties property_id 
where P.product_id = ProductProperties.product_id and property_name = 'Propeprty B') -- *or whatever* 
+0

Я предполагаю, что это не будет работать. Этот запрос возвращает пустой набор результатов. –

+0

Благодарим вас, но я подразумевал, что не нужно выполнять суб-запрос. – gmile

+0

Я просто отредактировал свой ответ. Я думаю, что сейчас это правильно. –

0
SELECT Products.ProductID, Products.Name, Properties.property_name FROM Products 
INNER JOIN ProductProperties ON Products.product_ID = ProductProperties.product_ID 
INNER JOIN Properties ON ProductProperties.Property_ID = Properties.Property_ID 
WHERE Properties.Property_ID <> 2 
+0

Это вернет свойства non-PropertyB для Продукта, который * имеет * свойство PropertyB. –

+0

Вы правы, я набирал способ быстро. Вы должны «LEFT OUTER JOIN Properties» на ProductProperties.Property_ID = Properties.Property_ID' – Phoenix

-1

Да (исправлено, чтобы удалить подводные лодки),

Select * from 
    Products pr 
    left join jointable jt on pr.id = jt.product_id 
    join properties pr on jt.property_id = pr.property_id and pr.property_name = 'Property B' 
where jt.product_id is null 
+0

Спасибо, ответили, но я подразумевал также не выполнять суб-запрос. – gmile

+0

Я думаю, что ваш <> в where должен быть =. В противном случае вы возвращаете продукты, которые * делают *, имеют PropertyB. –

1

Мне нужно, чтобы все продукты, которые не имеют "Property B"

Inverse проблему. Найдите сPropertyB, затем отмените его.

Старт со всеми PropertyB свойствами:

SELECT 
    Property_Id 
FROM Properties 
WHERE 
    Property_Name = 'Property B' 

Затем найти ProductId s, что сделать имеют те Property_Id S:

SELECT 
    ProductId 
FROM ProductProperties 
JOIN (
    --1st query 
    SELECT 
     Property_Id 
    FROM Properties 
    WHERE 
     Property_Name = 'Property B' 
) as PropertyB ON 
    ProductProperties.Property_Id = PropertyB.Property_Id 

Затем найти все Product S не в этом наборе:

SELECT 
    ProductId 
FROM Product 
LEFT OUTER JOIN (
    --2nd query 
    SELECT 
     ProductId 
    FROM ProductProperties 
    JOIN (
     --1st query 
     SELECT 
      Property_Id 
     FROM Properties 
     WHERE 
      Property_Name = 'Property B' 
    ) as PropertyB ON 
     ProductProperties.Property_Id = PropertyB.Property_Id 
) as ProductsWithPropertyB ON 
    Products.ProductId = ProductsWithPropertyB.ProductId 
WHERE 
    ProductsWithPropertyB.ProductId IS NULL 

тогда, вы можете упростить немного:

SELECT 
    ProductId 
FROM Product 
LEFT OUTER JOIN (
    SELECT 
     ProductId 
    FROM ProductProperties 
    JOIN Properties ON 
     ProductProperties.PropertyId = Properties.PropertyId 
    WHERE 
     Properties.Name = 'Property B' 
) as ProductsWithPropertyB ON 
    Products.ProductId = ProductsWithPropertyB.ProductId 
WHERE 
    ProductsWithPropertyB.ProductId IS NULL 

Или, если вы предпочитаете IN пункты (сервер, вероятно, не заботится):

SELECT 
    ProductId 
FROM Products 
WHERE 
    ProductId NOT IN (
      SELECT ProductId FROM ProductProperties WHERE PropertyId IN (
       SELECT PropertyId FROM Properties WHERE PropertyName = 'Property B' 
     ) 
    ) 
+0

Я сделал это изначально, но я бы хотел избежать использования суб-запросов для повышения эффективности. – gmile

+1

У вас есть 3 стола с информацией. Вы не получите более эффективной, чем 3-х табличное соединение (или эквивалентные предложения IN). То, что вы хотите избежать, - это * коррелированные * подзапросы (которые запускаются один раз для каждой строки набора результатов), а не подзапросы. –

+0

Благодарим вас за помощь, Марк. Теперь я буду определенно отличать коррелированные подзапросы и другие. Тем не менее, похоже, что @LesterDove отлично работает для меня – gmile

Смежные вопросы