Условно соединяющиеся столы - PullRequest
2 голосов
/ 10 января 2012

Я хочу создать условное соединение с таблицей в моем запросе T-SQL. Таблицы, используемые в этом примере, взяты из базы данных Northwind (только с одной дополнительной таблицей ProductCategories)

Таблица Продукты и категории таблиц имеют отношение «многие ко многим», поэтому таблица ProductCategories входит в картину.

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

Select p.ProductName, Sum(od.Quantity) As Qty
From Products p
    Join OrderDetails od On od.ProductID = p.ProductID
    Join ProductCategories pc On pc.ProductID = p.ProductID
        And pc.CategoryID = @CategoryID
Group By p.ProductName

@ CategoryID - необязательный параметр. Так что, если он не предоставлен, присоединение к таблице ProductCategories не потребуется и запрос должен выглядеть так, как показано ниже

Select p.ProductName, Sum(od.Quantity) As Qty
From Products p
    Join OrderDetails od On od.ProductID = p.ProductID
Group By p.ProductName

Я хочу достичь этого, не повторяя весь запрос с условиями If (как показано ниже)

If @CategoryID Is Null
    Select p.ProductName, Sum(od.Quantity) As Qty
    From Products p
        Join OrderDetails od On od.ProductID = p.ProductID
    Group By p.ProductName
Else
    Select p.ProductName, Sum(od.Quantity) As Qty
    From Products p
        Join OrderDetails od On od.ProductID = p.ProductID
        Join ProductCategories pc On pc.ProductID = p.ProductID
            And pc.CategoryID = @CategoryID
    Group By p.ProductName

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

Есть какие-нибудь решения? Спасибо.

Ответы [ 3 ]

2 голосов
/ 10 января 2012

Попробуйте, если вы будете использовать правильно параметризованный запрос - это не повлияет на производительность, но может привести к увеличению:

Select p.ProductName, Sum(od.Quantity) As Qty
From Products p
    Join OrderDetails od On od.ProductID = p.ProductID
WHERE @CategoryID IS NULL OR EXISTS (SELECT * FROM ProductCategories WHERE CategoryID = @CategoryID AND ProductID = p.ProductID)
Group By p.ProductName

На самом деле

в вашемзапросить, может ли быть несколько строк в ProductCategories для одной строки в OrderDetails - тогда вы получите дубликаты od.Quantity в вашей сумме - это предполагаемое поведение?

0 голосов
/ 10 января 2012

Я полагаю, что вы можете присоединиться к таблицам слева от неявного внутреннего объединения, которое вы делаете.

Во внутреннем объединении он сопоставляет ключ исходной таблицы с каждым экземпляром ключа в целевой таблице.

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

При внешнем объединении будет отображаться исходная строка ДАЖЕ, ЕСЛИ в другой таблице нет подходящей строки. Если он есть, он будет делать то же самое, что и внутреннее соединение, и вы получите строку назад для каждого экземпляра совпадения. Таким образом, вы получаете данные, которые вам нужны, когда они доступны, а не получаете данные, которые недоступны.

Возьмите это как пример

select * from Products

    Left join ProductAndCategory on ProductAndCategory.ProductID = Products.ProductID
    left join Categories on Categories.CategoryID = ProductAndCategory.CategoryID

Где у меня есть простая таблица Product с ProductID и таблицей ProductName a ProductAndCategory с ProductID и CategoryID и таблицей Categories с CategoryID и CategoryName

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

0 голосов
/ 10 января 2012

Я не очень знаком с T-SQL, поэтому не знаю, будет ли это сокращать его, но в mysql вы могли бы сделать что-то вроде

Select p.ProductName, Sum(od.Quantity) As Qty
From Products p
    Join OrderDetails od On od.ProductID = p.ProductID
    Join ProductCategories pc On pc.ProductID = p.ProductID
        And pc.CategoryID = if(@CategoryID is null , pc.CategoryID, @CategoryId)
Group By p.ProductName

Да, и если () все еще остается, но это всего лишь "один запрос", если это то, что вы ищете.

В то же время вы говорите, что смогли динамически генерировать один запрос. Если это так, то читаемость это большая проблема? Если бы ваш сгенерированный запрос был более производительным по сравнению с тем, что я предложил выше, я бы согласился с этим. Это генерируется; вы не будете вручную настраивать / читать результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...