2013-03-20 30 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 for Bronze是0,MaxAmount是999.目前他的年度訂單是2500美元。我需要找到2500美元適合的級別並升級他的帳戶。我還需要檢查他們的LevelAchievmentDate,如果它不在當前年份,我們可能需要降級用戶,如果沒有活動。

我在想我可以創建一個臨時表來保存所有級別的結果,然後在上面的查詢中創建一個CASE語句來確定新的級別。我不知道這是否可能。或者,迭代我的訂單結果並執行其他查詢會更好嗎?如果我使用迭代模式,我知道我可以使用When語句遍歷行。

更新

我更新了我查詢了一下,到目前爲止想出了這個,但我可能需要更多的信息,不僅僅是從子查詢

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和問題,多少更容易理解;從而吸引更多潛在的回答者。 – 2013-03-20 18:02:13

+0

我想提供上下文,它不是一個過於複雜的查詢。 – DDiVita 2013-03-20 18:24:18

回答

1

未被語法檢查或測試但應處理插入和更新你描述的。插入可以通過使用派生/虛擬表(包含通過計算的訂單組)的單個語句完成。需要注意的是,INSERT和UPDATE語句在同一事務中進行,以確保沒有兩個記錄相同的用戶可以結束了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

這幾乎是我正在尋找的東西,但是,我用馬克的cte作品 – DDiVita 2013-03-21 11:51:07

1

一種方法的ID:

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」。 MemberAdvantageLevels上還缺少別名「l」。基本上這與我的答案是一樣的,但我也處理插入/更新。你的格式很好..不過我可能會嘗試改進我的。 – 2013-03-21 11:02:10

+0

@YoungBob:謝謝 - 我已經相應地更新了我的答案。 – 2013-03-21 11:38:38

相關問題