我有一个Customer
表,其中包含IsActive
列。如果"活跃",他有资格获得某些产品和服务。
我需要知道是否在特定日期,他是否符合条件。
问题是他的记录可能会发生变化,因此我必须在CustomerChanges
审核表中跟踪这些更改,其中包含可以更改的属性。每当我们更改他的记录时,我们都会在该表中添加一条记录,包括更改和日期。
我需要的是"让我所有的客户,他们约会xyz,活跃"。
我如何建模和查询这样的表?
(我使用的是SQL Server和EF Core)
愚蠢的例子:给他的生日送一张礼品卡,但前提是他的帐户没有被暂停,取消或拖欠等等。换句话说,只有当他的帐户是“活跃的”#34;在那一天。
答案 0 :(得分:1)
我会这样做:将CustomerId,StartingDate和EndingDate作为PrimaryKey的表。然后,您还可以获得此表中可能需要的所有其他信息,例如他是否活跃。
保存所有更改的最佳方法是在Customer.IsActive上设置更新触发器....此触发器需要在更改的起始点和更改的结束点之间进行区分。
然后,如果你想查询它,你需要在这两个表之间进行连接,看起来像这样:
SELECT * FROM CustomerChanges
INNER JOIN Customer ON Customer.Id = CustomerChanges.CustomerId
WHERE xyz BETWEEN CustomerChanges.StartingDate
AND CustomerChanges.EndingDate;
答案 1 :(得分:1)
我相信理论上这就是你想要实现的目标。
select Users.Id, Users.UserName, OrderedActivity.IsActive
from
(
select UserActivity.Id
, UserActivity.UpdateTime
, UserActivity.IsActive
, row_number() over
(partition by UserActivity.Id order by UserActivity.UpdateTime desc) as EntryNum
from UserActivity
where UserActivity.UpdateTime <= '20161210 10:00:00 AM'
) OrderedActivity
inner join Users
on Users.Id = OrderedActivity.Id
where OrderedActivity.EntryNum = 1;
基本上,它按日期对UserActivity中的条目进行排名(包含任何活动/非活动更改),不包括比所选日期更新的任何内容。然后它接受第一个条目(日期之前的最近更改)。
此时,对于每个用户记录,您都可以使用相应的IsActive标记(您可以使用添加到外部查询的另一个where子句来过滤掉您不想要的内容)。
以下是此操作的示例:http://rextester.com/QPSM50121
在C#中:
var filteredActivity =
Activity.Where(activity => activity.UpdateTime <= SOME_DATE)
.GroupBy(activity => activity.Id)
.Select(groupedActivities => groupedActivities.OrderByDescending(activity => activity.UpdateTime).FirstOrDefault()).ToList();
var results =
from user in Users
join activity in filteredActivity
on user.Id equals activity.Id
where activity.IsActive == 'Y'
select new { user.Id, activity.IsActive };
行动中的示例:http://rextester.com/SYZ96749
这是C#中的另一个版本,但尝试将其全部合并到LINQ-to-SQL中。不确定它是否会因为问题而帮助您解决您的EF小组问题。
var results =
from activity in Activity
where activity.UpdateTime <= Convert.ToDateTime("10/12/2016 10:00:00")
group activity by activity.Id into groupedActivities
let mostRecentActivity =
(
from groupedActivity in groupedActivities
orderby groupedActivity.UpdateTime descending
select groupedActivity
).First()
join user in Users
on mostRecentActivity.Id equals user.Id
where mostRecentActivity.IsActive == 'Y'
select new { user.Id, mostRecentActivity.IsActive };
答案 2 :(得分:1)
您走在正确的轨道上,可能已经拥有最佳设计。你没有显示审计表的设计,所以这是我的建议:
create table CustomerStatus(
CustID int not null references Customer( ID ),
EffDate date not null,
Status char( 1 ) not null, -- A = Active, S = Suspended, etc.
constraint PK_CustomerStatus primary key( CustID, EffDate )
);
注意没有&#34;结束&#34;日期。一旦状态生效,它将一直有效,直到它被另一个状态替换。这是查询的关键,以查找当前状态或在任何给定日期生效的状态。
Select c.*, cs.Status
from Customer c
join CustomerStatus cs
on cs.CustID = c.ID
and cs.EffDate =(
select Max( EffDate )
from CustomerStatus
where CustID = cs.CustID
and EffDate <= Today() );
不要让子查询吓到你。您得到的是一条记录,其中包含最新生效日期之前或当前日期/时间的状态。您可以使用查询创建视图,以返回任何或所有客户的当前状态,因为这可能是操作中最常用的状态。
这是非常酷的部分。将最后一行更改为以下内容:
and EffDate <= :AsOf );
将 AsOf 变量设置为当前日期/时间,您将获得之前的当前状态。将变量设置为过去或将来的任何日期/时间,您将获得该日期/时间(或将来)生效的状态。您可以使用相同的查询检索当前状态或任何过去(或将来)状态。我认为这非常棒。
假设客户今天购买了3个月的会员资格。因此,您插入状态为Active的生效日期为今天,另一个状态为Arrears(或Lapsed或其他),生效日期为3个月。