换行符在SAS的宏参数中丢失
Line breaks are lost in macro parameters of SAS
我想将包含换行符的文本从 SAS table 传输到外部数据库 table(通过 ODBC)。
我使用宏变量作为缓冲区。我使用宏将文本插入 table
的远程数据库。问题是文本中的换行符丢失了,
如果我将文本作为参数传递给宏。
如何保留换行符?
%macro dbinsert (id=,text=);
/*
Macro for inserting text into table of second database.
For test purposes, odbc table replaced with SAS table.
Issue: line breaks will be lost. How can i keep the line breaks?
Original Code:
proc sql;
CONNECT TO ODBC (DSN="mydb");
EXEC (update mytable
set text= "&text."
where id = &id.;
) BY ODBC;
quit;
*/
proc sql noprint;
update x2
set text = "&text."
where id = &id.;
quit;
%mend dbinsert;
%macro main;
/* Initialize SAS table. Just for test purposes. */
data x1;
text="Hello Martin how are you?"; output;
text="Thank you I am fine!"; output;
text="And how are you?"; output;
run;
/* Read content from SAS table into macro variable (text1). The content is separated via line breaks 0D0A. */
proc sql noprint;
select text into :text1 separated by '0D0A'x from x1;
quit;
/* Initialize table in second database. Just for test purposes. */
data x2;
length id 8 text 0;
id=1; text="111"; output;
id=2; text="222"; output;
run;
%dbinsert(id=2,text=&text1.);
%mend main;
%main;
宏不支持 non-printable 个字符。
来自文档
Getting Started with the Macro Facility
...
The SAS macro language is a string-based language. It does not support the use of hexadecimal character constants.
Note: The SAS macro language does not support using hexadecimal values to specify non-printable characters.
和
Macro Variables
...
Macro variable values have a maximum length of 65,534 characters. The length of a macro variable is determined by the text assigned to it instead of a specific length declaration. So its length varies with each value that it contains. Macro variables contain only character data. However, the macro facility has features that enable a variable to be evaluated as a number when it contains character data that can be interpreted as a number. The value of a macro variable remains constant until it is specifically changed. Macro variables are independent of SAS data set variables.
Note: Only printable characters should be assigned to macro variables. Non-printable values that are assigned to macro variables can cause unpredictable results.
可能的选择
你知道EXEC
并通过了——很好!
考虑使用 SQL 为连接字符串文字的字符串表达式 构造源代码。该表达式将包含使用远程数据库本机字符函数的源代码。必须修改 DBINSERT
宏以处理现在包含表达式的参数。
同样,宏将 non-printable 个字符转换为 space,因此如果 x1.text
中的数据值包含嵌入的 CRLF,它们将不会出现在构造的表达式中。
示例:
重要提示: 请勿将此版本的 DBINSERT 与不受信任的用户提供的任何输入或网络输入一起使用。来自数据值的 Codegen 是用于 SQL 注入或代码注入的向量。
%macro dbinsert (id=,expression=);
proc sql noprint;
update x2
set text = &expression
where id = &id.;
quit;
%mend dbinsert;
data x1;
text="Hello Martin how are you?"; output;
text="Thank you I am fine!"; output;
text="And how are you?"; output;
run;
/*
* CONSTRUCT SOURCE CODE FOR AN EXPRESSION THAT CONCATENTATES STRING LITERALS
* (also known as codegen short for code generator)
*/
proc sql noprint;
select
quote(trim(text))
into :text1
separated by '||byte(13)||byte(10)||'
from x1;
data x2;
length id 8 text 0;
id=1; text="111"; output;
id=2; text="222"; output;
run;
options mprint;
%dbinsert(id=2,expression=&text1.);
%symdel text1;
title;
ods html style=monospace;
proc print data=x2; where id=2;
proc print data=x2; where id=2; format text $HEX400.;
proc print data=x2; where id=2;
var text / style=[asis=true];
run;
ods html close;
日志显示在 DBINSERT
调用时正在运行的 codegen。
634 %dbinsert(id=2,expression=&text1.);
MPRINT(DBINSERT): proc sql noprint;
MPRINT(DBINSERT): update x2 set text = "Hello Martin how are you?"||byte(13)||byte(10)||"Thank
you I am fine!"||byte(13)||byte(10)||"And how are you?" where id = 2;
NOTE: 1 row was updated in WORK.X2.
检查结果。 SAS ViewTable 将 non-printables 呈现为 space,但数据值中存在控制字符。
查看器中的结果图像
ODS HTML 中的相同结果,第二个 table 显示十六进制格式时的文本值。第三个 table 显示当样式选项 ASIS=YES
生效时由 ODS HTML
解释的控制字符的视图。
无需尝试添加将宏变量的值转换为有效代码所需的引号,您只需编写宏以假定该值已经是包含在生成代码中的有效语法。那么 SQL 语法就是:
set text = &text.
如果您需要添加远程系统用于指定字符串中特殊字符的任何语法,那么您可以这样做
%dbinsert (id=,text='ABC'||byte(13)||'XYZ')
如果您有一个现有的宏变量并且想用单引号将其括起来,您可以使用数据步骤来保留任何特殊字符。
data _null_;
call symputx('text',quote(symget('text'),"'"));
run;
请注意,使用数据步会将您限制为 32K 字节的字符串,而不是宏变量可以容纳的 64k 字节的限制。
我想将包含换行符的文本从 SAS table 传输到外部数据库 table(通过 ODBC)。 我使用宏变量作为缓冲区。我使用宏将文本插入 table 的远程数据库。问题是文本中的换行符丢失了, 如果我将文本作为参数传递给宏。 如何保留换行符?
%macro dbinsert (id=,text=);
/*
Macro for inserting text into table of second database.
For test purposes, odbc table replaced with SAS table.
Issue: line breaks will be lost. How can i keep the line breaks?
Original Code:
proc sql;
CONNECT TO ODBC (DSN="mydb");
EXEC (update mytable
set text= "&text."
where id = &id.;
) BY ODBC;
quit;
*/
proc sql noprint;
update x2
set text = "&text."
where id = &id.;
quit;
%mend dbinsert;
%macro main;
/* Initialize SAS table. Just for test purposes. */
data x1;
text="Hello Martin how are you?"; output;
text="Thank you I am fine!"; output;
text="And how are you?"; output;
run;
/* Read content from SAS table into macro variable (text1). The content is separated via line breaks 0D0A. */
proc sql noprint;
select text into :text1 separated by '0D0A'x from x1;
quit;
/* Initialize table in second database. Just for test purposes. */
data x2;
length id 8 text 0;
id=1; text="111"; output;
id=2; text="222"; output;
run;
%dbinsert(id=2,text=&text1.);
%mend main;
%main;
宏不支持 non-printable 个字符。
来自文档
Getting Started with the Macro Facility
...
The SAS macro language is a string-based language. It does not support the use of hexadecimal character constants.
Note: The SAS macro language does not support using hexadecimal values to specify non-printable characters.
和
Macro Variables
...
Macro variable values have a maximum length of 65,534 characters. The length of a macro variable is determined by the text assigned to it instead of a specific length declaration. So its length varies with each value that it contains. Macro variables contain only character data. However, the macro facility has features that enable a variable to be evaluated as a number when it contains character data that can be interpreted as a number. The value of a macro variable remains constant until it is specifically changed. Macro variables are independent of SAS data set variables.
Note: Only printable characters should be assigned to macro variables. Non-printable values that are assigned to macro variables can cause unpredictable results.
可能的选择
你知道EXEC
并通过了——很好!
考虑使用 SQL 为连接字符串文字的字符串表达式 构造源代码。该表达式将包含使用远程数据库本机字符函数的源代码。必须修改 DBINSERT
宏以处理现在包含表达式的参数。
同样,宏将 non-printable 个字符转换为 space,因此如果 x1.text
中的数据值包含嵌入的 CRLF,它们将不会出现在构造的表达式中。
示例:
重要提示: 请勿将此版本的 DBINSERT 与不受信任的用户提供的任何输入或网络输入一起使用。来自数据值的 Codegen 是用于 SQL 注入或代码注入的向量。
%macro dbinsert (id=,expression=);
proc sql noprint;
update x2
set text = &expression
where id = &id.;
quit;
%mend dbinsert;
data x1;
text="Hello Martin how are you?"; output;
text="Thank you I am fine!"; output;
text="And how are you?"; output;
run;
/*
* CONSTRUCT SOURCE CODE FOR AN EXPRESSION THAT CONCATENTATES STRING LITERALS
* (also known as codegen short for code generator)
*/
proc sql noprint;
select
quote(trim(text))
into :text1
separated by '||byte(13)||byte(10)||'
from x1;
data x2;
length id 8 text 0;
id=1; text="111"; output;
id=2; text="222"; output;
run;
options mprint;
%dbinsert(id=2,expression=&text1.);
%symdel text1;
title;
ods html style=monospace;
proc print data=x2; where id=2;
proc print data=x2; where id=2; format text $HEX400.;
proc print data=x2; where id=2;
var text / style=[asis=true];
run;
ods html close;
日志显示在 DBINSERT
调用时正在运行的 codegen。
634 %dbinsert(id=2,expression=&text1.);
MPRINT(DBINSERT): proc sql noprint;
MPRINT(DBINSERT): update x2 set text = "Hello Martin how are you?"||byte(13)||byte(10)||"Thank
you I am fine!"||byte(13)||byte(10)||"And how are you?" where id = 2;
NOTE: 1 row was updated in WORK.X2.
检查结果。 SAS ViewTable 将 non-printables 呈现为 space,但数据值中存在控制字符。
查看器中的结果图像
ODS HTML 中的相同结果,第二个 table 显示十六进制格式时的文本值。第三个 table 显示当样式选项 ASIS=YES
生效时由 ODS HTML
解释的控制字符的视图。
无需尝试添加将宏变量的值转换为有效代码所需的引号,您只需编写宏以假定该值已经是包含在生成代码中的有效语法。那么 SQL 语法就是:
set text = &text.
如果您需要添加远程系统用于指定字符串中特殊字符的任何语法,那么您可以这样做
%dbinsert (id=,text='ABC'||byte(13)||'XYZ')
如果您有一个现有的宏变量并且想用单引号将其括起来,您可以使用数据步骤来保留任何特殊字符。
data _null_;
call symputx('text',quote(symget('text'),"'"));
run;
请注意,使用数据步会将您限制为 32K 字节的字符串,而不是宏变量可以容纳的 64k 字节的限制。