How to execute prepared SQL statement stored in another table - sql

Suppose we have a Teradata table db.queries in which prepared statements are stored in statement_code as CLOB, for example the content of such field can look like:
INSERT INTO DATA.TABLE
(ID, JOB_NAME, DATE)
VALUES(1, 'TEST_JOB', CAST(CURRENT_DAY AS DATE FORMAT 'YYYYMMDD')='$currentDay');
We have a stored procedure, which reads this data and then executes this using the following code:
SELECT statement_code
FROM db.queries
WHERE ACTIVE_FLAG = 1
INTO SQL_QRY;
EXECUTE IMMEDIATE SQL_QRY;
This is failing because the extracted statement_code in the SQL_QRY has now esacped single quotes.
Syntax error, expected something like '')'' or '','' between a string or a Unicode character literal and the word ''YYYYMMDD''.
Returned string from SQL_QRY is:
INSERT INTO DATA.TABLE
(ID, JOB_NAME, DATE)
VALUES(1, ''TEST_JOB'', CAST(CURRENT_DAY AS DATE FORMAT ''YYYYMMDD'')=''$currentDay'');
As opposed to the stored statement_code:
INSERT INTO DATA.TABLE
(ID, JOB_NAME, DATE)
VALUES(1, 'TEST_JOB', CAST(CURRENT_DAY AS DATE FORMAT 'YYYYMMDD')='$currentDay');
We have tried using OREPLACE in the variable setting to no avail. The function can replace double single quotes to any character, but single quotes.
By dumping various testing combinations:
OREPLACE(SQL_QRY, '''''', '*') --replaces to *
OREPLACE(SQL_QRY, '''', '*') --replaces to *
OREPLACE(SQL_QRY, '''', '') --get rids of quotes completely
OREPLACE(SQL_QRY, '''''', '''') --leaves the double quotes
Is there a way to overcome this nuisance or what is the proper way to achieve the goal? Retrieve prepared statements and execute them?
Kind Regards

Since your query is prepared already, I think you don't need to prepare it again, execute immediate converts ' to '' to make a string ready as a SQL statement to be executed and screws your already prepared string up.
So you just need to do :
EXECUTE SQL_QRY;
or if your queries stored with two single quotes maybe you need to convert them to one single quote:
OREPLACE(SQL_QRY, '''', ''')

Related

How to remove a single quote from a value while inserting in SQL database

I have a long list of insert query which has a slight error.
INSERT INTO `delivery_zip` (..)
VALUES ("AB'C / DEF", ..), ("AB'C / DEF", ..), ("AB'C / DEF", ..), ...
How do I remove the single quote after AB' from the values.
If the single quote in question is the only single quote present in the column col1, and you have already inserted the data, then you should be safe using UPDATE with REPLACE to remove it:
UPDATE delivery_zip
SET col1 = REPLACE(col1, ''', '')
But if you haven't done the insertion yet, you could do a find and replace in your script first, possibly using a regex if needed.

How to concatenate variables into SQL strings

I need to concatenate a variable table name into my SQL query such as the following...
ALTER FUNCTION fn_myfunction(#KeyValue text)
BEGIN
INSERT INTO #tmpTbl1
SELECT #KeyValue AS fld1
FROM tbl + #KeyValue + KeyValue.fld1
I also attempted the following but it told me I had to declare the table variable?
ALTER FUNCTION fn_myfunction(#KeyValue text, #KeyTable text)
FROM #KeyTable.fld1
You can accomplish this (if I understand what you are trying to do) using dynamic SQL.
The trick is that you need to create a string containing the SQL statement. That's because the tablename has to specified in the actual SQL text, when you execute the statement. The table references and column references can't be supplied as parameters, those have to appear in the SQL text.
So you can use something like this approach:
SET #stmt = 'INSERT INTO #tmpTbl1 SELECT ' + #KeyValue
+ ' AS fld1 FROM tbl' + #KeyValue
EXEC (#stmt)
First, we create a SQL statement as a string. Given a #KeyValue of 'Foo', that would create a string containing:
'INSERT INTO #tmpTbl1 SELECT Foo AS fld1 FROM tblFoo'
At this point, it's just a string. But we can execute the contents of the string, as a dynamic SQL statement, using EXECUTE (or EXEC for short).
The old-school sp_executesql procedure is an alternative to EXEC, another way to execute dymamic SQL, which also allows you to pass parameters, rather than specifying all values as literals in the text of the statement.
FOLLOWUP
EBarr points out (correctly and importantly) that this approach is susceptible to SQL Injection.
Consider what would happen if #KeyValue contained the string:
'1 AS foo; DROP TABLE students; -- '
The string we would produce as a SQL statement would be:
'INSERT INTO #tmpTbl1 SELECT 1 AS foo; DROP TABLE students; -- AS fld1 ...'
When we EXECUTE that string as a SQL statement:
INSERT INTO #tmpTbl1 SELECT 1 AS foo;
DROP TABLE students;
-- AS fld1 FROM tbl1 AS foo; DROP ...
And it's not just a DROP TABLE that could be injected. Any SQL could be injected, and it might be much more subtle and even more nefarious. (The first attacks can be attempts to retreive information about tables and columns, followed by attempts to retrieve data (email addresses, account numbers, etc.)
One way to address this vulnerability is to validate the contents of #KeyValue, say it should contain only alphabetic and numeric characters (e.g. check for any characters not in those ranges using LIKE '%[^A-Za-z0-9]%'. If an illegal character is found, then reject the value, and exit without executing any SQL.
You could make use of Prepared Stements like this.
set #query = concat( "select name from " );
set #query = concat( "table_name"," [where condition] " );
prepare stmt from #like_q;
execute stmt;

Create INSERT statement using parameter

I need to create a INSERT statement using parameters. Say I have two variable name #DestinationFields, #InsertValues.
Here #DestinationFields contain the column name like: product,price and #InsertValues contains the values for those two columns, like: Book,100.
Now, How i create a insert command to insert those values where each value need to add a quotation mark .I already tried as
I already tried as
EXEC('INSERT into tbl_test('+#DestinationFields+')values('+#InsertValues+')')
But it's returning an error.
The name "book" is not permitted in this context. Valid expressions are constants, constant expressions, and (in some
contexts) variables. Column names are not permitted.
How do I do it? Thanks in advance.
Pretending there is no problem of SQL injection here*, you can quickly fix your code by adding quotation marks around Book. The value of # InsertValues should be
'Book', 100
instead of simply
Book, 100
You need to add quotation marks around each string value; otherwise, strings are interpreted as names, which is not valid.
EDIT : (in response to a comment) If all columns are of varchar type, you can put quotes around the entire string, and replace all commas with the quote-comma-quote pattern, like this:
values('''+REPLACE(#InsertValues,',',''',''')+''')'
* You should not put code like this into production, because it can be manipulated to harm your system rather severely. Here is a good illustration of the problem (link).
Try:
DECLARE #DestinationFields VARCHAR(200);
SET #DestinationFields = 'Col1, Col2, Col3'
DECLARE #InsertValues VARCHAR(200);
SET #InsertValues = '1, 2, 3'
DECLARE #SQLString VARCHAR(1000);
SET #SQLString = 'INSERT INTO tbl_test (' + #DestinationFields + ') VALUES (' + #InsertValues + ')';
EXEC (#SQLString)
However, this is very open to SQL Injection attacks. But, it will do what you require.
The Curse and Blessing of Dynamic SQL

How do I remove single quotes from a table in postgresql?

I searched around quite a bit, it would be great if someone could link me to a solution or answer my query.
The thing is I have a postgresql table that contains a lot of single quotes and I cant figure out how to get rid of them, because obviously this
update tablename set fieldname= NULL where fieldname=' ;
wont work.
Better use replace() for this:
UPDATE tbl SET col = replace(col, '''', '');
Much faster than regexp_replace() and it replaces "globally" - all occurrences of the search string. The previously accepted answer by #beny23 was wrong in this respect. It replaced first occurrences only, would have to be:
UPDATE tbl SET col = regexp_replace(col, '''', '', 'g');
Note the additional parameter 'g' for "globally". Read about string functions in the manual.
Aside: the canonical (and SQL standard) way to escape single quotes (') in string literals is to double them (''). Using Posix style escape sequences works, too, of course. Details:
Insert text with single quotes in PostgreSQL
update tablename set fieldname= NULL where fieldname='''' ;
or
update tablename set fieldname= NULL where fieldname=E'\'' ;
insert into table1(data) values ($$it's a string, it's got some single quotes$$)
Use $$ before and after the string. It will insert data.

SQL Server - Replacing Single Quotes and Using IN

I am passing a comma-delimited list of values into a stored procedure. I need to execute a query to see if the ID of an entity is in the comma-delimited list. Unfortunately, I think I do not understand something.
When I execute the following stored procedure:
exec dbo.myStoredProcedure #myFilter=N'1, 2, 3, 4'
I receive the following error:
"Conversion failed when converting the varchar value '1, 2, 3, 4' to data type int."
My stored procedure is fairly basic. It looks like this:
CREATE PROCEDURE [dbo].[myStoredProcedure]
#myFilter nvarchar(512) = NULL
AS
SET NOCOUNT ON
BEGIN
-- Remove the quote marks so the filter will work with the "IN" statement
SELECT #myFilter = REPLACE(#myFilter, '''', '')
-- Execute the query
SELECT
t.ID,
t.Name
FROM
MyTable t
WHERE
t.ID IN (#myFilter)
ORDER BY
t.Name
END
How do I use a parameter in a SQL statement as described above? Thank you!
You could make function that takes your parameter, slipts it and returns table with all the numbers in it.
If your are working with lists or arrays in SQL Server, I recommend that you read Erland Sommarskogs wonderful stuff:
Arrays and Lists in SQL Server 2005
You need to split the string and dump it into a temp table. Then you join against the temp table.
There are many examples of this, here is one at random.
http://blogs.microsoft.co.il/blogs/itai/archive/2009/02/01/t-sql-split-function.aspx
Absent a split function, something like this:
CREATE PROCEDURE [dbo].[myStoredProcedure]
#myFilter varchar(512) = NULL -- don't use NVARCHAR for a list of INTs
AS
SET NOCOUNT ON
BEGIN
SELECT
t.ID,
t.Name
FROM
MyTable t
WHERE
CHARINDEX(','+CONVERT(VARCHAR,t.ID)+',',#myFilter) > 0
ORDER BY
t.Name
END
Performance will be poor. A table scan every time. Better to use a split function. See: http://www.sommarskog.se/arrays-in-sql.html
I would create a function that takes your comma delimited string and splits it and returns a single column table variable with each value in its own row. Select that column from the returned table in your IN statement.
I found a cute way of doing this - but it smells a bit.
declare #delimitedlist varchar(8000)
set #delimitedlist = '|1|2|33|11|3134|'
select * from mytable where #delimitedlist like '%|' + cast(id as varchar) + '|%'
So... this will return all records with an id equal to 1, 2, 33, 11, or 3134.
EDIT:
I would also add that this is not vulnerable to SQL injection (whereas dynamic SQL relies on your whitelisting/blacklisting techniques to ensure it isn't vulnerable). It might have a performance hit on large sets of data, but it works and it's secure.
I have a couple of blog posts on this as well, with a lot of interesting followup comments and dialog:
More on splitting lists
Processing list of integers