Sql SAS中的分区运行总计

Sql SAS中的分区运行总计,sql,sum,sas,cumulative-sum,Sql,Sum,Sas,Cumulative Sum,如何为现有数据集创建一个新列,该数据集是由某个标识符分区的现有列的运行总数 ID | Value | New Value ---|--------|-------------------- 1 | 10 | 10 1 | 5 | 15 = 10 + 5 1 | 3 | 18 = 10 + 5 + 3 2 | 45 | 45 2 | 15 | 60 = 45 + 15 我习惯于在SQL(

如何为现有数据集创建一个新列,该数据集是由某个标识符分区的现有列的运行总数

ID |  Value |     New Value
---|--------|--------------------
1  |   10   |     10
1  |   5    |     15  = 10 + 5
1  |   3    |     18  = 10 + 5 + 3
2  |   45   |     45
2  |   15   |     60  = 45 + 15
我习惯于在SQL(Oracle)中使用简单的SUM()OVER()语句来实现这一点,但PROC SQL显然不支持这种语法

如果可能的话,我希望在procsql中实现这一点(我对SQL的经验要比SAS编码丰富得多)

谢谢


Mike。

在数据步骤中,这是通过
sum语句完成的

data want;
  set have;
  by id;
  if first.id then running_total=0;
  running_Total + value;
run;
在PROC SQL中,这是不可能的,除非您有一个排序变量(您可以在其中执行类似的操作):


但是SAS没有按
划分的
概念-SAS数据步骤远比这强大。

我通常使用
数据
步骤而不是
过程sql
在SAS中运行总计。理论上,您可以使用
procsql
和交叉连接来实现这一点,但这在现实世界中并不实用

步骤1:按ID值对数据进行排序

proc sort data=have;
     by ID;
run;
第2步:使用sum语句计算运行总数

data want;
    set have;
    by ID;

    New_Value+Value;

    output;

    if(last.ID) then New_Value = 0;
 run;
解释

分组处理是SAS最强大的工具之一。当您按ID值排序并在数据步骤中对其使用by语句时,您将解锁两个新的特殊布尔变量:
first.
last..
SAS确切地知道一组ID变量在您按组处理时何时开始和停止(实际上,您可以使用一个名为
notsorted
的特殊选项,不必对ID值进行排序,但这是一个高级概念)。在您的案例中,让我们看看它是如何工作的:

ID Value first.ID last.ID
1  10    1        0
1  5     0        0
1  3     0        1
2  45    1        0 
2  15    0        1
如果ID组中只有一个观察结果,
first.ID
last.ID
都是1

SAS中有一种特殊的语句,称为sum语句,用于保留和求和变量。SAS本身就是一种循环语言;每当它执行
数据
步骤时,它只查看一条记录和一条记录。当它到达
数据
步骤的底部并返回顶部时,b开始读取表中的下一条记录,并假设在读取或计算变量值之前,所有变量现在都已丢失。您实际输出的内容是称为程序数据向量的内容。在后台,这就是您正在操作的内容

默认情况下,只有在到达
run
边界后,它才会输出到数据集。如果您明确告诉SAS要输出,则只有在您告诉它时,它才会输出。要累积一个变量,我们要告诉SAS四件事:

  • 保留变量的上一个值(在读取新记录时,不要将其重置为
  • 将变量添加到自身
  • 将值添加到自身后的输出
  • 在我输出并且这是一组ID变量中的最后一个观察值之后,将我的累积变量重置为0
  • 要实现步骤1和2,您可以执行两个选项:

     data want;
          set have;
          retain New_Value;
    
          New_Value = sum(New_Value, Value);
    

    请注意,第二个选项与第一个选项完全相同,但工作量较少。请将其视为一种快捷方式。这称为Sum语句。它看起来在语法上是错误的,但它是一种特殊且非常有用的情况

    为了实现步骤3,我们只需告诉SAS在数据步骤结束后立即输出,而不是默认情况下在数据步骤结束时输出:

    data want;
        set have;
    
        New_Value+Value;
    
        output;
    
    如果按原样运行上面的代码,
    New\u Value
    将无限期地累加,直到它到达文件的最末尾。我们希望在它到达新的ID组后重置此值。我们使用“按组处理”解锁这两个布尔变量,以便在输出后的指定条件下将
    New\u Value
    重置为0:

    data want;
        set have;
        by ID;
    
        New_Value+Value;
    
        output;
    
        if(last.ID) then New_Value = 0;
    run;
    
    New_Value
    将不会重置为0,除非我们是在指定ID组的最后一次观察中。请注意,我们将条件
    if
    语句放在输出语句的下面。如果这是在上面,您将看到以下现象:

    ID Value New_Value first.ID last.ID
    1  10    10         1        0
    1  5     15         0        0
    1  3      0         0        1
    2  45    45         1        0 
    2  15     0         0        1
    
    我们希望在
    新值
    重置为0之前输出累积和


    还有一些其他SAS过程可以用来做类似的事情,但它们是为特定情况而设计的。在这种情况下,您可以重新调整它们的用途来做您想做的事情,但最好在开始重新调整过程用途之前先学习
    数据
    步骤处理。

    Joe-您的答案无论出于何种原因都不起作用,但得到了正确的答案让我在正确的轨道上找到答案。谢谢

    data want;
        set have;
        by id;
        if first.id then running_total = 0;
        if first.id then retained_total = 0;
        running_total = retained_total + value;
        retained_total = running_total;
        retain retained_total;
    run;
    
    还有一个选择:

    data want;
    do until (last.id);
        set have;
        by id;
        new_value + value;
        output;
    end;
    new_value = 0;
    run;
    

    我的数据步骤会产生与此完全相同的结果。您的工作比您需要的要努力一些-为什么有第二个变量?直觉上,您的应该会产生相同的结果-我提供的虚拟集会产生相同的结果-但我正在做的项目中的实际集不会产生相同的结果。对于为什么您的代码不能与我一起工作,我没有一个很好的答案在我的项目中,但由于某种原因,它没有产生所需的结果。听起来您可能有一个问题,即正在运行的total变量已经存在于数据集上(在本例中,
    have
    )?这是唯一的区别,也是拥有第二个变量唯一会改变的事情。对于所描述的问题,这不是一个精心设计的解决方案。此外,如果您拥有SAS/ETS许可,请参阅此处发布的PROC EXPAND解决方案。
    data want;
        set have;
        by id;
        if first.id then running_total = 0;
        if first.id then retained_total = 0;
        running_total = retained_total + value;
        retained_total = running_total;
        retain retained_total;
    run;
    
    data want;
    do until (last.id);
        set have;
        by id;
        new_value + value;
        output;
    end;
    new_value = 0;
    run;