一尘不染

如何复制SAS合并

sql

我有两个表,t1和t2:

t1
  person | visit | code1 | type1
       1       1      50      50 
       1       1      50      50 
       1       2      75      50

t2
  person | visit | code2 | type2
       1       1      50      50 
       1       1      50      50 
       1       1      50      50

SAS运行以下代码时:

   DATA t3;
     MERGE t1 t2;
     BY person visit;

   RUN;

它生成以下数据集:

       person | visit | code1 | type1 | code2 | type2
            1       1      50      50      50      50
            1       1      50      50      50      50
            1       1      50      50      50      50
            1       2      75      50

我想在SQL中复制此过程,我的想法是使用完全外部联接。除非有重复的行,否则此方法有效。当像上面的示例一样有重复的行时,完整的外部联接将产生下表:

       person | visit | code1 | type1 | code2 | type2
            1       1      50      50      50      50
            1       1      50      50      50      50
            1       1      50      50      50      50
            1       1      50      50      50      50
            1       1      50      50      50      50
            1       1      50      50      50      50
            1       2      75      50

我想知道如何使SQl表与SAS表匹配。


阅读 134

收藏
2021-03-17

共1个答案

一尘不染

戈登的答案很接近。但它遗漏了一点。这是它的输出:

person  visit   code1   type1   seqnum  person  visit   code2   type2   seqnum
1       1       1       1       1       1       1       1       1       1
1       1       2       2       2       1       1       2       2       2
NULL    NULL    NULL    NULL    NULL    1       1       3       3       3
1       2       1       3       1       NULL    NULL    NULL    NULL    NULL

第三行的空值是不正确的,而第四行的空值是正确的。

据我所知,在SQL中,除了将事情分解成几个查询外,没有什么好方法。我认为有五种可能性:

  • 匹配的人/访客,匹配的序号
  • 匹配的人/访问者,Left有更多的后继
  • 匹配的人/访问者,Right有更多的序列
  • 左有无与伦比的人/访客
  • 权利拥有无与伦比的人/访客

我认为后两个可以在一个查询中使用,但我认为第二个和第三个必须是单独的查询。当然,您可以将所有内容结合在一起。

因此,这是一个示例,使用一些更适合查看正在发生的情况的临时表。请注意,即使它们是“多余”的,现在也为code1和填充了第三行type1。我仅添加了五个条件中的三个-
您在最初的示例中具有三个-但其他两个条件并不难。

请注意,这是什么一个例子 在SAS更快-
因为SAS具有逐行概念,即它能够在同一时间去一行。对于大型表,SQL往往会花费更长的时间,除非可以非常整洁地对事物进行分区并拥有非常好的索引-
甚至到那时,我还从未见过SQL DBA可以像SAS那样在任何地方做得很好问题类型。这当然是您必须接受的-SQL具有自己的优势,其中之一可能是价格…

这是我的示例代码。我确信它不是非常优雅,希望SQL专家之一可以对其进行改进。这是为了在SQL
Server(使用表变量)中工作而编写的,假设其他东西实现了窗口化,则同样的东西应该在其他变体中进行一些更改(以使用临时表)。(SAS当然不能做这件事-
甚至FedSQL都实现ANSI
1999,而不是ANSI2008。)这是基于Gordon的初始查询,然后在末尾用其他位进行修改的。任何想要改善此问题的人都可以随意编辑和/或复制到新的/现有的答案中。

declare @t1 table (person INT, visit INT, code1 INT, type1 INT);
declare @t2 table (person INT, visit INT, code2 INT, type2 INT);


insert into @t1 values (1,1,1,1)
insert into @t1 values (1,1,2,2)
insert into @t1 values (1,2,1,3)

insert into @t2 values (1,1,1,1)
insert into @t2 values (1,1,2,2)
insert into @t2 values (1,1,3,3)

select coalesce(t1.person, t2.person) as person, coalesce(t1.visit, t2.visit) as visit,
                t1.code1, t1.type1, t2.code2, t2.type2
from (select *,
             row_number() over (partition by person, visit order by type1) as seqnum
      from @t1
     ) t1 inner join
     (select *,
             row_number() over (partition by person, visit order by type2) as seqnum
      from @t2
     ) t2
     on t1.person = t2.person and t1.visit = t2.visit and
        t1.seqnum = t2.seqnum
 union all

select coalesce(t1.person, t2.person) as person, coalesce(t1.visit, t2.visit) as visit,
                t1.code1, t1.type1, t2.code2, t2.type2
from (
      (select person, visit, MAX(seqnum) as max_rownum from (
        select person, visit, 
             row_number() over (partition by person, visit order by type1) as seqnum
      from @t1) t1_f 
      group by person, visit
     ) t1_m inner join
     (select *, row_number() over (partition by person, visit order by type1) as seqnum
       from @t1
      ) t1 
        on t1.person=t1_m.person and t1.visit=t1_m.visit
        and t1.seqnum=t1_m.max_rownum
        inner join
     (select *,
             row_number() over (partition by person, visit order by type2) as seqnum
      from @t2
     ) t2
     on t1.person = t2.person and t1.visit = t2.visit and
        t1.seqnum < t2.seqnum 
     )
 union all
 select t1.person, t1.visit, t1.code1, t1.type1, t2.code2, t2.type2
     from @t1 t1 left join @t2 t2
    on t2.person=t1.person and t2.visit=t1.visit
    where t2.code2 is null
2021-03-17