How can i convert this SAS code in to SQL Query? - sql

data GC_OUT.ABCD_2;
set GC_OUT.TEST;
index_first_non_zero = verify(ASSIGNED_EMPLOYEE_CD,"0");
ASSIGNED_EMPLOYEE_CD_1 = substr(ASSIGNED_EMPLOYEE_CD, index_first_non_zero);
run;

A direct translation would be something like this:
proc sql;
create table GC_OUT.ABCD_2 as
select *
, verify(ASSIGNED_EMPLOYEE_CD,"0") as index_first_non_zero
, substr(ASSIGNED_EMPLOYEE_CD,calculated index_first_non_zero)
as ASSIGNED_EMPLOYEE_CD_1
from GC_OUT.TEST
;
quit;

Related

How to run a different query if table is empty one month earlier

How to run a different query if the output table is empty.
My current query is:
PROC SQL;
CREATE TABLE WORK.QUERY_FOR_A_KUNDESCORINGRATINGRE AS
SELECT t1.PD,
t1.DATO,
t1.KSRUID
FROM DLKAR.A_KUNDESCORINGRATINGRETRO t1
WHERE t1.KSRUID = 6 AND t1.DATO = '31Aug2022'd;
QUIT;
But I would like to make a conditional statement to run the query again if it is empty but with the filter t1.DATO set to '31Jul2022'd instead of august. So every time the query fails on a given date the query tries again one month earlier.
I hope you can point me in a direction.
Just loop until you get results. You should put an upper bound on the number of times it loops to make sure if will end.
This will require that you create a macro to allow the conditional code generation.
%macro loop(start,months);
%local offset;
PROC SQL;
%do offset=0 to -&months by -1;
CREATE TABLE WORK.QUERY_FOR_A_KUNDESCORINGRATINGRE AS
SELECT t1.PD
, t1.DATO
, t1.KSRUID
FROM DLKAR.A_KUNDESCORINGRATINGRETRO t1
WHERE t1.KSRUID = 6
AND t1.DATO = %sysfunc(intnx(month,&start,&offset,e))
;
%if &sqlobs %then %goto leave;
%end;
%leave:
QUIT;
%mend;
%loop('31AUG2022'd,6)
You could make SQL work a little harder to get what you want. Pull the data back as many months as you want, but only keep the observations that are for the latest month. Now you don't need any looping.
CREATE TABLE WORK.QUERY_FOR_A_KUNDESCORINGRATINGRE AS
SELECT t1.PD
, t1.DATO
, t1.KSRUID
FROM DLKAR.A_KUNDESCORINGRATINGRETRO t1
WHERE t1.KSRUID = 6
AND t1.DATO between %sysfunc(intnx(month,&start,-&offset,e)) and &start
having dato=max(dato)
;
Which method performs better will depend on the data and things like whether or not the data is sorted or indexed.
I assume you always want to query for DATO the last day of the month.
%macro QUERY_FOR_A_KUNDESCORINGRATINGRE(DATO);
** Try with the date given **;
PROC SQL;
CREATE TABLE WORK.QUERY_FOR_A_KUNDESCORINGRATINGRE AS
SELECT t1.PD,
t1.DATO,
t1.KSRUID
FROM DLKAR.A_KUNDESCORINGRATINGRETRO t1
WHERE t1.KSRUID = 6 AND t1.DATO = &DATO;
QUIT;
** Read the result AND any other dataset.
(SASHELP.CLASS is a small dtaset that always exists.) **;
data _null_;
set QUERY_FOR_A_KUNDESCORINGRATINGRE(in=real_result) SASHELP.CLASS;
** If there is any result, the first observation(=row) will be from
that result and real_result will be 1(the SAS coding of True)
otherwise real_result will be 0(the SAS coding of False) **;
if not real_result then do;
** find the last day of the previous month **;
month_earlier = intnx("month", -1, &DATO, 'end');
call execute('%QUERY_FOR_A_KUNDESCORINGRATINGRE('
|| put(month_earlier, 8.) ||');');
end;
** We only need one observation(=row), so stop now **;
stop;
run;
%mend;
%QUERY_FOR_A_KUNDESCORINGRATINGRE('31Aug2022'd);
Disclaimer: I did not test this. It might need some debugging.
Try to run this code, we need loop until you get records
%macro query;
%global DATO;
%let DAT0 = '31Aug2022'd;
%first: PROC SQL;
CREATE TABLE WORK.QUERY_FOR_A_KUNDESCORINGRATINGRE AS
SELECT t1.PD,
t1.DATO,
t1.KSRUID
FROM DLKAR.A_KUNDESCORINGRATINGRETRO t1
WHERE t1.KSRUID = 6 AND t1.DATO = &DATO;
QUIT;
%let dsid = %sysfunc(open (QUERY_FOR_A_KUNDESCORINGRATINGRE))
%let obs = %sysfunc(attrn(&dsid. nlobs));
%let dsid = %sysfunc(close(&dsid.));
%if &obs = 0 %then %do;
data _null_;
call symputx("dato",intnx('m',&dato.,-1));
run;
%goto first;
%end;
%mend;
%query;
Please note: I haven't tested this code would be great if this helps you
If your dataset only contains data for the last day of a month, this solves your problem without iterating at all:
PROC SQL;
CREATE TABLE WORK.QUERY_FOR_A_KUNDESCORINGRATINGRE AS
SELECT t1.PD,
t1.DATO,
t1.KSRUID
FROM DLKAR.A_KUNDESCORINGRATINGRETRO t1
WHERE t1.KSRUID = 6 AND t1.DATO = (
SELECT max(t2.DATO)
FROM DLKAR.A_KUNDESCORINGRATINGRETRO t2
WHERE t2.KSRUID = 6);
QUIT;

Proc Sql Output

Hello i am new in sas and i created sql code, and now i need to redirect the output to /tmp/output.txt.
proc sql;
select (COUNT(IDCUENTACLIENTE)) AS COUNT_of_IDCUENTACLIENTE from S1.CUENTACLIENTE where segmentonivel1 = 'Altas Recientes'
and segmentonivel2 = 'Masivo'
GROUP BY SEGMENTONIVEL1,SEGMENTONIVEL2;
quit;
I tried to put
data _null_;
FILE "/tmp/MyFile.txt";
run;
but is not creating the file.
Some one can help me?
I have a sugestion...
First create a data set using the query. In your code, I have doubts about the GROUP BY you are using. It's run without errors?
Second export to txt file like below
proc sql;
create table work.temp as
select SEGMENTONIVEL1,SEGMENTONIVEL2, (COUNT(IDCUENTACLIENTE)) AS
COUNT_of_IDCUENTACLIENTE from S1.CUENTACLIENTE
where segmentonivel1 = 'Altas Recientes'
and segmentonivel2 = 'Masivo'
GROUP BY SEGMENTONIVEL1,SEGMENTONIVEL2;
quit;
/* code to create TXT file */
data _null_;
FILE "/tmp/MyFile.txt";
set work.temp;
put
SEGMENTONIVEL1
SEGMENTONIVEL2
COUNT_of_IDCUENTACLIENTE;
run;
If you want use the filename definition and you don't want to write the filename into datastep:
proc sql;
create table tableName as
select (COUNT(IDCUENTACLIENTE)) AS COUNT_of_IDCUENTACLIENTE from
S1.CUENTACLIENTE where segmentonivel1 = 'Altas Recientes'
and segmentonivel2 = 'Masivo'
GROUP BY SEGMENTONIVEL1,SEGMENTONIVEL2;
quit;
filename x "c:\temp\teszt.txt";
data _null_;
file x;
set work.tableName;
put COUNT_of_IDCUENTACLIENTE;
run;

SAS data step vs. proc sql dates

I hope someone can help me answer this query: I have two programs, one in proc sql and one in data step. The proc sql works, the data step doesn't. I can't see why?
%let _run_date = '30-jun-2017';
proc sql;
connect to oracle (path='EDRPRD' authdomain='EDRProduction'
buffsize=32767);
create table customer_sets as
select * from connection to oracle (
select *
from customer_set
where start_date <= &_run_date.
and nvl(end_date, &_run_date.) >= &_run_date.
and substr(sets_num,1,2) = 'R9');
quit;
This works fine. However, this doesn't:
libname ora oracle path='EDRPRD' authdomain='EDRProduction' schema='CST';
data customer_sets;
set ora.customer_set;
where start_date le &_run_date. and
coalesce(end_date, &_run_date.) ge &_run_date. and
substr(sets_num,1,2) = "R9";
run;
Can anyone tell me why?
Thanks!
It would have helped to see the error log but, for starters, your date macro variable, as it is used in your data step is interpreted by SAS as a string literal, not a date. In SAS, date literals are enclosed in quotes (single or double) and followed by a d.
You can modify your data step as follows and see if that's any better:
%let _run_date = '30-jun-2017';
data customer_sets;
set ora.customer_set;
where start_date le &_run_date.d and
coalesce(end_date, &_run_date.d) ge &_run_date.d and
substr(sets_num,1,2) = "R9";
run;
If that's not the issue, please post the log containing the error.
EDIT
Here is the above code with a small test data created beforehand:
libname ora (work);
data ora.customer_set;
infile datalines dlm='09'x;
input ID start_date :anydtdte. end_date :anydtdte. sets_num $;
format start_date end_date date.;
datalines;
1 30-may-2017 . R9xxx
2 30-may-2017 31-may-2017 R9xxx
;
run;
%let _run_date = '30-jun-2017';
data customer_sets;
set ora.customer_set;
where start_date le &_run_date.d and
coalesce(end_date, &_run_date.d) ge &_run_date.d and
substr(sets_num,1,2) = "R9";
run;
You can copy paste and run this as-is and you will see that it works fine.

SAS proc sql inside %macro

Firstly I have the following table:
data dataset;
input id $ value;
datalines;
A 1
A 2
A 3
A 4
B 2
B 3
B 4
B 5
C 2
C 4
C 6
C 8
;
run;
I would like to write a macro so that the user can subset the data by giving the id value. I do proc sql inside the macro as follows:
%macro sqlgrp(id=,);
proc sql;
create table output_&id. as
select *
from dataset
where id = '&id.'
;
quit;
%mend;
%sqlgrp(id=A); /*select id=A only*/
I am able to generate the output_A table in the WORK library, however it has zero (0) observations.
Why is this not working?
You need to use double quotes when referring to macro variables.
Current Code
%macro sqlgrp(id=,);
proc sql;
create table output_&id. as
select *
from dataset
where id = '&id.'
;
quit;
%mend;
%sqlgrp(id=A); /*select id=A only*/
Looks for values of id that are literally '&id.'. You can test this by creating this dataset:
data dataset;
input id $ value;
datalines;
&id. 2
A 2
;
run;
Now, use %let to set the value of the macro variable id:
%let id=A;
Run a quick test of the functionality difference between single and double quotes. Notice the titles also contain single and double quotes, so we can see exactly what has happened in the output:
proc sql;
title 'Single Quotes - where id=&id.';
select *
from dataset
where id='&id.';
title "Double Quotes - where id=&id.";
select *
from dataset
where id="&id.";
title;
quit;
Correct Code
%macro sqlgrp(id=,);
proc sql;
create table output_&id. as
select *
from dataset
where id = "&id."
;
quit;
%mend;
%sqlgrp(id=A); /*select id=A only*/
The double quotes allow the macro variable &id to resolve to 'A', which will return results based on your input.
Just a simple rewrite of the previous answer which passes 'in' and 'out' through a signature of the macros
%macro sqlgrp(in=, id=, out=);
proc sql noprint;
create table &out. as select * from &in. where id = "&id.";
quit;
%mend sqlgrp;

Converting CYYMMDD to SAS Date in DB2 via SAS

I'm looking to convert a date that is in the format of CYYMMDD (where C is either 0 for 20th century or 1 for 21st century) to a standard SAS date. This code will be placed inside of a SAS query using 'proc sql' so that it can compare a SAS date against a date stored in DB2.
Example: Input data=1130101, Output='1Jan2013'd
Examples I've tried are:
(substr(t1.'EffectDate'n,4,2)|| '/' || substr(t1.'EffectDate'n,6,2) || '/' || cast(substr(t1.'EffectDate'n,1,3) AS INTEGER) + 1900)
That fails to the cast() function (appears it doesn't exist?)
Also tried:
convert(varchar(10), convert(datetime, right(t1.'EffectDate'n, 6), 12), 101)
But varchar(10) doesn't exist.
My query looks like this:
proc sql;
create table CLAIMS as select
t1.CID,
t1.MID,
t1.DOS
OTHER_TABLE.ChangeDate AS EffectDate
FROM
SOURCE.REJECTED t1
INNER JOIN
EGTASK.OTHER_TABLE
ON
t1.DOS >= *Converted_Date*
[... goes on a couple more lines...]
Where *Converted_Date* is what I need.
(However, I should clarify that this particular query/join doesn't necessarily need to be SQL)
To convert your variable from it's current coded format into a proper SAS date variable, you will need to turn it into a character string and then read the result using the INPUT function. For example:
data _null_;
do EffectDate = 1130101,0130101;
cEffectDate = put(EffectDate,z7.);
if substr(cEffectDate,1,1) = '0'
then SASEffectDate = input('19' || substr(cEffectDate,2),yymmdd8.);
else SASEffectDate = input('20' || substr(cEffectDate,2),yymmdd8.);
put EffectDate=
/ SASEffectDate=
/ ;
end;
format SASEffectDate yymmdd10.;
run;
This is just an illustration and a bit long-winded; it creates a new SAS variable named SASEffectDate to preserve the original variable. Once you have it as a SAS variable, you don't need to do anything else; the SAS Access product will know how to make the references to the external database.
Here is an example of doing something similar using PROC SQL:
data have; /* Just a dummy data set for illustration */
do EffectDate = 1130101,0130101;
i+1;
output;
end;
run;
proc sql;
create table want as
select t2.*
, case when t2.EffectDate < 999999 /* starts with 0 */
then input('19' || substr(put(EffectDate,z7.),2),yymmdd8.)
else input('20' || substr(put(EffectDate,z7.),2),yymmdd8.)
end as SASEffectDate format=yymmdd10.
from have t2
;
quit;