T-SQL: Quote syntax in building SQL string - tsql

I am building a SQL sting, mostly the WHERE clause, on the fly based on parameters passed in and the executing the built string. So in the end it is: EXEC (#strSELECT + #strFROM + #strWHERE + #strORDERBY).
My #strSELECT looks like: SET #strSELECT = 'SELECT DISTINCT FieldA, FIELDB, FIELDC'
This all works so far, but now I added a nested function field to the end of #strSELECT so the whole #strSELECT now looks like: SET #strSELECT = 'SELECT DISTINCT FieldA, FIELDB, FIELDC, UPPER(REPLACE(CONVERT(VARCHAR, CAST(MyStringDateField AS DATETIME),6),' ','-')) AS FormattedDate'
I know the new nested function field works because I tested it without concantenation and I also know that the problem is with the single quotes [' ','-'] within the function. Can anyone help me with the correct quote syntax when building the query string? thnx.

You'll have to make your nested function look like this:
UPPER(REPLACE(CONVERT(varchar, CAST(MyStringDateField AS datetime),6),'' '',''-''))

Double up on the quotes inside the string. This works for me and returns "02-MAR-11":
DECLARE #strSELECT nvarchar(200)
SET #strSELECT = 'SELECT UPPER(REPLACE(CONVERT(VARCHAR, CAST(GETDATE() AS DATETIME),6),'' '',''-'')) AS FormattedDate'
EXECUTE sp_executesql #strSELECT

To insert a single quote in a T-SQL string you prepend another single quote. Thus your #strSelect statement becomes
SET #strSELECT = 'SELECT DISTINCT FieldA, FIELDB, FIELDC, UPPER(REPLACE(CONVERT(VARCHAR, CAST(MyStringDateField AS DATETIME),6),'' '',''-'')) AS FormattedDate'
That doesn't mean that this is the right way to do it though. You should try to use parameterized queries wherever possible to avoid sql injection attacks

Related

How to pick up data from row and put it into tPostgresqlInput?

I have a requets which giving me an ids. I need to iterate them into another request, so I have a sheme like this: scheme
In tPostgresqlInput I have this code rc.id = upper('18ce317b-bf69-4150-b880-2ab739eab0fe') , but instead of id I need to put smthn like globalMap.get(row4.id). How did I do this?
Apparently this is a syntax issue
Try with :
"select * FROM table LEFT JOIN table on parameter JOIN table on parameter
WHERE 1=1 AND
column = 'content'
AND upper(rc.id) = upper('"+((String)globalMap.get("row4.id")) +"')"
Expressions in tDBInput should always begin and end with double quotes.
Don't forget to cast globalMap.get() with the type of your element (here I put String)
.equals is not a DB function but a java function. I have replaced it with '='
Let me know if it's better

Postgresql if null in field,the whole sql is null

I use this sql to execute sql:
v_sql4 :='
INSERT INTO public.rebatesys(head,contract_no,history_no,f_sin,line_no,s_line_no,departmentcd,catagorycd,jan,seriescd,f_exclude, f_del,ins_date,ins_time,ins_user_id,ins_func_id,ins_ope_id,upd_date,upd_time,upd_user_id,upd_func_id,upd_ope_id)
VALUES (0, '''||v_contract_no||''', '||v_history_no||',1, '||v_line_no||', '||v_down_s_line_no||', '||coalesce(v_deptCD,null)||', '||0||', '''||v_singleJan||''','''||0||''','||v_fExclude||',
0, current_date, current_time, '||v_ins_user_id||', 0, 0,
current_date,current_time,'||v_upd_user_id||',0, 0);';
RAISE NOTICE 'v_sql4 IS : %', v_sql4;
EXECUTE v_sql4;
But when field "v_deptCD" is null,the whole sql is null,even I use coalesce,I still can't do id, the out put is :
NOTICE: v_sql4 IS : <NULL>
How to fix it?
When v_deptCD is null, you want to replace it by the string 'null', not the keyword.
', '||coalesce(v_deptCD,'null')||', '
You can use this
case when v_deptCD notnull then v_deptCD else null end
or use this for string concatination inside sql
concat(field1, ', ', field2)
Alternative approach to JGH solution is to use function format(your_string, list, of, values), it can ignore NULL values, but has the option to display them as NULL if you use %L in your format string. It will however single quote numbers if you use that format specifier, requiring casting in some cases.
Format arguments according to a format string. This function is similar to the C function sprintf. See Section 9.4.1.
But in my opinion best solution is to use USING clause and pass values in there. It looks kinda like prepared statement, protects you from SQL Injection, but does not cache plans like prepared statements. There are simple examples on how to do this in documentation for executing dynamic commands.
EXECUTE 'SELECT count(*) FROM mytable WHERE inserted_by = $1 AND inserted <= $2'
INTO c
USING checked_user, checked_date;

How to correctly insert a parameter into an existing sql query to avoid SQL Injections

I have seen some answers already but my query is a little bit different:
Here is an original query:
cmd.CommandText = "select count(Table1.UserID) from Table1 INNER JOIN
Table2 ON Table1.ID = Table2.ID where Table1.Userid = " + UserID + " and
Table1.Number != '" + Number +"' and Table2.ID < 4";
Here is a modified query for SQL Injections:
cmd.CommandText = "select count(Table1.UserID) from Table1 INNER JOIN
Table2 ON Table1.ID = Table2.ID where Table1.Userid = #userId and
Table1.ID != #Number and Table2.ID < 4";
If you can notice, the first query has UserId surrounded by double quotes: ..." + UserID +"... and Number us surrounded by single and double quotes: ...'" + Number + "'...
Here is how I'm setting parameters:
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#Number", Number);
cmd.Parameters.AddWithValue("#userId",UserID);
where UserID is an integer and Number is a string.
So, my question is, if the modified query formatted the right way? Is there any difference how to put #UserId and #Number parameters into a query considering the different ways they are specified in the original query?
I have been working on .net Mvc for a long time, and I can ensure you the parameters are correctly fixed by yourself in the second case, and you do not need to worry. By the way you can still debug and test if you can inject yourself. Briefly, your code looks great and invulnerable.
This is how i do it, which is similar and also as safe as yours:
string Query = #"select a1, a2, a3, a4 from table1 where a1 in
(select b1 from table2 where b2 = #start or b2 = #end)";
using (SqlCommand Comm = new SqlCommand(Query, Conn))
{
Comm.Parameters.Add("#start", SqlDbType.NVarChar).Value = start;
Comm.Parameters.Add("#end", SqlDbType.Int).Value = end;
}
In your initial query, the double quotes belonged to the actual text of the query, not the parameter. The single quotes you would add when appending a string into the sql query. I do not know why you would put single quotes around something called Number. If in fact that is a numeric type variable, it can go into the query without the single quotes. But if it has single quotes, the only thing that happens is that Sql sees it as a string, and then converts it to a number if it is going to use it as one. For example, if Table1.Number is numeric.
But, as you have noted, building your query string by appending your parameters into your query string is terrible practice as it opens the door, wide open, for sql injection attacks. So, you go with parameterized queries, as you have.
In parameterized queries, you do not worry about quotes. For parameters that are string values, the environment will worry about encasing them in quotes as it builds the command to pass to your sql db. For parameters that are numeric, quotes are not needed, and again, that is taken care of for you.
I think your 2nd version of the query is much better and from the looks of it, it should work just fine.
Adding parameters instead of concatenating your values is much safer against sql injection. And in this example, and I can't see any way to do a sql injection.
EDIT
When using parametrised queries, you dont need to add any quotes, just like when you declare a variable and use it in a query - you dont need to use quotes.
DECLARE #x CHAR(10) = 'abc'
SELECT #x
When using concatenation of values inside a query, if the value you're trying to add into the query is a CHAR, you need to wrap it between single quotes. If it's an INT, it shouldn't be wrapped between single quotes.
SELECT 'abc', 1
The double quotes you have in your first query dont have anything to do with the sql statement, they are used in your c# code to build the sql statement string you're trying to assign to CommandText.
string abcVar = "abc";
int intVar = 1;
string sqlCommand = "SELECT '" + abcVar + "', " + intVar;

Escaping formula for Grails derived properties

Grails offers derived properties to generate a field from a SQL expression using the formula mapping parameter:
static mapping = {
myfield formula: "field1 + field2"
}
I'm trying to use the formula parameter with a PostgreSQL database to make a concatenated field. The syntax is a little strange since PostgreSQL 8.4 doesn't yet support concat_ws:
static mapping = {
myfield formula: "array_to_string(array[field1, field2],' ')"
}
The produced SQL shown with loggingSql = true in the DataSource config has the table prefix inserted into some strange places:
select table0_.field1 as field1_19_0_,
table0_.field2 as field2_19_0_,=
array_to_string(table0_.array[field1, table0_.field2], ' ') as formula0_0_
from test_table table0_ where table0_.id=?
The table prefix errantly appears before array but not before field1 in the derived formula. Is there a way to escape the prefix or correct this behavior more explicitly?
This is just an issue with parsing the formula syntax. GORM tries to insert the table prefix for unquoted expressions not followed by parens, so the ARRAY[] notation trips it up.
My solution was to define the concat_ws function:
CREATE OR REPLACE FUNCTION concat_ws(separator text, variadic str text[])
RETURNS text as $$
SELECT array_to_string($2, $1);
$$ LANGUAGE sql;
The GORM formula parameter can now avoid the ARRAY[] syntax, and works as expected.
myfield formula: "concat_ws(' ', field1, field2)"
I had a very similar problem and solved it by adding single-quotes around the things that GORM was trying to prefix:
static mapping =
{
dayOfYear formula: " EXTRACT('DOY' FROM observed) "
}
GORM then produced this, which worked:
select
EXTRACT('DOY' FROM observed) as y1_
This may not work in all cases, but I hope it helps somebody.

TSQL syntax for enclosing search terms within brackets

I believe [ and ] are special characters when using with LIKE clause in TSQL( SQlserver 2005 if it matters). How do i escape the search term in the stored procedure, i did below but does not return valid records even while exists
SELECT * FROM Table WHERE Column LIKE '%['+ #searchedTerm +']'
So which is the valid thing to do, when searching like above??
You need to escape the opening (not the closing) bracket like this:
LIKE '%[[]' + #searchedTerm + ']'
The MSDN page for LIKE has a section "Using Wildcard Characters As Literals"
Edit, after comment
LIKE '[[]cap]%' searches for a name containing the string [cap]
LIKE '[wel]%' searches for a name containing one of the letters w, e or l
Try this:
DECLARE #searchedTerm as varchar(50);
SET #searchedTerm = 'TEST VALUE'
SELECT * FROM Table WHERE Column LIKE '%[[]' + #searchedTerm +']'
try this:
SELECT * FROM Table WHERE Column LIKE '%/['+ #searchedTerm +']' {escape '/'}