2013-03-20 2 views
0

Во-первых, я объясню, что захвачено. У пользователя есть уровень членства, связанный с их учетными записями (Бронза, Золото, Алмаз и т. Д.). Ночная работа должна выполняться для расчета заказов с сегодняшнего дня в течение года. Если общая сумма заказа для данного пользователя переполнена или находится под определенной суммой, их уровень обновляется или понижается. Таблица, в которой хранится информация о уровне, не будет сильно изменяться, но пороговые значения минимальной и максимальной величины могут со временем. Это выглядит так:Сравнение значений из одной таблицы с результатами запроса?

CREATE TABLE [dbo].[MemberAdvantageLevels] (
[Id] int NOT NULL IDENTITY(1,1) , 
[Name] varchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL , 
[MinAmount] int NOT NULL , 
[MaxAmount] int NOT NULL , 
CONSTRAINT [PK__MemberAd__3214EC070D9DF1C7] PRIMARY KEY ([Id]) 
) 
ON [PRIMARY] 
GO 

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

SELECT 
Sum(dbo.tbh_Orders.SubTotal) AS OrderTotals, 
Count(dbo.UserProfile.UserId) AS UserOrders, 
dbo.UserProfile.UserId, 
dbo.UserProfile.UserName, 
dbo.UserProfile.Email, 
dbo.MemberAdvantageLevels.Name, 
dbo.MemberAdvantageLevels.MinAmount, 
dbo.MemberAdvantageLevels.MaxAmount, 
dbo.UserMemberAdvantageLevels.LevelAchievmentDate, 
dbo.UserMemberAdvantageLevels.LevelAchiementAmount, 
dbo.UserMemberAdvantageLevels.IsCurrent as IsCurrentLevel, 
dbo.MemberAdvantageLevels.Id as MemberLevelId, 


FROM 
dbo.tbh_Orders 
INNER JOIN dbo.tbh_OrderStatuses ON dbo.tbh_Orders.StatusID = dbo.tbh_OrderStatuses.OrderStatusID 
INNER JOIN dbo.UserProfile ON dbo.tbh_Orders.CustomerID = dbo.UserProfile.UserId 
INNER JOIN dbo.UserMemberAdvantageLevels ON dbo.UserProfile.UserId = dbo.UserMemberAdvantageLevels.UserId 
INNER JOIN dbo.MemberAdvantageLevels ON dbo.UserMemberAdvantageLevels.MemberAdvantageLevelId = dbo.MemberAdvantageLevels.Id 
WHERE 
dbo.tbh_OrderStatuses.OrderStatusID = 4 AND 
(dbo.tbh_Orders.AddedDate BETWEEN dateadd(year,-1,getdate()) AND GETDATE()) and IsCurrent = 1 
GROUP BY 
dbo.UserProfile.UserId, 
dbo.UserProfile.UserName, 
dbo.UserProfile.Email, 
dbo.MemberAdvantageLevels.Name, 
dbo.MemberAdvantageLevels.MinAmount, 
dbo.MemberAdvantageLevels.MaxAmount, 
dbo.UserMemberAdvantageLevels.LevelAchievmentDate, 
dbo.UserMemberAdvantageLevels.LevelAchiementAmount, 
dbo.UserMemberAdvantageLevels.IsCurrent, 
dbo.MemberAdvantageLevels.Id 

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

Так, например, скажем, [email protected] сейчас находится в бронзе. MinAmount для бронзы - 0, а MaxAmount - 999. В настоящее время его заказы на год составляют 2500 долларов. Мне нужно найти уровень, который соответствует $ 2500 и обновить его аккаунт. Я также должен проверить их LevelAchievmentDate, и если он находится за пределами текущего года, нам может потребоваться понизить рейтинг пользователя, если не было никакой активности.

Я думал, что могу создать временную таблицу, которая содержит результаты всех уровней, а затем каким-то образом создать оператор CASE в запросе выше, чтобы определить новый уровень. Я не знаю, возможно ли это. Или, лучше ли перебирать результаты моего заказа и выполнять дополнительные запросы? Если я использую шаблон итерации, я знаю, что могу использовать оператор When для итерации по строкам.

Update

Я обновил свой запрос немного, и до сих пор придумал, но я, возможно, потребуется больше информации, чем просто ID из подзапроса

Select * into #memLevels from MemberAdvantageLevels 


SELECT 
Sum(dbo.tbh_Orders.SubTotal) AS OrderTotals, 
Count(dbo.AZProfile.UserId) AS UserOrders, 
dbo.AZProfile.UserId, 
dbo.AZProfile.UserName, 
dbo.AZProfile.Email, 
dbo.MemberAdvantageLevels.Name, 
dbo.MemberAdvantageLevels.MinAmount, 
dbo.MemberAdvantageLevels.MaxAmount, 
dbo.UserMemberAdvantageLevels.LevelAchievmentDate, 
dbo.UserMemberAdvantageLevels.LevelAchiementAmount, 
dbo.UserMemberAdvantageLevels.IsCurrent as IsCurrentLevel, 
dbo.MemberAdvantageLevels.Id as MemberLevelId, 

(Select Id from #memLevels where Sum(dbo.tbh_Orders.SubTotal) >= #memLevels.MinAmount and Sum(dbo.tbh_Orders.SubTotal) <= #memLevels.MaxAmount) as NewLevelId 


FROM 
dbo.tbh_Orders 
INNER JOIN dbo.tbh_OrderStatuses ON dbo.tbh_Orders.StatusID = dbo.tbh_OrderStatuses.OrderStatusID 
INNER JOIN dbo.AZProfile ON dbo.tbh_Orders.CustomerID = dbo.AZProfile.UserId 
INNER JOIN dbo.UserMemberAdvantageLevels ON dbo.AZProfile.UserId = dbo.UserMemberAdvantageLevels.UserId 
INNER JOIN dbo.MemberAdvantageLevels ON dbo.UserMemberAdvantageLevels.MemberAdvantageLevelId = dbo.MemberAdvantageLevels.Id 
WHERE 
dbo.tbh_OrderStatuses.OrderStatusID = 4 AND 
(dbo.tbh_Orders.AddedDate BETWEEN dateadd(year,-1,getdate()) AND GETDATE()) and IsCurrent = 1 
GROUP BY 
dbo.AZProfile.UserId, 
dbo.AZProfile.UserName, 
dbo.AzProfile.Email, 
dbo.MemberAdvantageLevels.Name, 
dbo.MemberAdvantageLevels.MinAmount, 
dbo.MemberAdvantageLevels.MaxAmount, 
dbo.UserMemberAdvantageLevels.LevelAchievmentDate, 
dbo.UserMemberAdvantageLevels.LevelAchiementAmount, 
dbo.UserMemberAdvantageLevels.IsCurrent, 
dbo.MemberAdvantageLevels.Id 
+0

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

+0

Я пытаюсь предоставить контекст, и это не слишком сложный запрос. – DDiVita

ответ

1

Этот не проверял или тестировавших синтаксис, но должен обрабатывать вставленные вставки и обновлять вы описываете. Вставка может быть сделана как единый оператор, используя производную/виртуальную таблицу, которая содержит группу заказов посредством caluclation. Следует отметить, что как вставка и утверждение обновление будет сделано в рамках одной транзакции, чтобы убедиться в отсутствии двух записей для одного пользователя может в конечном итоге с IsCurrent = 1

INSERT UserMemberAdvantageLevels (UserId, MemberAdvantageLevelId, IsCurrent, 
     LevelAchiementAmount, LevelAchievmentDate) 
SELECT t.UserId, mal.Id, 1, t.OrderTotals, GETDATE() 
FROM 
    (SELECT ulp.UserId, SUM(ord.SubTotal) OrderTotals, COUNT(ulp.UserId) UserOrders 
    FROM UserLevelProfile ulp 
    INNER JOIN tbh_Orders ord ON (ord.CustomerId = ulp.UserId) 
    WHERE ord.StatusID = 4 
      AND ord.AddedDate BETWEEN DATEADD(year,-1,GETDATE()) AND GETDATE() 
    GROUP BY ulp.UserId) AS t 
INNER JOIN MemberAdvantageLevels mal 
ON (t.OrderTotals BETWEEN mal.MinAmount AND mal.MaxAmount) 
    -- Left join needed on next line in case user doesn't currently have a level 
LEFT JOIN UserMemberAdvantageLevels umal ON (umal.UserId = t.UserId) 
WHERE umal.MemberAdvantageLevelId IS NULL -- First time user has been awarded a level 
     OR (mal.Id <> umal.MemberAdvantageLevelId -- Level has changed 
      AND (t.OrderTotals > umal.LevelAchiementAmount -- Acheivement has increased (promotion) 
       OR t.UserOrders = 0))    -- No. of orders placed is zero (de-motion) 

/* Reset IsCurrent flag where new record has been added */ 
UPDATE UserMemberAdvantageLevels 
SET umal1.IsCurrent=0 
FROM UserMemberAdvantageLevels umal1 
INNER JOIN UserMemberAdvantageLevels umal2 On (umal2.UserId = umal1.UserId) 
WHERE umal1.IsCurrent = 1 
AND umal2.IsCurrent = 2 
AND umal1.LevelAchievmentDate < umal2.LevelAchievmentDate) 
+0

Это в значительной степени то, что я искал, однако, я использовал кусок Марка – DDiVita

1

Один из подходов:

with cte as 
(SELECT Sum(o.SubTotal) AS OrderTotals, 
     Count(p.UserId) AS UserOrders, 
     p.UserId, 
     p.UserName, 
     p.Email, 
     l.Name, 
     l.MinAmount, 
     l.MaxAmount, 
     ul.LevelAchievmentDate, 
     ul.LevelAchiementAmount, 
     ul.IsCurrent as IsCurrentLevel, 
     l.Id as MemberLevelId 
FROM dbo.tbh_Orders o 
INNER JOIN dbo.UserProfile p ON o.CustomerID = p.UserId 
INNER JOIN dbo.UserMemberAdvantageLevels ul ON p.UserId = ul.UserId 
INNER JOIN dbo.MemberAdvantageLevels l ON ul.MemberAdvantageLevelId = l.Id 
WHERE o.StatusID = 4 AND 
     o.AddedDate BETWEEN dateadd(year,-1,getdate()) AND GETDATE() and 
     IsCurrent = 1 
GROUP BY 
     p.UserId, p.UserName, p.Email, l.Name, l.MinAmount, l.MaxAmount, 
     ul.LevelAchievmentDate, ul.LevelAchiementAmount, ul.IsCurrent, l.Id) 
select cte.*, ml.* 
from cte 
join #memLevels ml 
    on cte.OrderTotals >= ml.MinAmount and cte.OrderTotals <= ml.MaxAmount 
+0

Соединение на tbh_OrderStatuses не требуется - «s.OrderStatudID = 4» можно заменить на «o.StatusID = 4». Также отсутствует псевдоним «l» на MemberAdvantageLevels. В основном это то же самое, что и мой ответ, но мой также обрабатывает вставку/обновление. Твоя красиво отформатирована. Возможно, я попытаюсь улучшить мою. –

+0

@YoungBob: Спасибо - я обновил свой ответ соответственно. –

Смежные вопросы