如何在数据库中创建传递持有者信息的移动快照

时间:2013-05-02 21:38:24

标签: sql sql-server tsql database-design

我有一个会员数据库,我想创建一个额外的表格,以跟踪我们的会员资格如何随着时间的推移(按月逐月)变化整整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 =非活动,N =新,C =当前和E =已过期。

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

我的问题:

  • 表示此移动快照的好设计
  • 填充快照数据的相应查询是什么(假设您拥有上述订阅数据)

我不处理大量数据,也不需要完全标准化的设计。我正在做一些简单的事情来创建从中提取数据。我可能会在过去12个月的每个月的第一天重新生成这些数据。

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

2 个答案:

答案 0 :(得分:0)

我会写一个表格,它是您的会员资格表的克隆,但删除了无关的信息 因为它非常清楚,所以我会重新回到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

EDIT -------------

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

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

答案 1 :(得分:0)

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

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

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

通过使用(YearElement,ElementType)而不仅仅是Month,我可以按月或周等创建快照。例如,April表示为(4,'Month')。第32周的快照可以表示为(32,'周')。状态只是“新”,“过期”或“当前”。