SQL中的条件求和

时间:2012-03-14 20:30:38

标签: sql sql-server

我无法让查询工作。我想要做的是按用户ID计算一个计数器,但条件是。

目前我的查询提供以下输出。

User ID  EndDate    Date       Index
 123      5/1/12   1/1/12       -1
 123      5/1/12   1/25/12       1
 123      5/1/12   2/13/12      -1
 456      4/1/12   1/18/12      -1
 456      4/1/12   2/15/12      -1
 456      4/1/12   2/18/12       1

我想用这个列表做的是按用户ID加上索引但是有一个catch。索引必须按日期顺序求和,索引的最小值为-1,max为1,因此值只能为-1,0,1。因此,对于用户123,进程将为-1,然后您添加1然后添加-1以获得-1的最终总和。但是对于用户456,你从-1开始,然后你再次得到-1但是总和必须保持-1然后你有1,所以最后的总和是0.以下是我一直试图做的但是我无法想象出来。我真的很感激一些帮助。

DECLARE @Period char(6)
DECLARE @StatusCount int
    SET @Period = '201201'
    SET @StatusCount = 0

SELECT     Q1.UserID, Q1.End_Date,
            Sum(Case 
                When Index = -1 Then Case When @IndexCount >=0 Then @IndexCount - 1 Else @IndexCount + 0 End
                When Index = 1 Then Case When @IndexCount <=0 Then @IndexCount + 1 Else @IndexCount + 0 End
            END) as FinalIndex

FROM 
(
    (SELECT    UserID,  End_Date, Enter_Dt, 1 as Index
    FROM        UserTable 
    WHERE       (Code in ('A', 'B') and PRD = @Period)
    GROUP BY    UserID,  End_Date, Enter_Dt)

         UNION

    (SELECT     UserID,  End_Date, Enter_Dt, -1 as Index
    FROM         UserTable 
    WHERE     (Code in ('C', 'D') and PRD = @Period)
    GROUP BY    UserID,  End_Date, Enter_Dt)
) as Q1

GROUP BY Q1.UserID, Q1.End_Date
ORDER BY Q1.UserID ASC, Q1.End_Date ASC

我认为我的主要问题是我无法弄清楚如何正确积累指数。我无法让IndexCount记住之前的值,然后从0开始再次使用下一个用户ID

我使用此查询得到的结果是

User ID    EndDate       Index
 123       5/01/12       -1
 456       4/01/12       -1

这只是汇总指数

3 个答案:

答案 0 :(得分:0)

听起来你需要定义循环序列:

http://www.postgresql.org/docs/8.1/static/sql-createsequence.html

这将创建您在问题中描述的效果,循环-1,0,1作为行迭代。您可以在选择中或在表中插入记录时实现此目的。

答案 1 :(得分:0)

我将在此处通过userID解决方案说明运行总计,为了清晰起见,省略了查询的其他详细信息。基本上,添加一个IndexRT列,用一个为每个新用户ID重置的运行总计填充它。

编辑:将运行总数限制为-1,0,1

create table #temp(userID int, [Index] int, IndexRT int) 
insert into #temp (userID,[Index]) values (123,-1) , (123,1) , (123,-1) , (456,-1) , (456,-1) , (456,1)  
declare @rt int; set @rt=0;

with a as (
    select select TOP 100 percent *
    ,r=ROW_NUMBER()over(partition by userID order by userID) 
    from #temp order by userID,ROW_NUMBER()over(partition by userID order by userID) 
) 
update a set @rt = [IndexRT] = case when case when r=1 then [Index] else @rt + [Index] end between -1 and 1
then case when r=1 then [Index] else @rt + [Index] end
else @rt
end

select * from #temp;
go 
drop table #temp;

结果:

userID      Index       IndexRT
----------- ----------- -----------
123         -1          -1
123         1           0
123         -1          -1
456         -1          -1
456         -1          -1
456         1           0

答案 2 :(得分:0)

这使用游标,似乎在SQL 2005中工作(我建议彻底检查你的结果,以防我错过了一些明显的东西)。

作为免责声明,大多数数据库专家会告诉您游标是可怕的,低效的,不应该使用。是的 - 你应该尽可能使用直接的SELECT语句。但是:(1)我不知道这种类型的累积有一个简单的SELECT语句,(2)对于任何必须维护代码的人来说,这将是一个更易读的解决方案。如果您的数据集不是非常大(并且您不希望它增长太多),那么游标应该没问题。

请注意,我已将“Table3”替换为整个FROM语句;我导入了您的示例表来创建此示例。这里要注意的关键要素是我首先按用户ID排序,然后按DECLARE csrOrdered CURSOR语句中的日期排序。因此,您只需要在游标定义中替换自己的已排序SQL语句。

CREATE TABLE #sumResult (
    [User ID] int,
    [Sum Result] int
)

DECLARE csrOrdered CURSOR FOR
SELECT [User Id], [Index] FROM Table3 -- <- your table name goes here!
ORDER BY [User ID], Date, EndDate

DECLARE @uid int
DECLARE @index int
DECLARE @lastUid int
DECLARE @curSum int

SET @uid=0
SET @index=0
SET @lastUid=0
SET @curSum=0

OPEN csrOrdered

FETCH NEXT FROM csrOrdered
INTO @uid, @index

WHILE @@FETCH_STATUS=0
BEGIN
    --Are we working on a new User ID? Then reset the sum and insert the last group into the table.
    IF @uid<>@lastUid BEGIN
        --Don't do an insert if we just got into the loop
         IF @lastUid <> 0 BEGIN
            INSERT INTO #sumResult ([User ID], [Sum Result]) VALUES (@lastUid, @curSum)
         END
        SET @curSum=0
        SET @lastUid=@uid
    END

    SET @curSum = @curSum + @index
    IF @curSum < -1 SET @curSum=-1
    IF @curSum > 1 SET @curSum=1

    FETCH NEXT FROM csrOrdered
    INTO @uid, @index
END

IF @lastUid <> 0 BEGIN
    INSERT INTO #sumResult ([User ID], [Sum Result]) VALUES (@lastUid, @curSum)
END

CLOSE csrOrdered
DEALLOCATE csrOrdered

SELECT * FROM #sumResult

DROP TABLE #sumResult