0

我有一个会员数据库,我想在其中创建一个附加表,以跟踪我们的会员在整整 12 个月内如何随时间(按月)变化。我不确定要使用的最佳数据库设计。

我们的会员订阅有开始日期和结束日期。每个月我们都有几个新成员,即。他们订阅的开始日期在该月。同样,每个月我们都有一些成员离开,即。他们订阅的结束日期在该月。对于我们的其余成员,他们在整个月内都是最新的,即。他们订阅的开始日期在给定月份之前,而他们订阅的结束日期在给定月份之后。

我在创建的表中有这些数据:

SubscriptionSnaphot
   MemberID int
   SubscriptionType varchar
   StartDate datetime
   EndDate datetime

如果成员拥有多个订阅,则成员可以在数据中出现多次。

我想补充此表,以包括该成员过去 12 个月的状态指示。例如,假设一个成员在 9 个月前加入并持有 6 个月的通行证,然后离开。他们通过 12 个月的状态为:I,I,I,N,C,C,C,C,C,E,I,I 其中 I=Inactive, N=New, C=Current and E=Expired。

一个天真的设计可能只是在我的表中添加 12 列,过去 12 个月中的每一列,然后使用一些查询来更新它们。

我的问题:

  • 代表这个移动快照的好设计是什么
  • 填充快照数据的相应查询是什么(假设您有如上所述的订阅数据)

我不需要处理大量数据,也不需要完全标准化的设计。我追求的是易于创建提取数据的东西。我可能会在过去 12 个月的每个月的第一天重新生成这些数据。

我正在使用 SQL Server 2008,但如果可能的话,我更喜欢与数据库无关的解决方案。

4

2 回答 2

0

我会写一个表,它是您的 Membership 表的克隆,但删除了不相关的信息。
我要背着 aspnet_Membership 表,因为它是众所周知的。我们称之为“asp_Membership_Audit”。

我会创建一个表格,您可以在其中放置一个唯一的日期戳(一次)。我们称它为“Tageroni”(“Tag”的长名称)然后我将在我的 asp_Membership_Audit 表中添加一个列,该列是 Tageroni 表的 PK 的 FK。

然后,每个月运行一次将一行放入 Tageroni 表的作业。然后使用 Tageroni FK 复制您的成员资格表(到 aspnet_Membership_Audit 表)。您可以将日期戳放在“审计”表中,但我不喜欢使用时间戳作为唯一标识符......我喜欢 int、bigint 或 uuid。

然后,您就拥有了生成报告所需的数据。如果你现在想出一些“超级聪明”的东西,你的需求可能会改变。但是完全正确地捕获审计数据,您可以随时使用单列管道值创建“报告”。

这是概念。我的查询充其量只是初步结束,但只要捕获了数据,您就可以稍后创建报告。

但基本上,使用 Tageroni 表和克隆表,您将拥有“我的数据在任何月份的第一个月的样子”的完美快照......。

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[aspnet_Membership_Audit]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
      BEGIN
            DROP TABLE [dbo].[aspnet_Membership_Audit]
      END
GO


if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Tageroni]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
      BEGIN
            DROP TABLE [dbo].[Tageroni]
      END
GO


CREATE TABLE [dbo].[Tageroni] (
      TageroniUUID [uniqueidentifier] not null default NEWSEQUENTIALID() , 
      TageroniName varchar(64) not null , 
      TageroniDateStamp datetime not null
)     
GO


ALTER TABLE dbo.Tageroni ADD CONSTRAINT PK_Tageroni_TageroniUUID
PRIMARY KEY CLUSTERED (TageroniUUID)
GO


ALTER TABLE dbo.Tageroni ADD CONSTRAINT CK_Tageroni_TageroniName_UNIQUE 
UNIQUE (TageroniName)
GO



CREATE TABLE [dbo].[aspnet_Membership_Audit](
    aspnet_Membership_Audit_UUID  [uniqueidentifier]  not null default NEWSEQUENTIALID() , 
    TageroniUUID [uniqueidentifier] NOT NULL,

    /* The 3 columns below are the User, and the "status" flags I'm interested in */
    [UserId] [uniqueidentifier] NOT NULL,
    [IsApproved] [bit] NOT NULL,
    [IsLockedOut] [bit] NOT NULL
    )
GO



ALTER TABLE dbo.aspnet_Membership_Audit ADD CONSTRAINT PK_aspnet_Membership_Audit_UUID
PRIMARY KEY CLUSTERED (aspnet_Membership_Audit_UUID)
GO

ALTER TABLE [dbo].[aspnet_Membership_Audit]  WITH CHECK ADD FOREIGN KEY([TageroniUUID])
REFERENCES [dbo].[Tageroni] ([TageroniUUID])
GO


/* Once a Month, Run something like this */


INSERT INTO dbo.Tageroni ( TageroniUUID , TageroniName , TageroniDateStamp )
select '11111111-1111-1111-1111-111111111111' , 'My First Tag, 2013' , '01/01/2013'
UNION ALL select '22222222-2222-2222-2222-222222222222' , 'My Second Tag, 2013' , '02/01/2013'
UNION ALL select '33333333-3333-3333-3333-333333333333' , 'My Third Tag, 2013' , '03/01/2013'


/* Run this on Jan 1, 2013 */
INSERT INTO [dbo].[aspnet_Membership_Audit](    [UserId] ,  TageroniUUID  , [IsApproved] , [IsLockedOut] )
Select '11111111-1111-1111-1111-111111111111' , UserId ,  [IsApproved] ,  [IsLockedOut] 
from [dbo].[aspnet_Membership]

/* Run this on Feb 1, 2013 */
INSERT INTO [dbo].[aspnet_Membership_Audit](    [UserId] ,  TageroniUUID  , [IsApproved] , [IsLockedOut] )
Select '22222222-2222-2222-2222-222222222222' , UserId ,  [IsApproved] ,  [IsLockedOut] 
from [dbo].[aspnet_Membership]

/* Run this on March 1, 2013 */
INSERT INTO [dbo].[aspnet_Membership_Audit](    [UserId] ,  TageroniUUID  , [IsApproved] , [IsLockedOut] )
Select '33333333-3333-3333-3333-333333333333' , UserId ,  [IsApproved] ,  [IsLockedOut] 
from [dbo].[aspnet_Membership]


GO


Select derivedJan.UserId , derivedJan.[IsApproved] as JanIsApproved , derivedFeb.[IsApproved] as FebIsApproved , derivedMarch.[IsApproved] as MarIsApproved
From
(select * from [dbo].[aspnet_Membership_Audit] where TageroniUUID = '11111111-1111-1111-1111-111111111111') derivedJan 
join
(select * from [dbo].[aspnet_Membership_Audit] where TageroniUUID = '22222222-2222-2222-2222-222222222222') derivedFeb 
on derivedJan.UserId = derivedFeb.UserId
join
(select * from [dbo].[aspnet_Membership_Audit] where TageroniUUID = '33333333-3333-3333-3333-333333333333') derivedMarch
on derivedJan.UserId = derivedMarch.UserId

编辑 - - - - - - -

这是一个“滑动”警告..​​..........

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[aspnet_Membership_Audit]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
      BEGIN
            DROP TABLE [dbo].[aspnet_Membership_Audit]
      END
GO


if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Tageroni]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
      BEGIN
            DROP TABLE [dbo].[Tageroni]
      END
GO


CREATE TABLE [dbo].[Tageroni] (
      TageroniUUID [uniqueidentifier] not null default NEWSEQUENTIALID() , 
      TageroniName varchar(64) not null , 
      TageroniDateStamp datetime not null ,
      TageroniMonthsIntoThePast int not null
)     
GO


ALTER TABLE dbo.Tageroni ADD CONSTRAINT PK_Tageroni_TageroniUUID
PRIMARY KEY CLUSTERED (TageroniUUID)
GO


ALTER TABLE dbo.Tageroni ADD CONSTRAINT CK_Tageroni_TageroniName_UNIQUE 
UNIQUE (TageroniName)
GO



CREATE TABLE [dbo].[aspnet_Membership_Audit](
    aspnet_Membership_Audit_UUID  [uniqueidentifier]  not null default NEWSEQUENTIALID() , 
    TageroniUUID [uniqueidentifier] NOT NULL,

    /* The 3 columns below are the User, and the "status" flags I'm interested in */
    [UserId] [uniqueidentifier] NOT NULL,
    [IsApproved] [bit] NOT NULL,
    [IsLockedOut] [bit] NOT NULL
    )
GO



ALTER TABLE dbo.aspnet_Membership_Audit ADD CONSTRAINT PK_aspnet_Membership_Audit_UUID
PRIMARY KEY CLUSTERED (aspnet_Membership_Audit_UUID)
GO

ALTER TABLE [dbo].[aspnet_Membership_Audit]  WITH CHECK ADD FOREIGN KEY([TageroniUUID])
REFERENCES [dbo].[Tageroni] ([TageroniUUID])
GO


/* Once a Month, Run something like this */
/* And adjust the TageroniMonthsIntoThePast value to be a "sliding" value */


INSERT INTO dbo.Tageroni ( TageroniUUID , TageroniName , TageroniDateStamp , TageroniMonthsIntoThePast)
select '11111111-1111-1111-1111-111111111111' , 'My First Tag, 2013' , '01/01/2013' , 4
UNION ALL select '22222222-2222-2222-2222-222222222222' , 'My Second Tag, 2013' , '02/01/2013' , 3 
UNION ALL select '33333333-3333-3333-3333-333333333333' , 'My Third Tag, 2013' , '01/01/2013' , 2


/* Run this on Jan 1, 2013 */
INSERT INTO [dbo].[aspnet_Membership_Audit](    [UserId] ,  TageroniUUID  , [IsApproved] , [IsLockedOut] )
Select '11111111-1111-1111-1111-111111111111' , UserId ,  [IsApproved] ,  [IsLockedOut] 
from [dbo].[aspnet_Membership]

/* Run this on Feb 1, 2013 */
INSERT INTO [dbo].[aspnet_Membership_Audit](    [UserId] ,  TageroniUUID  , [IsApproved] , [IsLockedOut] )
Select '22222222-2222-2222-2222-222222222222' , UserId ,  [IsApproved] ,  [IsLockedOut] 
from [dbo].[aspnet_Membership]

/* Run this on March 1, 2013 */
INSERT INTO [dbo].[aspnet_Membership_Audit](    [UserId] ,  TageroniUUID  , [IsApproved] , [IsLockedOut] )
Select '33333333-3333-3333-3333-333333333333' , UserId ,  [IsApproved] ,  [IsLockedOut] 
from [dbo].[aspnet_Membership]


GO


Select TwoMonthsAgoDerived.UserId , TwoMonthsAgoDerived.[IsApproved] as TwoMonthsOldIsApproved , ThreeMonthsAgoDerived.[IsApproved] as ThreeMonthsOldIsApproved , FourMonthsAgoDerived.[IsApproved] as FourMonthsOldIsApproved
From
(select aud.* from [dbo].[aspnet_Membership_Audit] aud join dbo.Tageroni tag on aud.TageroniUUID = tag.TageroniUUID where TageroniMonthsIntoThePast = 2 ) TwoMonthsAgoDerived 
join
(select aud.* from [dbo].[aspnet_Membership_Audit] aud join dbo.Tageroni tag on aud.TageroniUUID = tag.TageroniUUID where TageroniMonthsIntoThePast = 3) ThreeMonthsAgoDerived 
on TwoMonthsAgoDerived.UserId = ThreeMonthsAgoDerived.UserId
join (select aud.* from [dbo].[aspnet_Membership_Audit] aud join dbo.Tageroni tag on aud.TageroniUUID = tag.TageroniUUID where TageroniMonthsIntoThePast =  4) FourMonthsAgoDerived
on TwoMonthsAgoDerived.UserId = FourMonthsAgoDerived.UserId
于 2013-05-02T22:36:06.253 回答
0

我最终创建了第二个表来与原始表一起保存快照信息。后者被修改为在前者中添加一个 RecordID 列作为主键和外键。我的附加(前)表如下所示:

SubScriptionSnapshotData
    SubscriptionRecordID int
    Year smallint
    YearElement smallint
    ElementType varchar(15)
    Status varchar(15)

因此,该表中的每条记录都指向原始表中的一条记录,并为其记录移动快照信息。本质上我可以记录快照的年份和月份以及快照中的订阅状态。

通过使用 (YearElement, ElementType) 而不是简单的 Month,我可以按月或按周或其他方式创建快照。例如,四月表示为 (4, 'Month')。第 32 周的快照可以表示为 (32, 'Week')。状态只是“新”、“过期”或“当前”。

于 2013-05-09T07:12:06.757 回答