I am the struggling with the following command. In reality, it is to be executed as a SQL statement. I am printing out the statement below using disp command.
Datevar = datestr(date,'mm/dd/yyyy') ; % 07/25/2011
% Required command: execute SQLname #startdate = '7/25/2011'
% My current command:
disp([...
'execute SQLname ' ...
'#startdate = ' ''' Datevar ''' ...
])
I have tried many combinations but I am not able to hit this string right: #startdate = '7/25/2011'. Thanks!
Misplaced quote, at least in the example code you posted. That third line of the disp call is concatenating two separate strings, and the second one contains a literal "Datevar". You want this, which will concatenate the contents of the variable named Datevar.
sql = [...
'execute SQLname ' ...
'#startdate = ''' Datevar '''' ...
];
disp(sql);
IMHO, short queries like these are more readable if you construct them with sprintf, because you don't have to differentiate between internal quotes and delimiting quotes.
sql = sprintf('execute SQLname #startdate = ''%s''', Datevar);
If you include an example of the exact output you are getting, it's easier to diagnose problems like this.
It seems like you are do not want the leading zeroes provided by datestr. There are no date specifiers for returning non-padded day and month values. You can create the string you want by using DATEVEC and SPRINTF like this:
>> date = datevec('2011/07/25');
>> sprintf('execute SQLname #startdate = ''%u/%u/%u''', date([2 3 1]))
ans =
execute SQLname #startdate = '7/25/2011'
Related
I have a string that I need to seperate into values seperated by commas. I have achieved this part with the below REPLACE statement:
declare #mc varchar(200)
declare #mc1 varchar(200)
select #mc = 'FRED&#g4;g;MARY&#g4;g;BILL&#g4;g;TIMOTHY&#g4;g;JOHNATHAN'
select #mc1 = REPLACE(#mc, '&#g4;g;',', ')
The replace returns a string 'FRED, MARY, BILL, TIMOTHY, JOHNATHAN'
I then want to have another variable that will return the first 3 characters of each value before the commas, so the above string would be returned as:
'FRE, MAR, TIM, JOH'
Anyone know how I can achieve this?
Also happy for this to be done directly to the original #mc variable
ON SQL Server 2017+ you can make use of openJson to split the string into manageble segments and then string_agg to assemble the desired result:
declare #mc varchar(100)='FRED&#g4;g;MARY&#g4;g;BILL&#g4;g;TIMOTHY&#g4;g;JOHNATHAN'
select String_Agg(v, ', ')
from (select #mc)x(s)
cross apply (
select Left(j.[value],3) v, Convert(tinyint,j.[key]) Seq
from OpenJson(Concat('["',replace(s,';', '","'),'"]')) j
where Convert(tinyint,j.[key]) % 2 = 0
)j;
Demo Fiddle
I need to build a SQL statement to be submitted on a linked server. The statement makes use of #parameters and case statements which contain quotation marks.
I found this Microsoft article 'How to pass a variable', which seemed ideal, however I am not able to get everything going. It seems that the linked server is not enabled for the final and neatest suggestion of calling Sp_executesql, so I have been trying the first two examples.
To start with, here is a cut down example of my SQL statement on its own:
SELECT *,
CASE WHEN FLDA = 'ABC' THEN 'DEF' ELSE 'ABC' END AS COL1
FROM MYTABLE
WHERE FLDB = #PARM
1, I can get the query to work when excluding the CASE statement:
DECLARE #TSQL NVARCHAR(4000), #PARM NVARCHAR(10)
SET #PARM = 'ABC'
SET #TSQL = 'SELECT * FROM OPENQUERY(MYLINKEDSERVER, ''
SELECT *
FROM MYTABLE
WHERE FLDA = '''''+#PARM+''''''')'
EXEC (#TSQL)
However I don't understand why I require 5 quotes before #PARM and then 7(!) after it? When coding SQL statements in a string in previous languages just 2 quotations together acted as a single. So why 5 and 7?
2, I can't get the SQL to work at all when attempting to add the CASE statement. I have tried all combinations of 2,3,4 quotations but to no avail: Do I again need a certain amount of opening quotes and then a different amount of closing quotes?
DECLARE #TSQL NVARCHAR(4000), #PARM NVARCHAR(10)
SET #PARM = 'ABC'
SET #TSQL = 'SELECT * FROM OPENQUERY(MYLINKEDSERVER, ''
SELECT *,
CASE WHEN FLDA = ''ABC'' THEN ''DEF'' ELSE ''ABC'' END AS COL1
FROM MYTABLE
WHERE FLDA = '''''+#PARM+''''''')'
EXEC (#TSQL)
Any help greatly appreciated!
Cheers
Mark
my first question was why do I need 5 and 7 quotes, so there was no error message there, but I get the point that I could have listed some of the errors seen when I was getting the incorrect number of quotes.
However the tip to use Print was very useful, so thank you all for that!
So it transpires that I do indeed require a pair of
quotes where a single quote is required. However, as I am creating a SQL string within a string, I need to double that again. So I first need to end my string with a single quote and then add 4 quotes to create the double quote required to proceed the variable - hence 5. And likewise, I need 4 quotes to get a pair of quotes following the variable, another pair of quotes for the quote to end the statement and then a final one to wrap around the end bracket of the OPENQUERY command....I hope that sort of reads correct!
So:
WHERE FLDA = '''''+#PARM+''''''')'
Printed as:
WHERE FLDA = ''ABC''')
And for my CASE statement, I required 4 set of quotes, to equate to 2. So:
CASE WHEN FLDA = ''''ABC'''' THEN ''''DEF'''' ELSE ''''ABC'''' END AS COL1
Printed as:
CASE WHEN FLDA = ''ABC'' THEN ''DEF'' ELSE ''ABC'' END AS COL1
I have a query that extracts performance measurements of a number of APIs and those I want to save over time to different files in one folder. Say every hour one run and one output file.
The Invantive scripting statement
local export results as "${exportfilename}" format xml
Can do this when you have exportfilename correctly set up.
With Oracle SQL*Plus you can memorize the outcome of a query in a variable with the column ... new_value syntax.
How can I set exportfile using the outcome of an Invantive SQL query?
Solution was to use the ${outcome:row,column} syntax as in:
local define outfolder "c:\temp"
select sdy3.value || '-' || lpad(year(sysdate), 4, '0') || lpad(month(sysdate), 2, '0') || lpad(day(sysdate), 2, '0') || lpad(hour(sysdate), 2, '0') || lpad(minute(sysdate), 2, '0') ||'.xml' file_name
from exactonlinerest..systemdatacontainerproperties sdy1
join exactonlinerest..systemdatacontainerproperties sdy2
on sdy2.data_container_alias = 'default'
and sdy2.name = 'provider-description'
join exactonlinerest..systemdatacontainerproperties sdy3
on sdy3.data_container_alias = 'default'
and sdy3.name = 'provider-short-name'
where sdy1.data_container_alias = 'default'
and sdy1.name = 'data-container-id'
local define exportfilename "${outfolder}\${outcome:0,0}"
<<< Run actual SQL>>>
local export results as "${exportfilename}" format xml
The ${outcome:...,...} syntax puts the string representation of the respective row number (0..max) and column number (0..max) as a value into the indicated variable name.
I have a table which has 120 columns and some of them is including Turkish characters (for example "ç","ğ","ı","ö"). So i want to replace this Turkish characters with English characters (for example "c","g","i","o"). When i use "TRANWRD Function" it could be really hard because i should write the function 120 times and sometimes hte column names could be change so always i have to check the code one by one because of that.
Is there a simple macro which replaces this characters in all columns .
EDIT
In retrospect, this is an overly complicated solution... The translate() function should be used, as pointed by another user. It could be integrated in a SAS function defined with PROC FCMP when used repeatedly.
A combination of regular expressions and a DO loop can achieve that.
Step 1: Build a conversion table in the following manner
Accentuated letters that resolve to the same replacement character are put on a single line, separated by the | symbol.
data conversions;
infile datalines dsd;
input orig $ repl $;
datalines;
ç,c
ğ,g
ı,l
ö|ò|ó,o
ë|è,e
;
Step 2: Store original and replacement strings in macro variables
proc sql noprint;
select orig, repl, count(*)
into :orig separated by ";",
:repl separated by ";",
:nrepl
from conversions;
quit;
Step 3: Do the actual conversion
Just to show how it works, let's deal with just one column.
data convert(drop=i re);
myString = "ç ğı òö ë, è";
do i = 1 to &nrepl;
re = prxparse("s/" || scan("&orig",i,";") || "/" || scan("&repl",i,";") || "/");
myString = prxchange(re,-1,myString);
end;
run;
Resulting myString: "c gl oo e, e"
To process all character columns, we use an array
Say your table is named mySource and you want all character variables to be processed; we'll create a vector called cols for that.
data convert(drop=i re);
set mySource;
array cols(*) _character_;
do c = 1 to dim(cols);
do i = 1 to &nrepl;
re = prxparse("s/" || scan("&orig",i,";") || "/" || scan("&repl",i,";") || "/");
cols(c) = prxchange(re,-1,cols(c));
end;
end;
run;
When changing single characters TRANSLATE is the proper function, it will be one line of code.
translated = translate(string,"cgio","çğıö");
First get all your columns from dictionary, and then replace the values of all of them in a macro do loop.
You can try a program like this (Replace MYTABLE with your table name):
proc sql;
select name , count(*) into :columns separated by ' ', :count
from dictionary.columns
where memname = 'MYTABLE';
quit;
%macro m;
data mytable;
set mytable;
%do i=1 %to &count;
%scan(&columns ,&i) = tranwrd(%scan(&columns ,&i),"ç","c");
%scan(&columns ,&i) = tranwrd(%scan(&columns ,&i),"ğ","g");
...
%end;
%mend;
%m;
I have a var: acc_date with type date.
It takes its value from a cursor and when I insert its value to logger table as:
insert into logger values(1,acc_date);
the out put when a select it from logger is
1 01-JAN-10
but when i use it to compare with another Date value in another cursor as
OPEN c_get_date_id
for 'SELECT Date_D.DATEKEY from Date_D where Date_D.DATEVALUE='||acc_date;
EXIT WHEN c_get_date_id%NOTFOUND;
FETCH c_get_date_id
INTO date_id;
insert into logger values (1,'Now with date_id'||date_id);
CLOSE c_get_date_id;
an error occurs:
Error report:
ORA-00904: "JAN": invalid identifier
ORA-06512: at "HW.FILLFACT", line 82
ORA-06512: at line 1
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
strong text
You need at least add some quotes around the date:
....' where Date_D.DATEVALUE='''||acc_date||'''';
Double apostrophes within a string will be concatenated to a single apostrophe, so that the expression becomes
where Date_D.DATEVALUE='....';
In order to make the thing more foolprof, I'd also add a specific to_date:
.... ' where Date_D.DATEVALUE=to_date(''' || acc_date || ', ''dd-mon-yy'')';
At the moment your dynamic query is being interpreted as:
SELECT Date_D.DATEKEY from Date_D where Date_D.DATEVALUE=01-JAN-10
The error is because string representation of the date isn't being quoted, so it's seeing JAN as an identifier - and nothing matches that name. You could enclose the date value in quotes:
open c_get_date_id
for 'SELECT Date_D.DATEKEY from Date_D where Date_D.DATEVALUE='''||acc_date||'''';
But you're treating the date as a string, and forcing conversion of all your table values to strings to be compared, using your session's NLS_DATE_FORMAT. It would be better to compare it as a date (although this somewhat assumes all your values have the time portion set to midnight):
open c_get_date_id
for select date_d.datekey from date_d where date_d.datevalue = acc_date;
Your exit is in the wrong place though, and you aren't looping, so maybe you want:
open c_get_date_id
for select date_d.datekey from date_d where date_d.datevalue = acc_date;
loop
fetch c_get_date_id into date_id;
exit when c_get_date_id%notfound;
insert into logger values (1, 'Now with date_id'||date_id);
end loop;
close c_get_date_id;
If you only have one value in the first place though, you probably don't want a loop or cursor at all, and could do a simple select ... into instead:
select date_d.datekey into date_id from date_d
where date_d.datevalue = acc_date;
insert into logger values (1, 'Now with date_id'||date_id);
Though of course that would error if you had no matching date in your table, or more than one, and you'd need to deal with that - but then I guess you'd want to anyway.