【问题标题】:PROC SQL - Transposing Data into Columns when Condition MetPROC SQL - 满足条件时将数据转换为列
【发布时间】:2019-08-22 13:10:59
【问题描述】:

我的数据结构如下,每个唯一 ID 都会有一行显示当月最后一天的余额:

ID      Day_Key    Balance
23412   20171229   50000
23412   20180131   45000
23412   20180228   40000   
27435   20171229   100000    
27435   20180131   80000
27435   20180228   60000

我想创建一个表,其中每个唯一 ID 显示在一行上,列表示每个月的余额,如下所示:

ID     DEC17    JAN 18    FEB18
23412  50000    45000     40000
27435  100000   80000     60000

**更新*

我当前的代码如下所示

PROC SQL;
CREATE TABLE BAL_TRANSPOSE AS 
SELECT DISTINCT ID,
        MAX(SUB_EY17) AS EY17,
      MAX(SUB_JAN18) AS JAN18,
      MAX(SUB_FEB18) AS FEB18,
      MAX(SUB_MAR18) AS MAR18,
      MAX(SUB_APR18) AS APR18,
      MAX(SUB_MAY18) AS MAY18,
      MAX(SUB_JUN18) AS JUN18,
      MAX(SUB_JUL18) AS JUL18,
      MAX(SUB_AUG18) AS AUG18,
      MAX(SUB_SEP18) AS SEP18,
      MAX(SUB_OCT18) AS OCT18,
      MAX(SUB_NOV18) AS NOV18,
      MAX(SUB_EY18) AS EY18
FROM (SELECT DISTINCT ID,
    CASE WHEN DAY_KEY = 20171229 THEN OUTSTANDING_BALANCE END AS SUB_EY17,
    CASE WHEN DAY_KEY = 20180131 THEN OUTSTANDING_BALANCE END AS SUB_JAN18,
    CASE WHEN DAY_KEY = 20180228 THEN OUTSTANDING_BALANCE END AS SUB_FEB18,
    CASE WHEN DAY_KEY = 20180330 THEN OUTSTANDING_BALANCE END AS SUB_MAR18,
    CASE WHEN DAY_KEY = 20180430 THEN OUTSTANDING_BALANCE END AS SUB_APR18,
    CASE WHEN DAY_KEY = 20180531 THEN OUTSTANDING_BALANCE END AS SUB_MAY18,
    CASE WHEN DAY_KEY = 20180629 THEN OUTSTANDING_BALANCE END AS SUB_JUN18,
    CASE WHEN DAY_KEY = 20180731 THEN OUTSTANDING_BALANCE END AS SUB_JUL18,
    CASE WHEN DAY_KEY = 20180831 THEN OUTSTANDING_BALANCE END AS SUB_AUG18,
    CASE WHEN DAY_KEY = 20180928 THEN OUTSTANDING_BALANCE END AS SUB_SEP18,
    CASE WHEN DAY_KEY = 20181031 THEN OUTSTANDING_BALANCE END AS SUB_OCT18,
    CASE WHEN DAY_KEY = 20181130 THEN OUTSTANDING_BALANCE END AS SUB_NOV18,
    CASE WHEN DAY_KEY = 20181231 THEN OUTSTANDING_BALANCE END AS SUB_EY18
FROM TABLE1) AS SUB
GROUP BY ID;   
QUIT;

新列已创建,但仅显示空值。以下是我看到的结果(为便于阅读而进行了修剪)。该查询返回超过 1m 条记录,但据我所知,所有记录都有 0 个值。我已经测试过数据并且知道每个 ID 都应该有每个 day_key 的值。

ID      EY17    JAN18        FEB18       MAR18         APR18   
1111    -       -            -            -            -
2222    -       -            -            -            -
3333    -       -            -            -            -
4444    -       -            -            -            -
5555    -       -            -            -            -

【问题讨论】:

  • 这是一个非常简单的 PROC TRANSPOSE stats.idre.ucla.edu/sas/modules/…
  • 你能解释一下标题的“条件满足”部分吗?
  • 抱歉 Reeza,我对 SAS 不太熟悉,因此尝试在 PROC SQL 中编写代码。在您的链接上进行了几次尝试,但我无法掌握它的窍门......
  • Richard - 我所说的“条件”是指对于 day_key 的每个新实例,创建一个存储当天余额的列。

标签: sql sas case proc-sql


【解决方案1】:

原始 SQL 可以与聚合函数一起使用,因为该过程称为条件聚合,当列已知且数量很少时,这是一种将数据从长旋转到宽的常见形式。

PROC SQL;
   CREATE TABLE BAL_TRANSPOSE AS 
   SELECT ID,
          MAX(CASE WHEN DAY_KEY = 20171229 THEN BALANCE END) AS DEC17,
          MAX(CASE WHEN DAY_KEY = 20180131 THEN BALANCE END) AS JAN18,
          MAX(CASE WHEN DAY_KEY = 20180228 THEN BALANCE END) AS FEB18
   FROM TABLE1
   GROUP BY ID    
QUIT;

但是,对于 SAS proc sql,您可能需要使用子查询:

PROC SQL;
   CREATE TABLE BAL_TRANSPOSE AS 
   SELECT ID, 
          MAX(SUB_DEC17) AS DEC17,
          MAX(SUB_JAN18) AS JAN18,
          MAX(SUB_FEB18) AS FEB18
   FROM (SELECT ID,
                CASE WHEN DAY_KEY = 20171229 THEN BALANCE END AS SUB_DEC17,
                CASE WHEN DAY_KEY = 20180131 THEN BALANCE END AS SUB_JAN18,
                CASE WHEN DAY_KEY = 20180228 THEN BALANCE END AS SUB_FEB18
         FROM TABLE1) AS sub
   GROUP BY ID    
QUIT;

实际上,您的原始查询应该出错了,因为您在 SELECT 中包含了未出现在 GROUP BY 中的非聚合列 - 违反了 ANSI-SQL 标准。 SAS 可能会将您尝试的聚合查询转换为单元级别(即,忽略 GROUP BY),如日志注释或警告所示。

【讨论】:

  • SAS 将允许您在选择列表中包含额外的变量,并自动将汇总统计重新合并回详细记录。它会在日志中记录它已为您完成此操作。
  • @Tom,没错!这是一种 SAS 解决方法,由于 OP 的查询没有开发汇总统计信息,因此输出保持在单位级别。但是所有符合的主要 RDBMS 都将因 OP 的尝试查询而失败。对于尝试使用相同 SAS 查询来后端外部数据库连接的未来读者来说,这一点很重要。
  • @Parfait,感谢您的帮助。我已经用我的新代码更新了我的原始帖子,但是我仍然在提取这些值时遇到问题?
  • DAY_KEY 是字符串还是数字类型?如果是前者,请在 CASE 语句中添加引号。
  • DAY_KEY 是数字,我已将您的建议的结果添加到 OP。感谢您对此提供的所有帮助。
【解决方案2】:

Proc 转置最适合这种情况。您也与 SQL 关系密切。您所需要的只是通过添加聚合函数来进行微小的更改。

 PROC SQL;
  CREATE TABLE BAL_TRANSPOSE AS 
  SELECT ID,
       max(CASE WHEN DAY_KEY = 20171229 THEN BALANCE END) AS DEC17,
       max(CASE WHEN DAY_KEY = 20180131 THEN BALANCE END) AS JAN18,
        max(CASE WHEN DAY_KEY = 20180228 THEN BALANCE END) AS FEB18,
  FROM TABLE1
  GROUP BY ID    
 QUIT;

【讨论】:

  • 谢谢 Alexey,我已经尝试过了,但是现在我没有收到任何通过的值?
【解决方案3】:

将时间维度转换为列标识符通常意味着需要报告而不是数据转换。

考虑使用TABULATE 或REPORT

data have;
attrib 
  id length=8
  day_key length=4 informat=yymmdd8. format=yymmdd10.
  balance length=8 format=comma12.
;
input
ID      Day_Key    Balance; datalines;
23412   20171229   50000
23412   20180131   45000
23412   20180228   40000   
27435   20171229   100000    
27435   20180131   80000
27435   20180228   60000
run;

ods html;

proc tabulate data=have;
  class id day_key;
  var balance;
  format day_key monyy7.;
  table 
    id = ''
    ,
    day_key='' * balance='' * max='' * f=comma12.
    /
    box = 'id'
  ;
run;

** -- OR --;

proc report data=have;
  columns id (balance, day_key);
  define id / group;
  define day_key / ' ' across format=monyy7.;
  define balance / ' ' analysis max;
run;

【讨论】:

  • 不错!我已将此解决方案保存到我的个人图书馆!
【解决方案4】:

你可以使用proc转置:

/*prepare*/
data g;
input ID  Day_Key   Balance;
datalines4;
23412   20171229   50000
23412   20180131   45000
23412   20180228   40000   
27435   20171229   100000    
27435   20180131   80000
27435   20180228   60000
;;;;
run;

proc sort ;
by id;
run;

/*you need*/
proc transpose data=g out=g2;
id Day_Key;
by id;
run;

你会得到:

+-------+----------+----------+----------+
|  ID   | 20171229 | 20180131 | 20180228 |
+-------+----------+----------+----------+
| 23412 |    50000 |    45000 |    40000 |
| 27435 |   100000 |    80000 |    60000 |
+-------+----------+----------+----------+

所以,你可以格式化你的日期,给你的名字“JAN18”和例如

此外,您还可以使用IDLABEL。

【讨论】:

  • 也许值得创建一个新变量来使用 IDLABEL 干净地存储变量名称和标签?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-07
  • 1970-01-01
相关资源
最近更新 更多