【问题标题】:Count where one column in one row is equal to another column in another row计算一行中的一列等于另一行中的另一列
【发布时间】:2021-06-30 00:17:44
【问题描述】:

所以我在下面有一个(简化的)表格。

shift_id employee_Nbr begin_dt end_dt
001 12 1/7/21 1/9/21
002 12 1/9/21 1/14/21
003 15 1/10/21 1/13/21
004 12 1/24/21 1/24/21
005 15 1/13/21 1/14/21

我正在尝试计算同一员工在一行中的end_dt 等于另一行的begin_dt 的次数。在此示例中,计数为 2,因为行 (1&2) 和行 (3&5) 满足此条件。请注意,第 4 行有一个 begin_dt 等于它自己的 end_dt 在这种情况下这对我没有任何意义。我还希望将这些数据放在一个表格中,以便能够回顾而不是简单的计数。有什么建议吗?

【问题讨论】:

  • 这些记录是否有唯一的密钥/标识符?否则,第 4 行也会导致大多数逻辑跳闸,因为您的条件在同一条记录中为真。换句话说,您有第二个未说明的条件:“并且 end_dt 和 begin_dt 不是来自同一记录”,如果没有唯一键,则更难解决。
  • 对不起,我漏掉了!现在包括@Jnevill
  • 应该在我最后的评论中问过。您使用的是什么 RDBMS?
  • 我应该包括的另一件事,我的错。 SAS EG

标签: sql sas


【解决方案1】:

这也可以使用哈希表来实现;这可能是最好的选择。它非常快,不需要排序,并且应该可以避免与重复行相关的数据步骤合并可能遇到的一些问题。

data have;
input shift_id $    employee_nbr $  begin_dt :mmddyy8. end_dt :mmddyy8.;
format begin_dt end_dt date9.;
datalines;
001 12  1/7/21  1/9/21
002 12  1/9/21  1/14/21
003 15  1/10/21 1/13/21
004 12  1/24/21 1/24/21
005 15  1/13/21 1/14/21
;
run;


data want;
  set have;
  
  ** Load up a hash table;
  if _n_ = 1 then do;
    declare hash h_enddt(dataset:'have');
    h_enddt.defineKey('employee_nbr','end_dt');  *these are the "unique key" to qualify a record as matching;
    h_enddt.defineData('employee_nbr');          *this is what to "output" when a match is found (basically, nothing here);
    h_enddt.defineDone();
  end;
  
  ** rc is the return code - 0 is "found", nonzero is "not found";
  ** this does a search in the hash table, using employee_nbr and begin_dt values as the match keys;
  ** So, "current record" begin_dt is compared to "hash table" end_dt, and it returns 0 if it is found;
  rc = h_enddt.find(key:employee_nbr,key:begin_dt);
  
  ** Now, output rows if "current record" begin_dt is not equal to "current record" end_dt, and a match is found (rc=0);
  if begin_dt ne end_dt and rc eq 0 then output;
run;

注意 1/24 日期仅通过拒绝 begin_dt = end_dt; 的行来处理。如果您的拒绝规则不同,您可能需要添加其他内容(如行号变量)以确保您没有得到自我匹配。

【讨论】:

  • 所以这肯定运行得更快,但效果相反(只保持 1/24 的条件,而不是其余的)。老实说,我不知道这里发生了什么(我的大部分经验是 SQL)所以不知道如何解决这个问题。
  • @MichaelAncel 它为我保留了正确的 2 条记录!也许你切换了 eq 和 ne?我会稍微评论一下,希望它更有意义。
  • 我添加了一些cmets!
  • 谢谢!有没有一种简单的方法可以显示记录的两面? I.E 在这个例子中不是抓取 2 条记录而是抓取所有 4 条记录?这种方式让我可以很容易地找到计数,但之后用它做事情会稍微困难一些。
【解决方案2】:

您可以自行加入此表并在您的唯一键上排除:

select t.*
    , t2.*
    , count(case when t2.shift_id is not null then 1 end) over ()
from t
left join t t2
    on (
        t.begin_dt = t2.end_dt
        or t.end_dt = t2.begin_dt
        )
    and t.employee_Nbr = t2.employee_Nbr
    and t.shift_id <> t2.shift_id

这可以为您提供所有匹配的数据以及匹配的行数,但我不完全确定我理解您在计算什么,所以如果您要计算某些内容,请随时告诉我具体的。

【讨论】:

  • 如果我的表名正确,我将“from t”替换为“from rotn as t”和“left join t t2”替换为“left join rotn as t2”是正确的吗?它运行得非常缓慢,并希望确保这是正确的解释。
【解决方案3】:

这可以使用 SAS 数据步执行您想要的操作。 如果您使用的是 SAS viya,则可以通过在 CAS 上运行 Data 步骤来避免使用两种 Proc 排序。

它基本上是用ifself加入表,但不包括shift_id相同的情况。

至于实际计数,您可以只检查表有多少观察值,或者如果您想按员工计数,则运行 proc freq。因为不知道,所以不包括在内。告诉我

data have;
infile datalines dlm='09'x;
input shift_id $    employee_Nbr $  begin_dt    $ end_dt $;
datalines;
001 12  1/7/21  1/9/21
002 12  1/9/21  1/14/21
003 15  1/10/21 1/13/21
004 12  1/24/21 1/24/21
005 15  1/13/21 1/14/21
;
run;

proc sort data=have (rename=(begin_dt=matchdate)) out=have1;
by employee_nbr matchdate;
run;

proc sort data=have (rename=(end_dt=matchdate)) out=have2;
by employee_nbr matchdate;
run;

data want;
    merge have1 (in=s1) have2 (in=s2 rename=(shift_id=shift_id2));
    by employee_nbr matchdate;
    if s1 and s2 and shift_id ne shift_id2; *keep if dates match and it is not the same shift;
run;

【讨论】:

    【解决方案4】:

    你似乎想要:

    select count(*)
    from t join
         t t2
         on t2.employee_Nbr = t.employee_Nbr  and 
            t2.end_dt = t.begin_dt
    where t.end_dt <> t.begin_dt and
          t2.end_dt <> t2.begin_dt;
    

    【讨论】:

      猜你喜欢
      • 2017-08-10
      • 2021-12-01
      • 1970-01-01
      • 2013-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-23
      • 2021-07-15
      相关资源
      最近更新 更多