Проблемы SQL Server при совместном использовании ODER BY и DISTINCT

У меня две проблемы, первая проблема - мои два СЧЁТА, с которых я начинаю. GroupID — это строка, которая объединяет продукты (имя_год вместе), один и тот же продукт, но разного размера. Если у меня есть три обзора в tblReview, и все они имеют один и тот же GroupID, я хочу вернуть 3. Моя проблема в том, что если у меня есть три продукта с разными ProductID, но одним и тем же GroupID, и я добавляю три обзора к этому GroupID, я получаю 9 возвратов (3 * 3). Если у меня есть только один продукт с одним и тем же GroupID и тремя отзывами, он работает (1 * 3 = 3 возврата)

Вторая проблема заключается в том, что если у меня есть ORDER BY CASE Price, я должен также добавить GROUP BY Price, и тогда я не получаю эффекта DISTINCT, который мне нужен. И это только для того, чтобы показать продукты, которые имеют уникальный GroupID.

Вот запрос, надеюсь, кто-нибудь может помочь мне с этим.

ALTER PROCEDURE GetFilterdProducts
@CategoryID INT, @ColumnName varchar(100)

AS
SELECT   COUNT(tblReview.GroupID) AS ReviewCount, 
    COUNT(tblComment.GroupID) AS CommentCount, 
    Product.ProductID, 
    Product.Name,
    Product.Year,
    Product.Price,
    Product.BrandID, 
                Product.GroupID, 
                AVG(tblReview.Grade) AS Grade


FROM            Product LEFT JOIN
                         tblComment ON Product.GroupID = tblComment.GroupID LEFT JOIN
                         tblReview ON Product.GroupID = tblReview.GroupID


WHERE        (Product.CategoryID = @CategoryID)

GROUP BY Product.ProductID, Product.BrandID, Product.GroupID, Product.Name, Product.Year, Product.Price

HAVING COUNT(distinct Product.GroupID) = 1

ORDER BY
  CASE 
  WHEN @ColumnName='Name' THEN Name
  WHEN @ColumnName='Year' THEN Year
  WHEN @ColumnName='Price' THEN Price 
  END

Мои таблицы:

Продукт: ProductID, Название, Год, Цена, BrandID, GroupID

tblReview: ReviewID, Описание, Оценка, ProductID, GroupID

tblComment: CommentID, Description, ProductID, GroupID

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


person Nicklas    schedule 14.05.2010    source источник
comment
Было бы полезно, если бы вы могли предоставить схему таблицы и образец ввода-вывода.....   -  person Nitin Midha    schedule 14.05.2010
comment
что произойдет, если вы получите три продукта с одинаковым идентификатором группы и четырьмя отзывами? сколько строк вы ожидаете увидеть тогда?   -  person Chris Bednarski    schedule 14.05.2010
comment
Если у них одинаковый идентификатор группы, я хочу получить 4 возврата по 4 отзывам, даже если они имеют разные идентификаторы продукта.   -  person Nicklas    schedule 14.05.2010


Ответы (2)


Во-первых, поскольку вы присоединяетесь к нескольким столам, в результате вы получите перекрестный продукт всех из них. Затем ваши подсчеты вернут общее количество строк, содержащих данные в этом столбце. Рассмотрим следующий пример:

- PRODUCTS -   -- COMMENTS --    --- REVIEWS ---
 Key | Name     Key | Comment     Key | Review
 1   | A        1   | Foo         1   | Great
 2   | B        1   | Bar         1   | Wonderful

Запрос

SELECT PRODUCTS.Key, PRODUCTS.Name, COMMENTS.Comment, REVIEWS.Review
FROM PRODUCTS
LEFT OUTER JOIN COMMENTS ON PRODUCTS.KEY = COMMENTS.KEY
LEFT OUTER JOIN REVIEWS ON PRODUCTS.KEY = REVIEWS.KEY

будут получены следующие данные:

 Key | Name | Comment | Review
 1   | A    | Foo     | Great
 1   | A    | Foo     | Wonderful
 1   | A    | Bar     | Great
 1   | A    | Bar     | Wonderful
 2   | B    | NULL    | NULL

Таким образом, считая в этом формате

SELECT PRODUCTS.Key, PRODUCTS.Name, COUNT(COMMENTS.Comment), COUNT(REVIEWS.Review)
FROM PRODUCTS
LEFT OUTER JOIN COMMENTS ON PRODUCTS.KEY = COMMENTS.KEY
LEFT OUTER JOIN REVIEWS ON PRODUCTS.KEY = REVIEWS.KEY
GROUP BY PRODUCTS.Key, PRODUCTS.Name

дам тебе

Key | Name | Count1 | Count2
1   | A    | 4      | 4
2   | B    | 0      | 0

потому что он подсчитывает каждую строку в таблице, созданную объединением!

Вместо этого вы хотите подсчитать каждую таблицу отдельно в подзапросе, прежде чем присоединять ее обратно, как показано ниже:

SELECT PRODUCTS.Key, PRODUCTS.Name, ISNULL(CommentCount.NumComments, 0),
       ISNULL(ReviewCount.NumReviews, 0)
FROM PRODUCTS
LEFT OUTER JOIN (SELECT Key, COUNT(*) as NumComments
                 FROM COMMENTS
                 GROUP BY Key) CommentCount on PRODUCTS.Key = CommentCount.Key
LEFT OUTER JOIN (SELECT Key, COUNT(*) as NumReviews
                 FROM REVIEWS
                 GROUP BY Key) ReviewCount on PRODUCTS.Key = ReviewCount.Key

который произведет следующее

Key | Name | NumComments | NumReviews
1   | A    | 2           | 2
2   | B    | 0           | 0

Что касается «DISTINCT эффекта», о котором вы говорите, я не совсем уверен, что следую ему. Не могли бы вы немного уточнить?

person lc.    schedule 14.05.2010
comment
Хорошо, я думаю, что знаю, о чем вы говорите, я собираюсь попробовать это. Моя вторая проблема заключается в том, что когда я перечисляю продукты, я хочу отображать продукт только один раз. Если я покажу продукт с уникальным GroupID только один раз. Это гарантирует, что продукты с одним и тем же GroupID (то есть продукт с тем же именем и тем же годом имеет один и тот же GroupID, это одна и та же модель, просто разная длина) будут отображаться только один раз. Если я добавлю ORDER BY case Price, то мне также придется добавить GROUP BY Product.Price. И это убирает эффект DISTINCT. - person Nicklas; 14.05.2010
comment
Если я добавлю GROUP BY Price, все продукты будут перечислены, даже если они имеют одинаковый GroupID. - person Nicklas; 14.05.2010
comment
Я не понимаю эту часть: ISNULL (CommentCount.NumComments, 0), ISNULL (ReviewCount.NumReviews, 0) Нужно ли мне создавать две новые таблицы, где я храню количество комментариев/отзывов, или что происходит? - person Nicklas; 17.05.2010
comment
@Nicklas CommentCount и ReviewCount не являются новыми таблицами, но они ссылаются на подзапросы, такие как LEFT OUTER JOIN (SELECT .. FROM ..) CommentCount ON ... Посмотрите technet.microsoft.com/en-us/library/ms189575.aspx для дополнительной помощи в понимании подзапросов. - person lc.; 19.05.2010
comment
Я также думаю, что вы действительно не понимаете GROUP BY. Вы либо хотите группировать по цене, либо хотите группировать по идентификатору группы; вы не можете иметь оба. Если вы хотите отсортировать по цене, вы не можете сгруппировать по чему-то другому, потому что данные о цене исчезают. Возьмем два товара А и В с ценами 4 и 5 соответственно. Они оба имеют одинаковый идентификатор группы. Теперь, если вы группируете по идентификатору, они оба объединяются; какова результирующая цена этой группы? 4? 5? Нет никакого способа узнать. - person lc.; 19.05.2010

О второй проблеме - нельзя ли сгруппировать по одному и тому же оператору CASE? Тогда у вас не должно быть поля «Цена» в списке результатов.

person Arvo    schedule 14.05.2010