Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在SAS/SQL中基于行值进行条件计数?_Sql_Excel_Sas - Fatal编程技术网

如何在SAS/SQL中基于行值进行条件计数?

如何在SAS/SQL中基于行值进行条件计数?,sql,excel,sas,Sql,Excel,Sas,重新上传,因为我上一篇文章有一些问题,我不知道我们应该发布样本数据。我是SAS的新手,我有一个问题,我知道如何用Excel解决,但不知道SAS。但是,数据集太大,无法在Excel中合理使用 我有四个变量:id、年份、组名、测试分数 样本数据: id year_start group_name test_score 1 19931231 Red 90 1 19941230 Red

重新上传,因为我上一篇文章有一些问题,我不知道我们应该发布样本数据。我是SAS的新手,我有一个问题,我知道如何用Excel解决,但不知道SAS。但是,数据集太大,无法在Excel中合理使用

我有四个变量:id、年份、组名、测试分数

样本数据:

id     year_start     group_name     test_score
1       19931231          Red            90
1       19941230          Red            89
1       19951231          Red            91
1       19961231          Red            92
2       19930630          Red            85
2       19940629          Red            87
2       19950630          Red            95
3       19950931          Blue           90
3       19960931          Blue           90
4       19930331          Red            95
4       19940331          Red            97
4       19950330          Red            98
4       19960331          Red            95
5       19931231          Red            96
5       19941231          Red            97
我的目标是通过每年的考试分数获得一份排名表。我希望我能够使用PROC秩分数来实现这一点。此函数将通过一个测试来计算顺序,最高的分数为1,第二高的分数为2,依此类推,然后除以观察的总数以提供分数等级。不幸的是,每一行的起始年份差别很大。对于每个id/年组合,我希望从年初开始执行一年回顾,并将该观察结果与在该一年范围内有一年开始的所有其他id进行排序。我对按日历年进行比较不感兴趣,每个id的排名应该是相对于它自己的年份开始的。再加上另一个复杂程度,我希望这个排名由groupname执行

如果有人有一个SQL解决方案,ProcSQL是完全好的

使用上述数据,排名如下所示:

id     year_start     group_name     test_score     rank
1       19931231          Red            90         0.75
1       19941230          Red            89          0.8
1       19951231          Red            91           1
1       19961231          Red            92           1
2       19930630          Red            85           1
2       19940629          Red            87          0.8
2       19950630          Red            95         0.75
3       19950931          Blue           90           1
3       19960931          Blue           90           1
4       19930331          Red            95           1
4       19940331          Red            97          0.2
4       19950330          Red            98          0.2
4       19960331          Red            95         0.333
5       19931231          Red            96         0.25
5       19941231          Red            97         0.667
为了计算第1行的排名

我们首先排除蓝色观察。 然后我们计算在那一年开始前一年内的观测数量,19931231,所以我们有4个观测。 我们计算这些观察中有多少具有较高的test_分数,然后加1以找到当前观察的顺序,因此它是第三高的。 然后,我们将顺序除以总数,得到秩3/4=0.75。 在Excel中,此变量的公式如下所示。假设公式适用于第1行,共有100行。id=A,年份开始=B,组名=C,测试分数=D:

      =(1+countifs(D1:D100,">"&D1, 
                B1:B100,"<="&B1,
                B1:B100,">"&B1-365.25,
                C1:C100, C1))/
       countifs(B1:B100,"<="&B1,
                B1:B100,">"&B1-365.25,
                C1:C100, C1) 
非常感谢你的帮助


如果我读对了,你的例子是不正确的,所以很难确切知道你想做什么。但是试试下面的方法,看看是否有效。您可能需要调整不平等性以打开或关闭,这取决于您是否希望包括截至日期的一年。请注意,您的year_start列需要以SAS日期格式导入才能正常工作。否则,您可以使用inputyear\u start,yymmdd8.对其进行更改

proc sql;
select distinct
    a.id,
    a.year_start,
    a.group_name,
    a.test_score,
    1+sum(case when b.test_score > a.test_score then 1 else 0 end) as rank_num,
    count(b.id) as rank_denom,
    calculated rank_num / calculated rank_denom as rank
from testdata a left join testdata b
    on a.group_name = b.group_name
    and intnx('year',a.year_start,-1,'s') le b.year_start le a.year_start
group by a.id, a.year_start, a.group_name, a.test_score
order by id, year_start;
quit;

请注意,由于没有9/31,我将日期从9/31改为9/30,但由于这可能是有意的,所以只剩下3/30、6/29和12/30,尽管其他日期似乎是季度末。

考虑SQL中的相关计数子查询:

资料

过程SQL

包括供您查看的其他字段

输出

您将注意到,您的预期结果之间存在细微差异,这可能是由于您申请所有年份的季度日365.25,因为SAS的intnx需要一个完整的日历年,天数随着年份的变化而变化


你能解释一下秩函数的逻辑吗?也许做一些示例计算。请阅读,这里是一个学习如何提高问题质量和获得更好答案的好地方。你的例子是错误的。在第一排,排名将是4分之3,因为这是一年内第三高的红色分数。也没有9月31日的日期。哦,哇,你说得对,我道歉。在实际数据中,越低越好,我忘了更新excel公式和输出以匹配我提供的示例。更新..如果您没有在总和中添加1,但使用了大于:sumcase当b.test\u score>=a.test\u score然后1或0结束为rank\u num时,我们的结果将反映出来。例如,19960331记录有两个日期介于那一天和一年前之间:19951231和19950630,您和OP将其计算为1。但是+1作为您的解决方案可能更有效,因为在大多数RDBMS中,联接取代了相关子查询。感谢回复Talmage。您的代码似乎非常合理,但数据集非常大,因此我还没有任何结果。我能否用select distinct*,,替换select distinct a.id、a.year\U start、a.group\U name、a.test\U score?我在实数集中有很多变量。1+和的原因…>。。。与总和相反…>=。。。正在处理领带。请参阅下面我对您的解决方案的评论。我不确定,因为有一个表2的连接。如果我记得的话,SAS SQL抱怨select a.*甚至不需要distinct,但您仍然需要在group by子句中列出非联接变量,并在联接条件中列出联接变量。仅查看输出,就不太正确。请注意,最后一行有一个97,这是并列的所有提供的最高分数,但num_排名可能是2,因为如何处理平局。id 4的最后一行也存在类似的问题,其中num_rank是2而不是1。
data ranktable;   
    infile datalines missover;  
    input id year_start group_name $ test_score; 
    datalines; 
1       19931231          Red            90
1       19941230          Red            89
1       19951231          Red            91
1       19961231          Red            92
2       19930630          Red            85
2       19940629          Red            87
2       19950630          Red            95
3       19950930          Blue           90
3       19960930          Blue           90
4       19930331          Red            95
4       19940331          Red            97
4       19950330          Red            98
4       19960331          Red            95
5       19931231          Red            96
5       19941231          Red            97
; 
run;

data ranktable;
    set ranktable;          
    format year_start date9.;
    year_start = input(put(year_start,z8.),yymmdd8.);
run;
proc sql;
    select r.id, r.year_start, r.group_name, r.test_score, 
           put(intnx('year', r.year_start, -1, 's'), yymmdd10.) as year_ago,
           (select count(*) from ranktable sub 
            where sub.test_score >= r.test_score
            and sub.group_name = r.group_name
            and sub.year_start <= r.year_start
            and sub.year_start >= intnx('year', r.year_start, -1, 's')) as num_rank,    
           (select count(*) from ranktable sub 
            where sub.group_name = r.group_name
            and sub.year_start <= r.year_start
            and sub.year_start >= intnx('year', r.year_start, -1, 's')) as denom_rank,    
           calculated num_rank / calculated denom_rank as rank
    from ranktable r;
run;