Объединение 3 таблиц с 2 предложениями where, дающими нулевые результаты

#sql-server #join

#sql-server #Присоединиться

Вопрос:

У меня проблема с получением результата из sql-запроса. Мне нужен результат из двух предложений where. Я работаю с SQLServer2014

таблица1: Продукт

 ProductID
1
2
3
4
5
  

таблица 2: Поставщик

 SupplierID
1
2
3
  

table3: Product_Supplier

 ProductSupplierID|ProductID|SupplierID|Reference
1                |1        |1         |Ref001
2                |1        |2         |Ref002
3                |2        |1         |Ref003
4                |3        |2         |Ref004
5                |4        |2         |Ref005
  

Я хочу получить результат, когда я устанавливаю:

где (ProductID<4) и (SupplierID= 2)

Я должен получить в результате: весь продукт под идентификатором продукта 4, связанный с идентификатором поставщика 2, если он не существует в Product_Supplier, я должен получить Reference = Null

 ProductID|SupplierID|Reference
1        |2         |Ref002
2        |2         |Null
3        |2         |Ref004
  

Я запускаю некоторый sql-скрипт, но не могу получить правильный результат

 select a.ProductID, b.SupplierID, C.Reference from Product as a
  left outer join Product_Supplier as c on c.ProductID= a.ProductID
  left outer join Supplier as B on b.SupplierID = c.SupplierID
where a.ProductID<4 and b.SupplierID=2
  

Ответ от Феликса Памиттана:

 SELECT
    t.*,
    ps.Reference
FROM (
    SELECT *
    FROM Product 
    CROSS JOIN Supplier
    WHERE
        ProductID < t.ProductID
        AND SupplierID = t.SupplierID
) t
LEFT JOIN Product_Supplier ps
    ON ps.ProductID = t.ProductID
    AND ps.SupplierID = t.SupplierID
  

В этом скрипте я не могу ввести add runtime код where. Когда я могу установить where в конце sql, конечный пользователь может ввести параметры where.

 SELECT
    t.*,
    ps.Reference
FROM (
    SELECT *
    FROM Product 
    CROSS JOIN Supplier
    --WHERE
    --    ProductID < t.ProductID
    --    AND SupplierID = t.SupplierID
) t
LEFT JOIN Product_Supplier ps
    ON ps.ProductID = t.ProductID
    AND ps.SupplierID = t.SupplierID
where t.ProductID < 4
and t.SupplierID=2
  

Я проверю это последним на реальной базе данных.

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

1. SELECT * FROM Product_Supplier WHERE ProductId < 4 AND SupplierID = 2

2. Проблема в том, что я могу получить вторую строку (2,2, null)

3. Просто поправьте меня, если я ошибаюсь; в Product_Supplier нет кортежей, где ProductID и SupplierID равны 2… Если кортеж отсутствует, он никогда не будет выбран. То есть, когда таблица Product объединяется с Product_Supplier , тогда идентификатор поставщика будет равен null, и аналогично для кортежа с SupplierID=2, тогда ProductID будет равен null. Вашим лучшим выбором может быть цикл For? Но это довольно некрасиво.

4. @JonSick : правильно. Я застрял с этим.

Ответ №1:

Сначала вам нужно получить все комбинации Product s и Supplier s. Сделайте это, выполнив a CROSS JOIN . Наконец, выполните a LEFT JOIN в Product_Supplier таблице:

 SELECT
    t.*,
    ps.Reference
FROM (
    SELECT *
    FROM #Product 
    CROSS JOIN #Supplier
    WHERE
        ProductID < 4
        AND SupplieIrD = 2
) t
LEFT JOIN #Product_Supplier ps
    ON ps.ProductID = t.ProductID
    AND ps.SupplierID = t.SupplieIrD
  

ONLINE DEMO

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

1. Я думаю, что это правильный путь. Могу ли я также установить предложения where в псевдониме t?

2. Что вы имеете в виду? Я помещаю WHERE предложение в CROSS JOIN , чтобы минимизировать его результат, прежде чем выполнять a LEFT JOIN в другой таблице.

Ответ №2:

Проблема b.SupplierID = 2 в критериях. Поскольку b (Supplier) ссылается на c (таблица ссылок), это отрицает левое соединение в b, если запись не существует в c.

Вместо этого вы можете переместить критерий в соединение:

 select a.ProductID, b.SupplierID, C.Reference from Product as a
  join Supplier as B on b.SupplierID = 2 -- moved criterium
  left join Product_Supplier as c on c.ProductID= a.ProductID and c.SupplierID=b.SupplierID   
where a.ProductID<4 
  

Поскольку явные данные supplier не требуются, вы также можете полностью исключить это объединение и вместо этого жестко указать «2» в части выбора (вместе с использованием его в качестве дополнительного критерия в объединении)

 select a.ProductID, 2, C.Reference from Product as a
  left join Product_Supplier as c on c.ProductID= a.ProductID and c.SupplierID=2 -- moved criterium
where a.ProductID<4 
  

Ответ №3:

Попробуйте это:

 SELECT ps.ProductSupplierID, s.SupplierID, ps.Reference
FROM Product_Supplier ps
   LEFT JOIN Product p ON ps.ProductID = p.ProductID
   LEFT JOIN Supplier s ON ps.SupplierID = s.SupplierID
WHERE p.ProductID < 4
   AND s.SupplierID = 2
  

Возможно, вам удастся избежать INNER JOINs объединения вместо ОБЪЕДИНЕНИЯ СЛЕВА, но попробуйте LEFT JOINS первое, и если это сработает, попробуйте INNER JOINs просто посмотреть. Вы не получаете свои Null значения из-за вашего JOINs I believe.

Редактирование приведенного выше запроса должно дать вам правильные результаты. Вам нужно проверить и убедиться, что у вас действительно есть запись, которая попадает в вашу категорию, которую, по вашему мнению, вы делаете. Начните с удаления части WHERE предложения построчно. Когда вы удаляете строку предложения и появляется запись, вы знаете, что нашли ошибку.

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

1. Это только моя проблема, я хочу получить нулевые значения.

2. @Ravaut123 Не сработал ли приведенный выше запрос? Этот запрос должен выдать вам ваши нулевые значения.

3. Нет, я только меняю p.ProductID> 4 на p.ProductID < 4. Но никаких нулевых значений

4. @Ravaut123 О, вау. Я не могу поверить, что не видел, что вы написали почти точный запрос, который я вам дал. Мой плохой! Позвольте мне попробовать что-нибудь еще очень быстро

5. @Ravaut123 На самом деле, вам нужно использовать запрос, который я написал выше. В вашем запросе вы сначала выбираете из таблицы Product. Сначала вам нужно выбрать из таблицы Product_Supplier, а затем ПРИСОЕДИНИТЬСЯ к другим таблицам.