2017-02-07 4 views
1

У нас есть широкий ассортимент продукции, с добавлением многих из них каждый день.Запрос для соответствия товарам клиентам?

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

Есть три соответствующие таблицы в базе данных:

  • Accounts (pk_AccountID, EmailAddress, название, имя)
  • Accounts_Alerts (fk_AccountID, pk_AlertID, категория, MaxPrice, цвет)
  • Продукты (pk_ItemID , Категория, Название, Цена, Цвет, Дата)

Что является наиболее эффективным способом выбора последних 10 продуктов, добавленных за последние 24 часа, которые соответствуют параметрам каждый клиент выбрал?

Это то, что у меня есть до сих пор, которое работает, но оно не отображает только 10 лучших продуктов по дате (т. Е. Последнее добавленное). Мы не хотим отправлять клиентам более 30 продуктов, чтобы просмотреть их по электронной почте.

SELECT 
    a.pk_AccountID, 
    aa.pk_AlertID, 
    a.Title As Title, 
    a.Name As Name,  
    a.EmailAddress As EmailAddress, 
    p.pk_ItemID As ItemID, 
    p.Category As Category, 
    p.Title As Title, 
    p.Price As Price, 
    p.Colour As Colour 

    FROM dbo.Accounts_Alerts aa 
    INNER JOIN dbo.Accounts a ON aa.fk_AccountID=a.pk_AccountID 
    LEFT OUTER JOIN dbo.Products p ON 
    (aa.Category = p.Category OR aa.Category IS NULL) 
    AND (aa.Colour = p.Colour OR aa.Colour IS NULL)  
    AND (aa.MaxPrice >= p.Price OR aa.MaxPrice IS NULL) 
    AND getdate()-1 < p.DateModified 

    WHERE 
    a.EmailAddress is not null AND 
    a.pk_AccountID = @AccountIDVariable 
    ORDER BY aa.pk_AlertID 
+0

Вы можете использовать 'top 10', чтобы получить 10 строк. –

+0

Если вам нужны лучшие 10 продуктов на пользователя, вы можете добавить row_number() или rank() в свой запрос, разделить по пользователю и ограничить его <= 10. Вам нужно будет обернуть ваш SQL внутри другого выбора для этого. –

+0

Для этого отлично подходит оконная функция [номер строки] (https://msdn.microsoft.com/en-us/library/ms186734.aspx?f=255&MSPPError=-2147217396). Используйте раздел by, чтобы вернуть 10 строк на каждого клиента. Если вы добавите [MCVE] (http://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-a- very-simple-sql-query) Я уверен, что кто-то поможет вам переписать ваш запрос. –

ответ

2

Обычный способ справиться с этим с оконными функциями и видом инлайн, что SQL Server обрабатывает достаточно хорошо.

Например:

SELECT 
    pk_AccountID, 
    pk_AlertID, 
    Title, 
    Name,  
    EmailAddress, 
    ItemID, 
    Category, 
    Title, 
    Price, 
    Colour 
FROM (
    SELECT 
     a.pk_AccountID, 
     aa.pk_AlertID, 
     a.Title As Title, 
     a.Name As Name,  
     a.EmailAddress As EmailAddress, 
     p.pk_ItemID As ItemID, 
     p.Category As Category, 
     p.Title As Title, 
     p.Price As Price, 
     p.Colour As Colour, 
     ROW_NUMBER() over (
      partition by a.pk_AccountID, p.pk_ItemID 
      order by p.DateModified desc 
     ) as rseq 
    FROM dbo.Accounts_Alerts aa 
    INNER JOIN dbo.Accounts a ON aa.fk_AccountID=a.pk_AccountID 
    LEFT OUTER JOIN dbo.Products p ON 
     (aa.Category = p.Category OR aa.Category IS NULL) 
     AND (aa.Colour = p.Colour OR aa.Colour IS NULL)  
     AND (aa.MaxPrice >= p.Price OR aa.MaxPrice IS NULL) 
     AND getdate()-1 < p.DateModified 
    WHERE 
     a.EmailAddress is not null AND 
     a.pk_AccountID = @AccountIDVariable 
) as any_alias_will_do 
where rseq <= 10 
ORDER BY pk_AlertID 

Обратите внимание, функция ROW_NUMBER() - вам нужно будет убедиться, что вы «разделение на» и «упорядочение по» правильным критериям (я выбрал идентификатор счета и Item ID здесь, но вам могут понадобиться разные поля). Попробуйте выполнить только внутренний запрос сам по себе, чтобы помочь вам понять, как это работает.

Эта техника довольно универсальна - рекомендуем вам дополнительно изучить эти функции.

+0

Большое спасибо за вашу любезную помощь. К сожалению, отредактировав свой код, чтобы добавить дополнительные поля, которые мне нужны и протестировали, он последовательно занимает много времени (1 минута +) и иногда выдает ошибки в памяти. Будет ли быстрее выбирать продукты за последние 24 часа во временную таблицу и выбирать из них для каждого предупреждения? – TVRV8S

+0

Я попробовал это с временным столом и сделал его еще хуже. 4 минуты проката, а затем из памяти. Затем я перевернул его обратно, используя таблицу продуктов напрямую, и теперь он не работает. – TVRV8S

+0

@ TVRV8S Во-первых, я верю вам, что вы говорите, и я не могу решить эту проблему без дополнительной информации, но у меня есть некоторые предложения для вас. Во-вторых, этот стиль запроса является вездесущим и хорошо поддержанным, поэтому он НЕ должен * HAVE * быть медленным! В-третьих, чтобы оптимизировать все, что вызывает проблемы, вам нужно знать индексы, определенные в таблицах, а также * планы выполнения * для запросов - планы выполнения должны сообщать вам, что использует большинство ресурсов, и вести вас к решение.Конечно, вы можете полностью игнорировать эту технику, но я использую ее достаточно для того, чтобы сохранить ее для вас :) – SlimsGhost