Sql 将成对的行转换为单行

Sql 将成对的行转换为单行,sql,sas,Sql,Sas,我有一张像这样的桌子 |=========|=====|==================|==============|===========|===========| | PREFIX | ID | PREVIOUS_PREFIX | PREVIOUS_ID | VENDOR_1 | VENDOR_2 | |=========|=====|==================|==============|===========|===========| | A |

我有一张像这样的桌子

|=========|=====|==================|==============|===========|===========|
| PREFIX  | ID  | PREVIOUS_PREFIX  | PREVIOUS_ID  | VENDOR_1  | VENDOR_2  |
|=========|=====|==================|==============|===========|===========|
| A       | 1   |                  |              | JAC       |      BOA  |
|---------|-----|------------------|--------------|-----------|-----------|
| B       | 2   | C                | 99           | LCH       |      GS   |
|---------|-----|------------------|--------------|-----------|-----------|
| B       | 3   | C                | 99           | LCH       |      JPM  |
|---------|-----|------------------|--------------|-----------|-----------|
|=========|=====|==================|==============|===========|===========|
| PREFIX  | ID  | PREVIOUS_PREFIX  | PREVIOUS_ID  | VENDOR_1  | VENDOR_2  |
|=========|=====|==================|==============|===========|===========|
| A       | 1   |                  |              | JAC       |      BOA  |
|---------|-----|------------------|--------------|-----------|-----------|
| C       | 99  |                  |              | GS        |      JPM  |
|---------|-----|------------------|--------------|-----------|-----------|
我需要把它变成一张像这样的桌子

|=========|=====|==================|==============|===========|===========|
| PREFIX  | ID  | PREVIOUS_PREFIX  | PREVIOUS_ID  | VENDOR_1  | VENDOR_2  |
|=========|=====|==================|==============|===========|===========|
| A       | 1   |                  |              | JAC       |      BOA  |
|---------|-----|------------------|--------------|-----------|-----------|
| B       | 2   | C                | 99           | LCH       |      GS   |
|---------|-----|------------------|--------------|-----------|-----------|
| B       | 3   | C                | 99           | LCH       |      JPM  |
|---------|-----|------------------|--------------|-----------|-----------|
|=========|=====|==================|==============|===========|===========|
| PREFIX  | ID  | PREVIOUS_PREFIX  | PREVIOUS_ID  | VENDOR_1  | VENDOR_2  |
|=========|=====|==================|==============|===========|===========|
| A       | 1   |                  |              | JAC       |      BOA  |
|---------|-----|------------------|--------------|-----------|-----------|
| C       | 99  |                  |              | GS        |      JPM  |
|---------|-----|------------------|--------------|-----------|-----------|
即:

  • 对于没有
    PREVIOUS\u前缀
    PREVIOUS\u ID
    的行,该行保持原样
  • 对于带有
    PREVIOUS\u前缀
    PREVIOUS\u ID
    的行:
  • 它创建一个新行,其
    前缀
    上一个\u前缀
    相同,
    ID
    上一个\u ID
    相同,
    供应商\u 1
    供应商\u 2
    是原始行对中不常见的供应商
  • 它删除原始行对

  • 一个稍微简单一点的解决方案是将单个观察扩展为2个观察,并将供应商引入单个变量,同时合并以前的_前缀和前缀以获得新的_前缀,类似地获得id。按此顺序获取数据可以在单个sql中解决您的问题。查看此代码草案

    DATA WANT;
    SET HAVE;
      PREFIX_NEW =COALESCEC(PREVIOUS_PREFIX,PREFIX);
      ID_NEW     =COALESCEC(PREVIOUS_ID    ,ID);
    IF NOT MISSING(VENDOR_1) THEN VENDOR=VENDOR_1; 
    OUTPUT;
    IF NOT MISSING(VENDOR_2) THEN VENDOR=VENDOR_2; 
    OUTPUT;
    RUN;
    
    PROC SQL;
    SELECT PREFIX_NEW
         , ID_NEW
         , MIN(VENDOR) AS VENDOR_1
         , MAX(VENDOR) AS VENDOR_2
    FROM ( SELECT PREFIX_NEW
                , ID_NEW
                , VENDOR
                , COUNT(*) AS COUNTER
             FROM WANT
             GROUP BY 1,2,3
             HAVING COUNTER=1
          )
    ;
    QUIT;
    

    希望这有帮助

    一个稍微简单的解决方案是将单个观察扩展为2个观察,并将供应商纳入单个变量,同时合并以前的_前缀和前缀,以获得新的_前缀,类似地获得id。按此顺序获取数据可以在单个sql中解决您的问题。查看此代码草案

    DATA WANT;
    SET HAVE;
      PREFIX_NEW =COALESCEC(PREVIOUS_PREFIX,PREFIX);
      ID_NEW     =COALESCEC(PREVIOUS_ID    ,ID);
    IF NOT MISSING(VENDOR_1) THEN VENDOR=VENDOR_1; 
    OUTPUT;
    IF NOT MISSING(VENDOR_2) THEN VENDOR=VENDOR_2; 
    OUTPUT;
    RUN;
    
    PROC SQL;
    SELECT PREFIX_NEW
         , ID_NEW
         , MIN(VENDOR) AS VENDOR_1
         , MAX(VENDOR) AS VENDOR_2
    FROM ( SELECT PREFIX_NEW
                , ID_NEW
                , VENDOR
                , COUNT(*) AS COUNTER
             FROM WANT
             GROUP BY 1,2,3
             HAVING COUNTER=1
          )
    ;
    QUIT;
    

    希望这有帮助

    如果您的数据像您所说的那样简单,那么您可以在单个数据步骤中实现这一点。我的假设是,最多只有2行具有重复前缀,并且始终只有2个唯一的供应商id。如果尚未按前缀和ID对数据进行排序,则还需要按前缀和ID对数据进行排序

    主要需求非常简单,可以通过结合使用
    first.
    last.
    来确定是否存在重复的前缀行并设置所需的值。更棘手的部分是供应商逻辑,我创建了一个临时变量来保存所有名称的列表,首先检查当前名称是否已经存在。如果是,则从列表中删除该名称,否则将添加该名称

    我在代码中添加了大量注释来解释正在发生的事情,希望它相当清楚。因为每个前缀最多只有2次迭代(我希望如此),所以我复制了几行代码,而不是创建一个
    do循环

    /* create dummy data */
    data have;
    input Prefix $ ID Previous_Prefix $ Previous_ID Vendor_1 $ Vendor_2 $;
    datalines;
    A 1  .  .  JAC BOA
    B 2  C  99 LCH GS
    B 3  C  99 LCH JPM
    ;
    run;
    
    /* transform data */
    data want;
    set have;
    by prefix id;
    length _vendors $30; /* temporary variable to hold Vendor names */
    retain _vendors; /* keep values from previous row where necessary */
    if first.prefix and last.prefix then output; /* if only one Prefix row then output */
    else do;
        if first.prefix then call missing(_vendors); /* clear vendor list when Prefix changes */
        if index(_vendors, compress(vendor_1)) then _vendors = tranwrd(_vendors,compress(vendor_1),''); /* if Vendor name already exists in list then remove it */
            else call catx(',',_vendors,vendor_1); /* else add Vendor name to comma separated list */
        if index(_vendors, compress(vendor_2)) then _vendors = tranwrd(_vendors,compress(vendor_2),''); /* repeat previous step for Vendor_2 */
            else call catx(',',_vendors,vendor_2);
        if last.prefix then do; /* for last Prefix record, set the required values and output record */
        prefix = previous_prefix; 
        id = previous_id;
        call missing(previous_prefix,previous_id);
        vendor_1 = scan(_vendors,1);
        vendor_2 = scan(_vendors,2);
        output;
        end;
      end;
    drop _vendors; /* drop temporary variable */
    run;
    

    如果您的数据像您所说的那样简单,那么您可以在单个数据步骤中实现这一点。我的假设是,最多只有2行具有重复前缀,并且始终只有2个唯一的供应商id。如果尚未按前缀和ID对数据进行排序,则还需要按前缀和ID对数据进行排序

    主要需求非常简单,可以通过结合使用
    first.
    last.
    来确定是否存在重复的前缀行并设置所需的值。更棘手的部分是供应商逻辑,我创建了一个临时变量来保存所有名称的列表,首先检查当前名称是否已经存在。如果是,则从列表中删除该名称,否则将添加该名称

    我在代码中添加了大量注释来解释正在发生的事情,希望它相当清楚。因为每个前缀最多只有2次迭代(我希望如此),所以我复制了几行代码,而不是创建一个
    do循环

    /* create dummy data */
    data have;
    input Prefix $ ID Previous_Prefix $ Previous_ID Vendor_1 $ Vendor_2 $;
    datalines;
    A 1  .  .  JAC BOA
    B 2  C  99 LCH GS
    B 3  C  99 LCH JPM
    ;
    run;
    
    /* transform data */
    data want;
    set have;
    by prefix id;
    length _vendors $30; /* temporary variable to hold Vendor names */
    retain _vendors; /* keep values from previous row where necessary */
    if first.prefix and last.prefix then output; /* if only one Prefix row then output */
    else do;
        if first.prefix then call missing(_vendors); /* clear vendor list when Prefix changes */
        if index(_vendors, compress(vendor_1)) then _vendors = tranwrd(_vendors,compress(vendor_1),''); /* if Vendor name already exists in list then remove it */
            else call catx(',',_vendors,vendor_1); /* else add Vendor name to comma separated list */
        if index(_vendors, compress(vendor_2)) then _vendors = tranwrd(_vendors,compress(vendor_2),''); /* repeat previous step for Vendor_2 */
            else call catx(',',_vendors,vendor_2);
        if last.prefix then do; /* for last Prefix record, set the required values and output record */
        prefix = previous_prefix; 
        id = previous_id;
        call missing(previous_prefix,previous_id);
        vendor_1 = scan(_vendors,1);
        vendor_2 = scan(_vendors,2);
        output;
        end;
      end;
    drop _vendors; /* drop temporary variable */
    run;