[prev in list] [next in list] [prev in thread] [next in thread] 

List:       sas-l
Subject:    SAS-L: Transposing rows to columns using proc sql partitioning
From:       Roger Deangelis <roger_deangelis () COMCAST ! NET>
Date:       2022-01-12 15:27:27
Message-ID: 9844614661638294.WA.rogerdeangeliscomcast.net () listserv ! uga ! edu
[Download RAW message or body]

%let pgm=utl-transposing-rows-to-columns-using-proc-sql-partitioning;

Transposing rows to columns using proc sql partitioning

github
https://tinyurl.com/47ncxbvy
https://github.com/rogerjdeangelis/utl-transposing-rows-to-columns-using-proc-sql-partitioning

I realize there is a simple non SQL solution, however this is a pure sql solution.
It may not be as slow as you think.

This is the case where you do not have column names in your input table

SAS does not directly supoort partitonibg however there is a way to doit.
Python and R Sqlite do support partitioning

Example of R and Python partitoning
select nam, score, row_number() over (partition by nam) as partition from havSql

  Two Solutions
        1. Without SQL arrays
        2. With SQL arrays

/*                   _
(_)_ __  _ __  _   _| |_
| | `_ \| `_ \| | | | __|
| | | | | |_) | |_| | |_
|_|_| |_| .__/ \__,_|\__|
        |_|
*/

libname sd1 "d:/sd1";

options validvarname=upcase;

data sd1.have;

 do nam = "JANE ", "MIKE", "MIKE","ROGER", "ROGER","ROGER" ;
    score=50 + int(50*uniform(1234));
    output;
 end;

run;quit;

/*
Up to 40 obs SD1.HAVE total obs=6 12JAN2022:07:06:53

Obs     NAM     SCORE

 1     JANE       62
 2     MIKE       54
 3     MIKE       69
 4     ROGER      54
 5     ROGER      62
 6     ROGER      54

INTERMEDIATE PARTITION VIEW WITH PARTITIONS

Up to 40 obs from PARTITION total obs=6 12JAN2022:07:34:04

     Obs    PARTITION     NAM     SCORE

       1        1        JANE       62
       2        1        MIKE       54
       3        1        ROGER      54
       4        2        MIKE       69
       5        2        ROGER      62
       6        3        ROGER      54
             _               _
  ___  _   _| |_ _ __  _   _| |_
 / _ \| | | | __| `_ \| | | | __|
| (_) | |_| | |_| |_) | |_| | |_
 \___/ \__,_|\__| .__/ \__,_|\__|
                |_|
*/

Up to 40 obs from WANT total obs=3 12JAN2022:07:35:28

Obs     NAM     SCORE1    SCORE2    SCORE3

 1     JANE       62         .         .
 2     MIKE       54        69         .
 3     ROGER      54        62        54


/*
 _ __  _ __ ___   ___ ___  ___ ___
| `_ \| `__/ _ \ / __/ _ \/ __/ __|
| |_) | | | (_) | (_|  __/\__ \__ \
| .__/|_|  \___/ \___\___||___/___/
|_|
 _             __                _
/ | __      __/ /__    ___  __ _| |   __ _ _ __ _ __ __ _ _   _
| | \ \ /\ / / / _ \  / __|/ _` | |  / _` | `__| `__/ _` | | | |
| |  \ V  V / / (_) | \__ \ (_| | | | (_| | |  | | | (_| | |_| |
|_|   \_/\_/_/ \___/  |___/\__, |_|  \__,_|_|  |_|  \__,_|\__, |
                              |_|                         |___/
*/

* safe use of undocumented monotonic function?;
* max is needed because of the group by;

proc sql;

   create view partition as
      select monotonic() as partition , nam, score from sd1.have where nam="JANE" union
      select monotonic() as partition , nam, score from sd1.have where nam="MIKE " union
      select monotonic() as partition , nam, score from sd1.have where nam="ROGER"
   ;
   create table want as select
      nam
     ,max(case when partition=1 then score else . end) as score1
     ,max(case when partition=2 then score else . end) as score2
     ,max(case when partition=3 then score else . end) as score3
   from
     partition
   group
     by nam
;quit;

/*___                         _
|___ \  __      __  ___  __ _| |   __ _ _ __ _ __ __ _ _   _
  __) | \ \ /\ / / / __|/ _` | |  / _` | `__| `__/ _` | | | |
 / __/   \ V  V /  \__ \ (_| | | | (_| | |  | | | (_| | |_| |
|_____|   \_/\_/   |___/\__, |_|  \__,_|_|  |_|  \__,_|\__, |
                           |_|                         |___/
*/
THIS IS A MORE GENERAL SOLUTION

* IN CASE YOU RERUN;
%symdel _nam1 _nam2 _nam3 _namn _part1 _part2 _part3 _partn / nowarn;

/* NOTE  %arraydelete(_nam) will also delete all the _nam macro variables */

*LOAD _NAM ARRAY;
proc sql; select distinct nam into: _nam1- from sd1.have ;quit;
%let _namn=&sqlobs;
%put &_namn;

* Load partition array;
%array(_part,values=1-&_namn);

/*
Macro arrays
%utlnopts;

%put &=_part1;  _part1=1
%put &=_part2;  _part2=2
%put &=_part3;  _part3=3
%put &=_partn;  _partn=3

%put &=_nam1;   _NAM1=JANE
%put &=_nam2;   _NAM2=MIKE
%put &=_nam3;   _NAM3=ROGER
%put &=_namn;   _NAMN=3

%utlopts;
*/

proc sql;
    create view partition as
        %do_over(_nam,phrase=%str(
          select monotonic() as partition , nam, score from sd1.have where nam="?"), between=union );
    create table want as select nam
        %do_over(_part,phrase=%str(
          ,max(case when partition=? then score else . end) as score?))
    from partition
    group by nam;
;quit;

/*              _
  ___ _ __   __| |
 / _ \ `_ \ / _` |
|  __/ | | | (_| |
 \___|_| |_|\__,_|

*/
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic