2009-10-26 81 views
0

以下是我的SQL Server 2005的表结构:帮助硬SQL查询来更新基于每日汇总到汇总表

产品(INT的productID PK,...)

ProductBids(INT的productID,用户ID INT,DATETIME创建)

用户(用户ID INT PK,TOTALBIDS INT)

每一天,因为他们希望在所有的产品,用户可以申办多次。 有一个定期运行的sql作业,用于统计用户执行的总出价,并将总数置于TOTALBIDS字段中。

问题在于,我们的业务规则要求我们在任何特定日期只能计算出最多10个出价。

因此,更新查询必须按天分组,并且如果产品上的用户的总出价超过10,那么我们仅在当天使用10。

例如 天#1出价总共 天#5倍2出价15中总 天#次3出价10倍

(假设共3天) 的bidCount对于用户将是5 + 10 + 10 = 25(不是30)。

这是可能在一个单一的查询?

+2

您可能想要接受超过1/3问题的答案。那些竭尽全力帮助你的人通常会被你实际接受他们的答案的机会激发出来。 – 2009-10-26 04:01:21

+0

亚伦,我现在要为过去做这件事,我必须回去你的权利!我真的很感谢这里的帮助。 – mrblah 2009-10-26 14:43:43

回答

0

我认为你可以使用聚合+ case语句来做到这一点。喜欢的东西:

declare @t table (a int, b int) 

insert into @t values(1, 5) 
insert into @t values(1, 15) 
insert into @t values(1, 10) 


select a, sum(case when b>10 then 10 else b end) 
from @t 
group by a 

case语句是确保你永远不会增加超过10如果该值大于10

1

你不说你想要的结果做什么,但你可以当然选择用户的最早的每天十个投标:

with ProductBidsRanked(productID, userID, Created, rk) as (
    select 
    productID, userID, Created, 
    row_number() over (
     partition by userID, dateadd(datediff(day,0,Created),0) 
     order by Created 
    ) 
) 
    select productID, userID, Created 
    from ProductBidsRanked 
    where rk <= 10 

当然,如果你只需要合计,并希望当超过10 10,以取代总,这是更简单:

with PartialAgg(userID,countOr10) as (
    select 
    userID, 
    case when count(*) > 10 then 10 else count(*) end 
    from ProductsBids 
    group by userID, dateadd(datediff(day,0,Created),0) 
) 
    select 
    userID, sum(countOr10) as BidsAdjusted 
    from PartialAgg 
    group by userID; 

回应评论:

你说你希望将其添加到用户的bidcount,但bidcount是不是在你的任何表的列名。也许你的意思TOTALBIDS,因此,例如,如果第二个查询,为你工作的人,你可以做这样的事情:

with PartialAgg(userID,countOr10) as (
    select 
    userID, 
    case when count(*) > 10 then 10 else count(*) end 
    from ProductsBids 
    group by userID, dateadd(datediff(day,0,Created),0) 
), FullAgg(userID,BidsAdjusted) as (
    select 
    userID, sum(countOr10) as BidsAdjusted 
    from PartialAgg 
    group by userID 
) 
    update users set 
    TOTALBIDS = TOTALBIDS + BidsAdjusted 
    from users join FullAgg 
    on FullAgg.userID = users.userID 

仅供参考,这里有一些SQL Server特定的东西 - ANSI不允许使用CTE进行更新,并且我没有确认T-SQL的古怪UPDATE .. FROM可以与CTE结合使用。

在任何情况下,考虑到这似乎是更新的类型,您只会偶尔运行,而不会同时运行,因此将我的第一个建议(以您的目的为准)的结果插入临时表中是最明智的选择,根据你的更新。

+0

结果是,我想将其添加到用户当前的出价金额。 – mrblah 2009-10-26 14:44:27

+0

我已添加到我的答案。 – 2009-10-26 20:27:09

1
CREATE TABLE dbo.ProductBids(ProductID INT, UserID INT, Created DATETIME); 

CREATE TABLE dbo.Users(UserID INT, TotalBids INT); 

INSERT dbo.Users(UserID) SELECT 1 UNION ALL SELECT 2; 

INSERT dbo.ProductBids 
      SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE()-1 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 1, GETDATE() 
UNION ALL SELECT 1, 2, GETDATE() 
UNION ALL SELECT 1, 2, GETDATE() 
UNION ALL SELECT 1, 2, GETDATE(); 

UPDATE u 
SET TotalBids = x.TotalBids 
FROM 
(
    SELECT 
     UserID, 
     TotalBids = SUM(CASE WHEN c > 10 THEN 10 ELSE c END) 
    FROM 
    (
     SELECT 
      UserID, 
      c = COUNT(*) 
     FROM 
      dbo.ProductBids 
     GROUP BY 
      UserID, 
      DATEADD(DAY, 0, DATEDIFF(DAY, 0, Created)) 
    ) AS y 
    GROUP BY UserID 
) AS x 
INNER JOIN dbo.Users AS u 
ON x.UserID = u.UserID; 

GO 

SELECT UserID, TotalBids FROM dbo.Users; 

GO 

DROP TABLE dbo.Users, dbo.ProductBids; 

然而,一般来说,当你从现有的数据中获得信息时,我总是皱着眉头来存储这个总数。问题是Users表中的数据只有在运行UPDATE语句和下一次发生在ProductBids表中的任何DML操作之间保证准确。

+0

应该实现为一个查看++ – 2009-10-26 04:15:50

+0

其丰富的查询,并且我不想在每次我列出页面上的10个用户时动态运行。 – mrblah 2009-10-26 14:45:04

+0

但是,如果它不准确可以吗?也许考虑索引视图。 – 2009-10-26 15:03:09