2015-05-20 2 views
3

Я пишу модуль поиска продукта, который использует граненый поиск. Чтобы немного упростить ситуацию, есть два объекта: информация о продукте и цене. Поскольку продукты могут продаваться в нескольких интернет-магазинах, у одного продукта может быть больше записей о ценах.DISTINCT in count SQL Server

продукт

- product_guid 
- product_category 
- product_brand 

priceInformation

- priceInformation_guid 
- priceInformation_price 
- priceInformation_product_guid 

Я перечисляю все продукты в определенной категории, и пользователь может фильтровать по диапазону цен. Диапазоны цен указаны с помощью флажков, за каждым ценовым диапазоном вы можете увидеть количество продуктов, соответствующих критериям поиска. Диапазоны цен, которые не имеют совпадений, не отображаются. Для каждого диапазона цен я делаю запрос, чтобы определить количество совпадений (количество фасетов).

select count(distinct(product.product_guid)) as count 
from product 
    INNER JOIN priceInformation ON product.product_guid = 
    priceInformation.priceInformation_product_guid 
WHERE category= 'beer' 
    AND product.priceInformation_price > 20 
    AND product.priceInformation_price <= 30 

Все работает нормально, но ... потому что число диапазонов растет (это просто упрощенный пример) я выполнять сотни запросов каждый поиск. Это большой убийца. Я попытался получить все счеты граней в одном запросе, но поскольку между продуктом и ценой существует соотношение 1: n, результатом будет количество цен, которые соответствуют, а не количество продуктов.

select (Count(Case WHEN product.priceInformation_price > 20 AND 
         product.priceInformation_price <= 30 THEN 1 
        ELSE NULL END)) as Range2030, 
     (Count(Case WHEN product.priceInformation_price > 30 AND 
         product.priceInformation_price <= 40 THEN 1 
        ELSE NULL END)) as Range3040 
from product 
    INNER JOIN priceInformation ON product.product_guid = 
    priceInformation.priceInformation_product_guid 
WHERE category= 'beer' 

Итог в том, что я пропустил DISTINCT здесь. Я тяну свои волосы на несколько дней. Может ли кто-нибудь помочь?

ответ

1

Используйте производную таблицу, чтобы получить разные диапазоны цен, сделайте GROUP BY, чтобы считать отличные. Что-то вроде:

select count(distinct(dt.product_guid)), dt.pricerange as count 
from 
(
select product.*, case when price < 20 then 'price < 20' 
         when price between 20 and 30 then 'price 20 - 30' 
         else 'price > 30' end as pricerange 
from product 
    INNER JOIN priceInformation ON product.product_guid = 
    priceInformation.priceInformation_product_guid 
WHERE category= 'beer' 
) dt 
group by dt.pricerange 

Или я ответил что-то еще здесь ...?

+0

Это работает как шарм! В стресс-тесте (250 'диапазонов) я измерил уменьшение общего времени запроса на 98%. Благодаря!!! –

+0

Добро пожаловать! Рад, что это сработало! – jarlh

0

Я думаю, вы должны создать таблицу с диапазонами цен, например:

create table PriceRanges(minPrice money,maxPrice money); 
insert PriceRanges values (0,9),(10,19),(20,29),(100,149) ; 

Затем с помощью этой таблицы запроса является:

SELECT minPrice,maxPrice,COUNT(DISTINCT p.product_guid) 
    as ProductCount 
FROM PriceRanges pr 
LEFT JOIN priceInformation pi ON pi.priceInformation_price 
      BETWEEN pr.minPrice AND pr.maxPrice 
LEFT JOIN product p ON pi.priceInformation_product_guid= p.product_guid 
WHERE p.product_category = 'beer' 
GROUP BY minPrice,maxPrice 
ORDER BY minPrice 

Sqlfiddle demo

Или использовать JOIN вместо LEFT JOIN, если вам не нужны пустые диапазоны цен.