Creating a dynamic sql query - sql-server

Please see this SQL code:
DECLARE #MyQuery nvarchar(max)
set #MyQuery = 'SELECT TOP 1 #TranslatedMessageOutput =
' + #LanguageName + ' FROM local_translation WHERE English =
'+CHAR(39)+CHAR(39)+Convert(nvarchar(50),
(select English from inserted))
+CHAR(39)+CHAR(39)+CHAR(39)+
' AND [' + #LanguageDateName + '] NOT LIKE ''%1900%'''
If I type abc for English this query works just fine.
But if I type 'abc' for English the query is throwing an error:
Unclosed quotation mark after the character string "". Incorrect syntax near "."
How do I solve this?

I suspect you will need to escape the output of this query:
(select English from inserted)
As in
(select replace(English, '''', '''''') from inserted)
The above will replace ' by '' before concatenating the outcome to your dynamic SQL statement. But with any dynamic SQL, I strongly suggest you make use of bind values to prevent such SQL syntax errors and SQL injection! I.e. you should be able to write something like this:
declare #English;
select #English = English from inserted;
set #MyQuery = 'SELECT TOP 1 #TranslatedMessageOutput =
' + #LanguageName +
' FROM local_translation WHERE English = #English'
' AND [' + #LanguageDateName + '] NOT LIKE ''%1900%''';
-- ...

In Dynamic sql queries in order to avoid confusion ,use Char(39) instead of '.
Eg :
SET #T='SELECT '+CHAR(39)+'NAME'+CHAR(39)
returns
SELECT 'NAME'

Related

Conversion failed when converting the varchar value '43302001-8' to data type int

When I try to execute the following:
DECLARE #sqlText nvarchar(1000);
SET #sqlText = N'SELECT TOP ' + CAST((:intValue) AS VARCHAR(20)) + 't_stamp, PART_NUM, ' + :Column + ' FROM dbo.press_7_recipes_log WHERE PART_NUM = ' + CAST(:text AS VARCHAR(20))
Exec (#sqlText)
I am getting the following
error:com.microsoft.sqlserver.jdbc.SQLServerException: Conversion failed when converting the varchar value '43302001-8' to data type int.
Any help would be greatly appreciated, not sure what else is required here.
:intValue is of type int4
:text is of type string
:Column is of type string (This is pulling a specified column from the database and why I think this needed to be a dynamic query)
Tried multiple attempts at googling the issue and changing the command with the same outcome. If I change the PART_NUM in the where to a column that is of type int the code works fine, any string related column does not.
The problem is that after your preparation the query becomes:
SELECT TOP 666 t_stamp, PART_NUM, ANOTHER_COLUMN FROM dbo.press_7_recipes_log WHERE PART_NUM = 43302001-8
And since 43302001-8 is an INTEGER=43301993, SQL Server converts PART_NUM column to INT, which doesn't work since it probably contains non-integers.
You need to change your dynamic query to this me thinks:
DECLARE #sqlText nvarchar(1000);
SET #sqlText = N'SELECT TOP ' + CAST((:intValue) AS VARCHAR(20)) + 't_stamp, PART_NUM, ' + :Column + ' FROM dbo.press_7_recipes_log WHERE PART_NUM = ''' + REPLACE(CAST(:text AS VARCHAR(20)), '''', '''''') + ''''
Exec (#sqlText)
This will change WHERE to: PART_NUM = '43302001-8'
But as others noticed, you have a lot of possibilities for SQL Injections here. So i'd probably get rid of this code and rewrite it to avoid dynamic SQL

Invalid Column name on parameter input

Really wrecking my head here and as with many sql mess up I know it is probably something silly and stupid but I just cant seem to get it to work.
I have a stored procedure which is this..
ALTER PROCEDURE [dbo].[RETURN_DATA](#TABLE_param VARCHAR(7),#COUNTRY_param VARCHAR(2),#FILEDATE_param int,#TTKT_param VARCHAR(6))
AS
BEGIN
SET NOCOUNT ON;
SELECT #SQL = 'Select * from ' + #TABLE_param + ' WHERE COUNTRY = ' + #COUNTRY_param + ' AND MONTH(Fil_Dte) = ' + cast(#FILEDATE_param as varchar(20)) + ' AND TRNN = '+ #TKTT_param
EXECUTE(#SQL)
END
I'm using it in a vb.net windows form app so applying the parameters there. But trying to run it in SSMS with this
exec RETURN_DATA #COUNTRY_param='GB',#FILEDATE_param=4,#TABLE_param='table30',#TTKT_param='000000'
Returns the error
Invalid column name 'GB'. which i find strange as I never called for a column called GB but called for rows with GB in the column COUNTRY in my where clause?
I know this hopefully is a simple fix so any help would be greatly appreciated and also even if you think theres a better way to go about writing the SP!
Thanks in advance guys.
I'd recommend parameterising the SQL which will guard against SQL injection and you don't have to worry about escaping quotes as below
ALTER PROCEDURE [dbo].[RETURN_DATA](#TABLE_param VARCHAR(7),#COUNTRY_param VARCHAR(2),#FILEDATE_param int,#TTKT_param VARCHAR(6))
AS
BEGIN
SET NOCOUNT ON;
SELECT #SQL = 'Select * from ' + #TABLE_param + ' WHERE COUNTRY = ''' + #COUNTRY_param + ''' AND MONTH(Fil_Dte) = ' + cast(#FILEDATE_param as varchar(20)) + ' AND TRNN = '''+ #TKTT_param +''''
EXECUTE(#SQL)
END
Use sp_executesql to run dynamic sql
DECLARE #SQL NVARCHAR (4000);
SET #SQL = '
Select *
from ' + QUOTENAME(#TABLE_param) + '
WHERE COUNTRY = #COUNTRY_param
AND MONTH(Fil_Dte) = #FILEDATE_param
AND TRNN = #TTKT_param
';
EXEC sp_executesql #SQL,
N'#COUNTRY_param VARCHAR(2), #FILEDATE_param int, #TTKT_param VARCHAR(6)',
#COUNTRY_param, #FILEDATE_param, #TTKT_param;
sp_executesql

T-SQL openquery doesn't update on NULL value

I have a Microsoft SQL Server trigger that updates a remote database with new values when the local database is updated. Everything works fine, and I tested the script and it updates fine, unless there is a null value.
The code is below:
DECLARE #TSQL nvarchar(4000);
SELECT #TSQL =
'UPDATE
OPENQUERY(TEST,''SELECT * FROM test_db WHERE id = ' + convert(VARCHAR(MAX), #id) +''')
SET
parent_id = ' + convert(VARCHAR(MAX), #parent_id) + ', user_id = ' + convert(VARCHAR(MAX), #user_id) + ', item_id = ' + convert(VARCHAR(MAX), #item_id) + ''
EXEC (#TSQL)
Everything works well if all the fields have values, but if one column is null, then the query doesn't update the row at all, no errors thrown. I tried to use COALESCE() to change the null variables to empty strings, and it will then update the row, but all the null columns become 0's and I want them to stay as NULL values. All the columns in both database allow null values and default to null so I'm not sure why I cannot update the database.
Any help would be nice, thanks!
Try this. Use ISNULL and if the value is null, use 'NULL' in single quotes. When the string is concatenated together, it won't keep the quotes, so it would set it to a NULL value and not a string of 'NULL'.
DECLARE #TSQL nvarchar(4000);
SELECT #TSQL =
'UPDATE
OPENQUERY(TEST,''SELECT * FROM test_db WHERE id = ' + convert(VARCHAR(MAX), #id) +''')
SET
parent_id = ' + ISNULL(convert(VARCHAR(MAX), #parent_id), 'NULL') + ',
user_id = ' + ISNULL(convert(VARCHAR(MAX), #user_id), 'NULL') + ',
item_id = ' + ISNULL(convert(VARCHAR(MAX), #item_id), 'NULL') + ''
EXEC (#TSQL)

Invalid Object Name - SQL server 2005

when executing the following stored procedure I get Invalid Object Name dbo.Approved. The object dbo.Approved does exist, so presumably this is something to do with the way i pass the table name in as the parameter?
I should also add that i get the error either by executing the procedure via .NET, or from within SMSS.
#tableName as nvarchar(100)
AS
BEGIN
EXEC('
UPDATE T1
SET T1.NPTid = dbo.Locations.NPT_ID
FROM ' + '[' + #tableName + '] As T1
INNER JOIN dbo.Locations ON T1.Where_Committed = dbo.Locations.Location_Name
')
END
Edit after receiving help from Joe and JNK the sproc is now this but i get the error
Msg 102, Level 15, State 1, Procedure sp_Updater, Line 14
Incorrect syntax near 'QUOTENAME'.
new sproc
#tableName as nvarchar(100),
#schemaName as nvarchar(20)
AS
BEGIN
EXEC('
--Update NPT
UPDATE T1
SET T1.NPTid = dbo.Locations.NPT_ID
FROM ' + QUOTENAME(#schemaName) + '.' + QUOTENAME(#tableName) + ' As T1
INNER JOIN dbo.Locations ON T1.Where_Committed = dbo.Locations.Location_Name
')
END
With the square brackets in you string, your table reference turns into [dbo.Approved] which is not valid. The reference should be [dbo].[Approved] instead.
You might want to consider passing schema name and table name as two separate parameters.
It would also be better to use the QUOTENAME function instead of hard coding the square brackets.
declare #sql nvarchar(1000)
set #sql = N'UPDATE T1
SET T1.NPTid = dbo.Locations.NPT_ID
FROM ' + QUOTENAME(#schemaName) + N'.' + QUOTENAME(#tableName) + N' As T1
INNER JOIN dbo.Locations ON T1.Where_Committed = dbo.Locations.Location_Name
'
EXEC (#sql)
If you use brackets for the three-part-name, you need to have brackets around each section but not the period, i.e.:
[dbo].[Approved]
If you pass dbo.Approved as your parameter, your Dynamic SQL is reading it as [dbo.Approved] which would only work if you had a table named that (i.e. the dbo. is part of the table name not the schema).
Change it to:
'...[dbo].[' + #tablename + ']...
And just pass Approved as the parameter.
Your wrapping the id too early so '[' + #tableName + '] is getting translated to [dbo.approved] when it should be [dbo].[Approved]
Table names and column names are actually sysname (which is, as I recall an NVARCHAR(128) or NVARCHAR(256) - off the top of my head I don't quite remember)
Also, You are vulnerable to a SQL Injection Attack. You should validate that #tableName is a real table by checking it against INFORMATION_SCHEMA.TABLES
Finally, just to be absolutely sure, in case the real table has some odd characters in it, you should use QUOTENAME(#tableName) to fully escape the table name.

SQL Server equivalent to DBMS_METADATA.GET_DDL

I was wondering if there is an equivalent in SQL Server 2008 to Oracle's DBMS_METADATA.GET_DDL Function? You can pass this function a table name and it will return the ddl for that table so that you can use it to build a script for a schema.
I know I can go into SSMS and use that, but I would prefer to have a t-sql script that would generate the ddl for me.
Thanks,
S
I using this query for generate query but this work for 1 table :
declare #vsSQL varchar(8000)
declare #vsTableName varchar(50)
select #vsTableName = 'Customers'
select #vsSQL = 'CREATE TABLE ' + #vsTableName + char(10) + '(' + char(10)
select #vsSQL = #vsSQL + ' ' + sc.Name + ' ' +
st.Name +
case when st.Name in ('varchar','varchar','char','nchar') then '(' + cast(sc.Length as varchar) + ') ' else ' ' end +
case when sc.IsNullable = 1 then 'NULL' else 'NOT NULL' end + ',' + char(10)
from sysobjects so
join syscolumns sc on sc.id = so.id
join systypes st on st.xusertype = sc.xusertype
where so.name = #vsTableName
order by
sc.ColID
select substring(#vsSQL,1,len(#vsSQL) - 2) + char(10) + ')'
If you are looking for a TSQL solution, it is quite verbose, as [this example]¹ shows.
A shorter alternative would be using the SMO library (example)
¹ Link for this example deleted. The way Internet Archive Wayback Machine displayed an error saying that they could not display the content. And following the link to the original went someplace malicious. (Grave errors, instruction to call some number, etc.)

Resources