BookmarkSubscribeRSS Feed
Milan983
Calcite | Level 5

Hello everyone.

 

I am using SAS® Customer Intelligence Studio to create CRM campaigns.

I want to execute campaign with Serbian special characters in it (šđžčć) and to export client data with special characters to excel file.

 

Can someone please help me how to do this?

Thank you everyone for your help!

1 REPLY 1
irinna
SAS Employee

Hi

I actually had a similar problem but with Nordic characters through a DM task. This happens if the encoding of the SAS platform is different than UTF-8 so the process fails at that point. To fix it, the options are either to change the encoding of the SAS platform or to change the encoding of the maexp.sas file in the direct marketing agent to add some code to cater for these changes. This will also mean that when the agent is updated, there needs to be a check that the maexp.sas file is still valid.

            

  1. Change the maexpfil.sas file in the DM agent setup

This presents the lowest risk. However, it involves changing one of the files of the DM agent which need then to be reconciled with the new version every time there is a DM agent version release (almost every month). So, when the DM agent update is upgraded, a SAS admin on the platform needs to compare the maexpfil.sas file against the new version that comes in the agent upgrade and if there are differences, implement them while still keeping the encoding changes.This can be an automated process as well but still needs an approval if the change should take place or not.

 

Steps to follow to change the file:

 

  1. I am attaching the file maexpfil.sas that you need to use – this is the version from 22.09 release + required changes so make sure you have the newest maexpfil
  2. /*****************************************************************/
    /* Copyright (c) 2007 - 2013 by SAS Institute Inc., Cary, NC,    */
    /*                    USA.                                       */
    /*             All Rights Reserved.                              */
    /*  This software is protected by copyright laws and             */
    /*               international treaties                          */
    /*                                                               */
    /* U.S. Government Restricted Rights                             */
    /* Use, duplication, or disclosure of this software and related  */
    /*  documentation by the U.S. government is subject to the       */
    /*   Agreement with SAS Institute and the restrictions set forth */
    /*  in FAR 52.227-19, Commercial Computer Software -             */
    /*              Restricted Rights ( June 1987 )                  */
    /*                                                               */
    /*****************************************************************/
    /* NAME: maexp                                                   */
    /* VERSION: 6.1                                                  */
    /*****************************************************************************/
    /* PRISM VERSION: $Revision: 1.5.2.7.2.6.2.4.4.1.2.7.4.6.2.1.6.3.2.9.4.3 $ ;
    /* Revision Date: $Date: 2017/08/08 13:20:07 $  ;
    /*****************************************************************************/
    /*****************************************************************************/
    /* HISTORY:                                                                  */
    /* DATE       Defect No  Comments/updated by                                 */
    /* ---------  ---------  --------------------------------------------------- */
    /* 23APR2013             GA                                                  */
    /*****************************************************************************/
    /* class: export */
    %macro maexpfil( input, vards, varList, output, outputType, headerRow, appendReplace, override , quoteRule);
       %if &MADebug = Y
       %then %do;
          %put Input table: &input;
          %put Variable data set: &vards;
          %put Variable list: &varList;
          %put Output name: &output;
          %put Output type: &outputType (7=Delimited, 4=Positional);
          %put Header row: &headerRow;
          %put Append or replace: &appendReplace;
          %put Override delimiter: &override;
          %put Quote Rule: &quoteRule;
       %end;
       %*-----get filename and delimter for export file-----*;
        /* S0897280 - removed checks for outputtype= 0 & 1 */
        %if %quote(&override) eq 'export_delimiter_comma' %then
            %let dlmchar=%str(",");
        %else %if %quote(&override) eq 'export_delimiter_tab' %then
            %let dlmchar='09'x;
        %else %if %quote(&override) eq 'export_delimiter_semicolon' %then
            %let dlmchar=%str(";");
        %else
            %let dlmchar=%str(&override);
    
       %if &headerRow=Y and %upcase(&appendReplace) = APPEND and %sysfunc(fileexist(&output))
       %then %let headerRow=N; %* do not add header if appending to file that already exists.;
    
       %* determine file statement for file based exports;
       %let export_filestmt=;
       %let export_filestmt=file "&output";
       %if %upcase(&appendReplace) = APPEND
       %then %let export_filestmt=&export_filestmt mod;
    
       /* S0897280 - removed checks for outputtype= 0 & 1 */
       %if &outputType=7 %then
            %let export_filestmt=&export_filestmt dlmstr=&dlmchar; /*Delimited or (old) CSV or TAB delimited*/;
    
       %let export_filestmt=&export_filestmt recfm=v lrecl=32767;
    
       /*******************************************/
       /* START SECTION "Identify email export".  */
       /*******************************************/
       /* This section ensures that on-prem email exports are generated in UTF-8 */
    
       data _null_;
         path = strip(symget("OUTPUT"));
         f = scan(path, -1, "/\");
         if index(f, "EmailExport_") = 1 then do;
           call symputx("IS_EMAIL_EXPORT", "YES");
           putlog "**************************";
           putlog path "is an email export";
           putlog "IS_EMAIL_EXPORT=YES";
           putlog "Sets output encoding to UTF-8";
           putlog "*************************";
         end;
         else do;
           call symputx("IS_EMAIL_EXPORT", "NO");
           putlog "**************************";
           putlog path "is not an email export";
           putlog "IS_EMAIL_EXPORT=NO";
           putlog "*************************";
         end;
       run;
       %if %superq(IS_EMAIL_EXPORT)=YES %then %do;
          options nobomfile;
          %let export_filestmt=&export_filestmt ENCODING='UTF-8';
       %end;
    
       /*******************************************/
       /* END SECTION "Identify email export" */
       /*******************************************/
    
    											
       /* S1134653 - Add BOM if utf-8  */
       %if %nrbquote(&SysEncoding) = %str(utf-8) %then
          %let export_filestmt=&export_filestmt ENCODING='UTF-8' ;
    
       filename logfile temp lrecl=32767;
    
       data _null_;
          set &vards end=done;
          file logfile;
          if _n_ = 1
          then do;
             put 'data ef_vartype (keep=exportOrder sasVarType);';
             put '   length sasVarType $ 2;';
             put '   set &input;';
             put '   if _n_ > 1 then stop;';
          end;
    
          put '   exportOrder=' exportOrder ';';
          put '   sasVarType=vtypex("' outputname+(-1) '");';
          put '   output;';
    
          if done then do;
             put 'run;';
          end;
       run;
       %inc logfile;
       filename logfile clear;
    
       data ef_varsort;
          merge &vards ef_vartype; by exportOrder;
    
        filename expfile temp lrecl=32767;
    
        data _null_;
            length _tmpvar $ 2000;
    		%if &EXTENDEDCOLUMNNAMES = Y and &outputType = 7 %then %do;
    		set &vars_extended_cols end=done;
    		%end;
    		%else %do;
    			set &vards end=done;
    		%end;
            file expfile;
            if _n_ = 1 then
            do;
    
                put "data _null_;";
    
                put "%bquote(&export_filestmt;)";
    			/* S1189436 - check for final table count */
    			%if &expt_final_tbl_cnt. ne 0 %then
    			%do;
    		put "set &input;";
    			%end;
                put "length _matemp $ 2000 sasmat_out $4000;";
                /* S0897280 - do not apply quotes when quote rule is set to  "never quote values in export file" ,
                              removed checks for outputtype= 0 & 1 */
                %if &outputType=7 and &quoteRule ne N %then
                %do;
                    put "format _matemp $quote.;";
                %end;
                %if &headerRow = Y %then
                %do;
    			/* S1189436 - check for final table count */
                    %if &expt_final_tbl_cnt. eq 0 %then
    				%do;
    					put "header_row_replace=1;";
    					put "if header_row_replace=1 then do;";
    				%end;
    				%else %do;
    					put "if _n_ = 1 then do;";
    				%end;
                %end;
            end;
            %if &headerRow = Y %then
            %do;
                put "_matemp = '" outputname +(-1) "';";
                %if &outputType = 4 %then
                %do;
                    put 'put @' position "_matemp @;";
                %end;
                %else
                %do;
                    put "put _matemp @;";
                %end;
    
                if done then put "put;" / "end;";
            %end;
        run;
    
    	/* S1189436 - check for final table count */
    	%if &expt_final_tbl_cnt. ne 0 %then
    	%do;
    	    data _null_;
    			length _tmpvar $ 2000 start_pos 8;
    	        set ef_varsort end=done;
    	        file expfile mod;
    			start_pos =1;
    			retain start_pos_end;
    			if _n_ =1 then
    			  start_pos_end = position;
    	        if format ^= '' then
    	        do;
    				 _tmpvar = '_sasmat' || left(put(_n_,f8.));
    
    	            /*      begin:S0556482- Modified to remove tilde character from format variable */
    	            if kindex(format,'~') eq 1 then
    	            do;
    	                notildeformat = ksubstr(format,2);
    	               put  _tmpvar  '= left(put(' outputname ', ' notildeformat '));';
    	            end;
    	            else
    	                put _tmpvar '= left(put(' outputname ',' format '));';
    	            /*      end:S0556482*/
    	            %if &quoteRule = A %then
    	            %do;
    	                put 'format ' _tmpvar '  $quote.;' ;
    	            %end;
    	            %else %if &quoteRule ne N %then
    	            %do;
    	                /* S0897280 - removed checks for outputtype= 0 */
    	                %if &outputType=7 %then
    	                %do;
    	                    put 'format ' _tmpvar '  $quote.;' ;
    	                %end;
    	            %end;
    	            %else %if &outputType ^= 7 and &outputType ^= 4 %then
    	            %do;
    	               put _tmpvar  = outputname;
    	            %end;
    	        end;
    	        else
    	        do;
    	            if ("&quoteRule"="A" and dataType="N") or dataType="DT" or dataType="D" or dataType="T" then
    	            do;
    					_tmpvar = '_sasmat' || left(put(_n_,f8.));
    	                length fmt $ 20;
    	                fmt="BEST12.";
    	                if dataType="DT" then fmt="DATETIME.";
    	                else if dataType="D" then fmt="DATE9.";
    	                else if dataType="T" then fmt="TOD.";
    					/* S1326282 -  do not set format when type is 8 */
    	                if sasVarType='C' then
    					do;
    	                  if Type = 8 then
                          do;
    					    _tmpvar =  outputname;
    					  end;
    					  else do;
    					    put _tmpvar '= left(putn(' outputname ', "' fmt +(-1)'"));';
    					  end;
    					end;
    	                else
    	                    put _tmpvar '= left(put(' outputname ', ' fmt '));';
    	            end;
    	            else  _tmpvar =  outputname;
    
    	            %if &quoteRule=A %then
    	            %do;
    	                put 'format  ' _tmpvar '  $quote.;' ;
    	            %end;
    	            %else %if &quoteRule ne N and &outputType=7 %then
    	            %do;
    	                if dataType^="N" then put 'format ' _tmpvar ' $quote.;';
    	            %end;
    	        end;
    	        /* S0814504 - the format is already applied in the first do loop above , if we apply the format again to the variable it will print incorrect values
    	                      not sure why the format was applied in case of quoteRule ^= A , need to test it for different conditions */
    	        %if &outputType = 4 %then
    	        %do;
    	            /*
    	            if format ^= '' then
    	            do;
    	                %if &quoteRule^=A %then
    	                %do;
    	                    put 'put @' position _tmpvar format '@ ;';
    	                %end;
    	                %else
    	                %do;
    	                    put 'put @' position _tmpvar '@ ;';
    	                %end;
    	            end;
    	            else
    	            do;
    	                put 'put @' position _tmpvar '@ ;';
    	            end;
    	            */
    
    				put  'sasmat_out  = ksubstr(sasmat_out,' start_pos ',' position ') || left(' _tmpvar '); ';
    
    	        %end;
    	        %else
    	        %do;
    	            put 'put ' _tmpvar ' @ ;';
    	        %end;
    
    	        if done then do;
    			/* S1144393 - Added fix,single put statement used for output */
    				%if &outputType = 4 %then
    			%do;
    				put 'put @' start_pos_end ' sasmat_out ;';
    					put 'run;';
    				%end;
    				%else %do;
    				put 'put;' / 'run;';
    				%end;
    			end;
    
    	    run;
    	%end;
    
        %inc expfile;
        /*S0401805*/
        %if (&SYSCC ne 0 and &SYSCC ne 4) and %symexist(SYSERRORTEXT) %then
        %do;
            /*send back the SYSERRORTEXT to user */
            %let MAERROR=399;/*set a  non used error code so that core can send error text back as is */
            %let MAMsg=Macro[&sysmacroname.].SYSERRORTEXT=[&SYSERRORTEXT];
            %return;
        %end;
    %mend;
    
  3. Enable/setup the sasfile.overrides in the cionprem.properties file.

When the DM agent runs it will use the sasfile.overrides maexpfil.sas first and not the one that comes with the dm agent.

 

2.1 Setting up sasfile.overrides ( detailed steps here 😞

 

- The directory for the sasfile.overrides needs to be in the dm agent server.

 

  1. a) cionprem.properties (you can pick your own directory)

 

sasfile.overrides=/opt/sas/onprem/sascode

 

  1. b) files inside /opt/sas/onprem/sascode. You only need to place the mapexpfil.sas here. Make sure the dm agent install/running user has permissions to it.

 

$ pwd

/opt/sas/onprem/sascode

 

$ ls -lR

drwxrwxr-x 2 sas sas 4096 Jun  8 11:15 sasmacro

drwxrwxr-x 2 sas sas 4096 May  5  2021 sasstp

 

./sasmacro:

total 48

-rw-rw-r-- 1 sas sas 11299 Jun  8 11:15 maexpfil.sas

-rw-rw-r-- 1 sas sas  1000 Mar 31 17:08 maspinit.sas

-rw-rw-r-- 1 sas sas  4614 Mar 18 06:16 mausrexp.sas

 

  1. c) You will need to restart the dm agent for the changes to take effect

 

 

When the dm agent is upgraded someone needs to check if the newer maexpfil.sas has changed with respect to the one being used and act appropriately.

 

  1. Getting the maexpfil.sas file when a new update is released – steps here. -

 

                   

How to improve email deliverability

SAS' Peter Ansbacher shows you how to use the dashboard in SAS Customer Intelligence 360 for better results.

Find more tutorials on the SAS Users YouTube channel.

Discussion stats
  • 1 reply
  • 813 views
  • 2 likes
  • 2 in conversation