BookmarkSubscribeRSS Feed
iced_tea
Obsidian | Level 7

Hello Community,

Trying something new where I am reusing the 1st solution from the following: https://stackoverflow.com/questions/15783315/combine-consecutive-date-ranges by modifying it to be in PROC SQL instead of SQL Server. This is what they have:

;with cte as (
   select a.employmentid, a.startdate, a.enddate
     from Tbl a
left join Tbl b on a.employmentid=b.employmentid and a.startdate-1=b.enddate
    where b.employmentid is null
    union all
   select a.employmentid, a.startdate, b.enddate
     from cte a
     join Tbl b on a.employmentid=b.employmentid and b.startdate-1=a.enddate
)
   select employmentid,
          startdate,
          nullif(max(isnull(enddate,'32121231')),'32121231') enddate
     from cte
 group by employmentid, startdate
 order by employmentid

  This is how I've attempted to modify it:

proc sql;
create view cte as (
   select a.employmentid, a.startdate, a.enddate
     from Tbl a
left join Tbl b on a.employmentid=b.employmentid and a.startdate-1=b.enddate
    where b.employmentid is null
    union all
   select a.employmentid, a.startdate, b.enddate
     from cte a
     join Tbl b on a.employmentid=b.employmentid and b.startdate-1=a.enddate
)
   select employmentid,
          startdate,
          nullif(max(isnull(enddate,'32121231')),'32121231') enddate
     from cte
 group by employmentid, startdate
 order by employmentid;
quit;

SAS doesn't like the last select piece. "Syntax error, expecting one of the following: EXCEPT, INTERSECT, UNION."

Any ideas as to what I'm doing wrong here? I think it is something to do with not translating SQL's  WITH clause correctly.

Thank you!

9 REPLIES 9
SASKiwi
PROC Star

This isn't valid SAS SQL:

   select employmentid,
          startdate,
          nullif(max(isnull(enddate,'32121231')),'32121231') enddate
     from cte

I suggest you just try this:

   select employmentid,
          startdate,
          enddate
     from cte

If you need to deal with missing values you can always do it afterwards or if necessary use an equivalent CASE statement.

iced_tea
Obsidian | Level 7
Thank you for taking a look. Dropping the nullif piece didn't work as it gives the same error. The last SELECT is underlined and the message reads:
"Syntax error, expecting one of the following: EXCEPT, INTERSECT, UNION."
Kurt_Bremser
Super User

Start with this:

proc sql;
create view v_cte as
  select a.employmentid, a.startdate, a.enddate
  from Tbl a
  left join Tbl b on a.employmentid=b.employmentid and a.startdate-1=b.enddate
  where b.employmentid is null
  union all
  select a.employmentid, a.startdate, b.enddate
     from cte a
     join Tbl b on a.employmentid=b.employmentid and b.startdate-1=a.enddate
;
create table want as
  select
    employmentid,
    startdate,
    enddate
  from v_cte
  group by employmentid, startdate
  order by employmentid
;
quit;
iced_tea
Obsidian | Level 7

Thank you for taking a look Kurt. This produces the following error:

"The current reference to SQL View WORK.v_cte has exceeded PROC SQL's limit of 50 references
to a single view in a SQL statement. Please check to make sure that these references are not
part of a recursive situation."

This means something got stuck in an infinite loop, no?

iced_tea
Obsidian | Level 7

Thank you. Do you know where in the code it is doing a circular reference?

proc sql;
create view v_cte as
  select a.employmentid, a.startdate, a.enddate
  from Tbl a
  left join Tbl b on a.employmentid=b.employmentid and a.startdate-1=b.enddate
  where b.employmentid is null
  union all
  select a.employmentid, a.startdate, b.enddate
     from cte a
     join Tbl b on a.employmentid=b.employmentid and b.startdate-1=a.enddate
;
create table want as
  select
    employmentid,
    startdate,
    enddate
  from v_cte
  group by employmentid, startdate
  order by employmentid
;
quit;
LinusH
Tourmaline | Level 20

In SAS SQL, isnull corresponds to coalesce.

Max works in SAS.

nullif can be mimiced as @SASKiwi stated using case when else logic.

 

 

Data never sleeps
PGStats
Opal | Level 21

For up to 5 chained periods per sequence, in SAS/SQL you could do (example data from Stackoverflow reference):

 

data have;
infile datalines dsd;
input id (dStart dEnd) (:yymmdd10.);
format dStart dEnd yymmdd10.;
datalines;
5, 2007-12-03, 2011-08-26
5, 2013-05-02, .
30, 2006-10-02, 2011-01-16
30, 2011-01-17, 2012-08-12
30, 2012-08-13, .
66, 2007-09-24, .
;

proc sql;
select 
    a.id, 
    a.dStart,
    case 
        when e.id then e.dEnd
        when d.id then d.dEnd
        when c.id then c.dEnd
        when b.id then b.dEnd
        else a.dEnd 
    end as dEnd         format=yymmdd10.
from
    have as a left join
    have as b on a.id=b.id and a.dEnd+1=b.dStart left join
    have as c on a.id=c.id and b.dEnd+1=c.dStart left join
    have as d on a.id=d.id and c.dEnd+1=d.dStart left join
    have as e on a.id=e.id and d.dEnd+1=e.dStart
group by a.id, calculated dEnd
having a.dStart = min(a.dStart) ;
quit;

PGStats_0-1614191777122.png

 

PG

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

Mastering the WHERE Clause in PROC SQL

SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.

Find more tutorials on the SAS Users YouTube channel.

Discussion stats
  • 9 replies
  • 3307 views
  • 0 likes
  • 5 in conversation