0

まず、何がキャプチャされているかを説明します。ユーザーのアカウントにはメンバーレベルが関連付けられています(ブロンズ、ゴールド、ダイアモンドなど)。1年前の今日からの注文を計算するには、夜間のジョブを実行する必要があります。特定のユーザーの注文合計が特定の金額を上回ったり下回ったりすると、レベルがアップグレードまたはダウングレードされます。レベル情報が格納されているテーブルはあまり変更されませんが、最小および最大量のしきい値は時間の経過とともに変化する可能性があります。テーブルは次のようになります。

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

これまでの1年間の注文をユーザー別にグループ化するクエリを作成しました。クエリには、現在のメンバーレベルが含まれます。

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を確認し、それが現在のレベルのしきい値を超えている場合は、現在の注文の合計に一致するレベルを見つけて、新しいレベルで新しいレコードを作成する必要があります。

たとえば、jon@doe.comが現在ブロンズにいるとします。ブロンズのMinAmountは0で、MaxAmountは999です。現在、彼の年間注文額は$2500です。$ 2500が収まるレベルを見つけて、彼のアカウントをアップグレードする必要があります。また、それらを確認するLevelAchievmentDate必要があります。今年以外の場合は、アクティビティがない場合はユーザーを降格する必要があります。

すべてのレベルの結果を保持する一時テーブルを作成してから、上記のクエリでCASEステートメントを作成して、新しいレベルを決定できると考えていました。それが可能かどうかはわかりません。または、注文結果を繰り返し処理して追加のクエリを実行する方がよいでしょうか。反復パターンを使用する場合、Whenステートメントを使用して行を反復できることがわかっています。

アップデート

クエリを少し更新して、これまでのところこれを思いついたのですが、サブクエリの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
4

2 に答える 2

1

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
于 2013-03-20T18:45:35.037 に答える
1

これは構文チェックもテストもされていませんが、記述した挿入と更新を処理する必要があります。挿入は、計算によるordersグループを含む派生/仮想テーブルを使用して単一のステートメントとして実行できます。挿入ステートメントと更新ステートメントの両方が同じトランザクション内で実行され、同じユーザーの2つのレコードが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)
于 2013-03-20T19:02:24.273 に答える