sql variables - tsql

Can somebody help me figure out why the sql statement doesn't like the following line
' and ' + #SearchCat + 'like '%'+#Keywords+'%''. It has to do with the number of single quotes but I can't figure out. How do the quotes work. What's the logic?
DECLARE #strStatement varchar(550)
declare #state as varchar(50)
declare #district as varchar(50)
declare #courttype as varchar(50)
declare #SearchCat as varchar(50)
declare #KeyWords as varchar (50)
select #State ='FL'
select #district = '11'
select #courtType = '1'
select #SearchCat='CaseNumber'
select #KeyWords='File'
select #strStatement= 'SELECT CaseNumber FROM app_Case
where State ='''+ #State+
''' and District='''+ #District+
' and ' + #SearchCat + 'like '%'+#Keywords+'%''
exec (#strStatement)

I was missing a space before 'like'
You've also got the wrong number of single-quotes around your ‘%’ characters, which will confuse it.
Incidentally, you've made yourself a nice little SQL injection security hole there, from inside SQL itself! If one of the parameters contains an apostrophe your sqlStatement will break and any rogue SQL in the parameter name would be executed.
You can use the REPLACE function to double up single quotes to prevent this attack:
' AND '+QUOTENAME(#SearchCat)+' LIKE ''%'+REPLACE(#Keywords, '''', '''''')+'%''...'
(The QUOTENAME is needed if the column name contains out-of-band characters or is a reserved word.)
A cleaner (but quite verbose) approach to generating the SQL than tediously REPLACEing every string literal yourself is to use sp_executesql. For example:
SELECT #strStatement= N'
SELECT #Number= CaseNumber FROM app_Case
WHERE State=#State AND District=#District
AND '+QUOTENAME(#SearchCat)+N' LIKE ''%''+#Keywords+''%''
';
SELECT #params= N'#State varchar(50), #District varchar(50), #Keywords varchar(50), #Number int OUTPUT';
EXECUTE sp_executesql #strStatement, #params, #State, #District, #Keywords, #Number OUTPUT;
Incidentally if #searchCat can only have a small number of different values, you can use a workaround to avoid having to do any of this laborious dynamic-SQL nonsense at all:
SELECT CaseNumber FROM app_Case
WHERE State=#State AND District=#District
AND CASE #searchCat
WHEN 'searchableColumnA' THEN searchableColumnA
WHEN 'searchableColumnB' THEN searchableColumnB
END LIKE '%'+#Keywords+'%';
See this rather good exploration of dynamically-created SQL statements in T-SQL for more background and some of the risks you face.

I figure it out. I was missing a space before 'like'

Related

Understanding PLPGSQL basics

I there, I am new to PL/pgSQL, the project I am working on started using it for some data-intensive handling implementations, I am failing to understand some basic foundations, even reviewing the docs again and again
So I have a function that looks like this:
CREATE OR REPLACE FUNCTION sum_stuff_over_value(
param1 uuid,
param2 uuid,
param3 enum
)
RETURNS float AS
$$
DECLARE
table_name varchar;
column_name varchar;
resolution integer;
another_table varchar := 'name_of_another_table';
another_column varchar := 'name_of_another_column';
sum float;
BEGIN
-- Get data from another table fiven a param2 ID
SELECT * INTO table_name, column_name, esolution
FROM get_table_and_column_by_Id(param2, param3);
-- Sum table column over region
EXECUTE format(
'SELECT sum(grid_mat.%I * grid_def.%I)
FROM
get_uncompact_region($1, $2) region
INNER JOIN %I grid_mat ON grid_mat.index = region.index
INNER JOIN %I grid_def ON grid_def.index = region.index;
', column_name, another_column, table_name, another_table)
USING param1, resolution
INTO sum;
RETURN sum;
END;
$$
LANGUAGE plpgsql;
I'd say I fairly understand the very very basic flow, instantiate vars, some of them assigned, etc...
What I am struggling the most is understanding which value holds %I, and how here
INNER JOIN %I grid_mat ON grid_mat.index = region.index
INNER JOIN %I grid_def ON grid_def.index = region.index;
%I is holding (I believe) different values to join different tables
I tried to figure it out by raising notices to print values, but I couldn't make it work. I am trying to add some breakpoints to debug this isolated in the DB but as it's new to me is not being straightforward
Can anyone help me understand what is going on here?
Thanks a lot in advance
You should read the documentation of format. The first %I will be replaced by the value of the second argument of format (column_name), escaped as an identifier, the second %I will be replaced by the value of another_column, and so on.
FROM https://www.postgresql.org/docs/14/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-ONEROW.
around section: Example 43.1. Quoting Values in Dynamic Queries
quote:
Dynamic SQL statements can also be safely constructed using the format function (see Section 9.4.1). For example:
EXECUTE format('UPDATE tbl SET %I = %L '
'WHERE key = %L', colname, newvalue, keyvalue);
Section 9.4.1 LINK: :
https://www.postgresql.org/docs/14/functions-string.html#FUNCTIONS-STRING-FORMAT
Quote from Section 9.4.1
type (required) The type of format conversion to use to produce the
format specifier's output. The following types are supported:
s formats the argument value as a simple string. A null value is
treated as an empty string.
I treats the argument value as an SQL identifier, double-quoting it if
necessary. It is an error for the value to be null (equivalent to
quote_ident).
L quotes the argument value as an SQL literal. A null value is
displayed as the string NULL, without quotes (equivalent to
quote_nullable).
There have serval examples, quote:
SELECT format('INSERT INTO %I VALUES(%L)', 'Foo bar', E'O\'Reilly');
Result: INSERT INTO "Foo bar" VALUES('O''Reilly')
Finally explain:
your EXECUTE format string have 4 %I. Then
1st %I refer to column_name
2nd %I refer to another_column
3rd %I refer to table_name
4th %I refer to another_table

SSIS How to Use Parameters with IN Clause

emailVariable = john#example.com, sally#testing.com
SQL Query:
select *
from [table_1]
where email in (?);
Parameter set to use emailVariable.
This returns nothing, both emails are valid.
Am I doing something wrong?
I am using an OLE DB Source Editor.
You can also use string_split:
declare #stringToSplit varchar(255) = 'john#example.com, sally#testing.com'
select *
from [table_1]
where email in (
select ltrim(rtrim(value)) from string_split(?,',')
)
String_Split will return a table of values based on your input string and the delimiter. In your case you also need ltrim and rtrim because of extra spaces.
This is a classic mistake. Although the following works:
where email in ('john#example.com','sally#testing.com')
you cannot use one variable to put a multitude of values. The comma(s) is not part of the value string, it is considered code. What you can do is use dynamic sql:
declare #emailVariable nvarchar(max)=N'''john#example.com'',''sally#testing.com''' -- notice the escaped quotes
declare #sql nvarchar(max)
set #sql=N'select * from [Table_1] where email in (' + #emailVariable + ')'
exec(#sql)

How do convert below code from T-SQL into DB2 LUW?

How do I convert this code from T-SQL into DB2 LUW, it seems so easy with T-SQL but in DB2 can't find any solution. See code below:
DECLARE #sqlCommand varchar(1000)
DECLARE #columnList varchar(75)
DECLARE #city varchar(75)
SET #columnList = 'AddressID, AddressLine1, City'
SET #city = '''London'''
SET #sqlCommand = 'SELECT ' + #columnList + ' FROM Person.Address WHERE City = ' + #city
EXEC (#sqlCommand)
The problem is that you can’t ‘select to nowhere’ in a compound statement in DB2. Db2 CLP can return you the result set of a single sql statement, but it doesn’t try to do the same for select statements in a compound statement. If you want to print the result set from a select statement in a compound statement, you can, for example, declare a cursor, fetch it in a loop, and use dbms_output.put_line calls to print the values of variables.
Not Pretty but you can find an example of the bottom of this page:
Stored Procedures and Dynamic SQL Returning a Result set
Essentially you most:
1) create a dynamic SQL string
2) prepare the string into a statement
3) Link the statement to a cursor you're going to declare as WITH RETURN
Opening the cursor will be the last line in your procedure.

T-SQL: issue with string concat

I have a set of audio files with names GreenLine1.mp3, GreenLine2.mp3 e.t.c. I'm going to write them into a table as BLOB (I use MS SQL Server'08), here's my sql request:
DECLARE #aud AS VARBINARY(MAX)
DECLARE #num AS INT
-- Load the audio data
SET #num=1
WHILE (#num<38)
BEGIN;
SELECT #aud = CAST(bulkcolumn AS VARBINARY(MAX))
FROM OPENROWSET(
BULK
'C:\Users\Ilya\folder\GreenLine' + CAST(#num AS VARCHAR) + '.mp3',
SINGLE_BLOB ) AS x
-- Insert the data to the table
INSERT INTO Mb2.dbo.Audios (Id, [Content])
SELECT NEWID(), #aud
SET #num = #num + 1
END;
I have an error: Incorrect syntax near '+', expecting ',' or ')'.
If I try to write
'C:\Users\Ilya\folder\GreenLine' +
CAST(#num AS VARCHAR) + '.mp3'
into a variable and put it after BULK, I get Incorrect syntax near #variable, expected STRING, or TEXT_LEX
You can't parametrise or concatenate the parameters of OPENROWSET. It is constant values only.
You'll have to use dynamic SQL and a temp table, or consider using SSIS for example
This article pointed me in the right direction when I had the same issue with OPENQUERY:
https://web.archive.org/web/20120724073530/http://consultingblogs.emc.com/jamespipe/archive/2007/06/28/SQL-Server-2005_3A00_-Passing-variables-into-an-OPENQUERY-argument.aspx
Basically, you can wrap the entire statement in a variable (nvarchar), including the openrowset, and run exec sp_executesql #sql. It gets a little ugly to read around the 's though, because you'll have to escape them with ''.

TSQL varchar string manipulation

I have a variable which contains the following string: AL,CA,TN,VA,NY
I have no control over what I get in that variable (comes from reporting services)
I need to make it look like this: 'AL','CA','TN','VA','NY'
How do I do this?
declare #x varchar(50) = 'AL,CA,TN,VA,NY'
select '''' + REPLACE(#x, ',', ''',''') + ''''
I ended up doing something very similar that I thought I'd post. (I'll give credit to Mitch however)
This takes care of the middle:
SET #StateList = REPLACE(#StateList, ',', ''',''')
Then quote the edges:
SET #WhereClause1 = #WhereClause1 + 'AND customerState IN (''' + #StateList + ''') '
For a more generic answer, when you don't know what your output will look like exactly, use regular expressions.
This would let you you match on something like [A-Z]{2} and replace it with '$&'.
A commenter suggested this is overkill for this task - agreed, if you can guarantee you will always get a string like that. However, other people find these question pages later with similar, but not exact, problems, so other options are helpful to have.
Don't bother with dynamic sql.
You need to convert the string to a table
so
A,B,C,D
becomes
Value
A
B
C
D
using a function like
http://www.sqlusa.com/bestpractices/training/scripts/splitcommadelimited/
then you can use CROSS APPLY (which is like joining to a table, but a table created by a function) or you can just put it in a table variable and join to that
I want to know y does the following script run in SQL and not in T-SQL
DECLARE #tblName varchar(30)
SET #tblName = CONVERT(VARCHAR(20),GETDATE(),112) + 'Table'
DECLARE #sql nvarchar(4000)
SELECT #sql =
'CREATE TABLE "' + #tblName + '"
(
ID VARCHAR(15),
Name VARCHAR(15)
)'
EXEC(#sql)
go
it gives you the error
Msg 170, Sev 15: Line 1: Incorrect syntax near '20090714Table'. [SQLSTATE 42000]