Search code examples
sql-serversassas-macro

How to pass macro variable to PROC SQL on IN statement in WHERE clause on MS SQL Server


I have a table in MS SQL Server that looks like:

ID, Code
01, A
02, A
03, B
04, C
...

and is defined in SAS as

LIBNAME MSSQLDB ODBC 
    CONNECTION=SHAREDREAD 
    COMPLETE='Description=OIPE DW (Dev);DRIVER=SQL Server Native Client 11.0;SERVER=Amazon;Trusted_Connection=Yes;DATABASE=OIPEDW_Dev;'
    SCHEMA='dbo'
    PRESERVE_TAB_NAMES=YES 
    PRESERVE_COL_NAMES=YES;

I have a SAS dataset that has records of the same format as MSSQLDB (ID and Code variables) but is just a subset of the full database.

I would like to do the following:

PROC SQL NOPRINT;
   /* If SASDS contains just codes A and B, CodeVar=A B
   SELECT DISCTINCT CODE INTO :CodeVar SEPARATED BY ' ' FROM SASDS;
QUIT;
/* seplist is a macro that wraps each code in a quote */
%LET CodeInVar=%seplist( &CodeVar, nest=%STR(") );
PROC SQL;
    DELETE * FROM MSSQLDB WHERE CODE IN (&CodeInVar);
    /* Should execute DELETE * FROM MSSQL WHERE CODE IN ('A','B');
QUIT;

The problem is this generates a syntax error on the values in the &CodeInVar macro variable.

Any idea how to pass the macro variable value to SQL Server in the IN statement?


Solution

  • I think you have a few problems here; hopefully some of them are just transcription errors.

    First off, this will not do anything:

    PROC SQL;
        DELETE * FROM MSSQLDB WHERE CODE IN (&CodeInVar);
        /* Should execute DELETE * FROM MSSQL WHERE CODE IN ('A','B');
    QUIT;
    

    MSSQLDB is your libname, not the table; you need to define it as MSSQLDB.dbname here. Perhaps that's just a copying error.

    Fundamentally there's nothing explicitly wrong with what you've typed. I would suggest first identifying if there are any problems with your macro variable. Put a %put statement in there:

    %put &codeinvar.;
    

    See what that outputs. Is it what you wanted? If not, then fix that part (the macro, presumably).

    I would say that there are a lot of better ways to do this. First off, you don't need to add a macro to add commas or quotes or anything.

    PROC SQL NOPRINT;
       /* If SASDS contains just codes A and B, CodeVar=A B */
       SELECT DISCTINCT cats("'",CODE,"'") INTO :CodeVar SEPARATED BY ',' FROM SASDS;
    QUIT;
    

    That should get you &codevar precisely as you want [ie, 'A','B' ].

    Secondly, since you're using LIBNAME and not passthrough SQL, consider using SQL syntax rather than this entirely.

    proc sql;
    delete from MSSQLDB.yourtable Y where exists 
      (select 1 from SASDS S where S.code=Y.code);
    quit;
    

    That is sometimes faster, depending on the circumstances (it also could be slower). If code is something that has a high frequency, summarize it using PROC FREQ or a SQL query first.