I am using Visual Studio, I'm trying to make a Insert statement using C# and Dynamic SQL.
SQL Command:
comando.CommandText = #"
declare #sql nvarchar(max);
set #sql = 'INSERT INTO ' + #curso + '(Data_Local, Deletado) VALUES ( ' + #date + ', 0)';
exec (#sql);
";
#curso is the Table Name, it's working, Data_Local is a Datetime value, which is not working, and Deletado is a bit value, which is working.
Declaring #curso:
comando.Parameters.Add("#curso", SqlDbType.NVarChar);
comando.Parameters["#curso"].Value = idCurso;
Declaring #date
comando.Parameters.Add("#date", SqlDbType.DateTime);
comando.Parameters["#date"].Value = dateTimePicker2.Value.Date;
Then after:
comando.ExecuteNonQuery();
The error message appears:
'Conversion failed when converting date and/or time from character
string.'
What should I do to read the value from the DateTimePicker, insert into the #date variable, and add it to the SQL Command properly?
Also, I have another doubt, where can I see how the SQL Command is sent? I need to see how the lines really are, how is the SQL Command without the variables, with the values instead.
Sorry if my issue is not explained very well, I'll keep trying to make it clear.
Edit:
I tried:
comando.CommandText = #"
declare #sql nvarchar(max);
set #sql = 'INSERT INTO ' + #curso + '(Data_Local, Deletado) VALUES ( ' + #date + ', 0)';
exec (#sql);
";
comando.Parameters.Add("#date", SqlDbType.NVarChar);
comando.Parameters["#date"].Value = "'" + dateTimePicker2.Value.Date + "'";
New error message:
'The conversion of a varchar data type to a datetime data type
resulted in an out-of-range value. The statement has been terminated.'
Edit. Thanks, solved.
Rather use a Stored Procedure, its awful if you going to use dynamic SQL in your c# application. Firstly because as a DBA, Adhoc queries like these are difficult to maintain, and secondly its easier to manage and also easier to apply to code.
1) Create a Stored Procedure
CREATE PROCEDURE Insert_Test
(
#curso VARCHAR(256),
#date VARCHAR(32)
)
AS
SET NOCOUNT ON
DECLARE #sql NVARCHAR(MAX)
IF ISDATE(#date) = 1 --check if its the correct date
BEGIN
SET #sql = 'INSERT INTO ' + #curso + '(Data_Local, Deletado) VALUES ( ''' + #date + ''', 0)'
EXEC (#sql)
END
2) In your c# code
string tbleName = "Test";
DateTime dte = DateTime.Now.ToString();
comando.ExecuteSqlCommand("exec Insert_Test #curso, #date",
new SqlParameter("curso", tbleName),
new SqlParameter("date", dte)
);
Related
I created the below stored procedure in sql server that requires 3 parameters: Date, URL, & Table Name:
ALTER PROCEDURE [stg].[usp_Delete_Data]
(#DateLookBack date,
#siteUrl nvarchar(100),
#tableName SYSNAME)
AS
BEGIN
SET QUOTED_IDENTIFIER ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'DELETE FROM ' + CONCAT('[stg].[',#tableName,']') +
'WHERE date = ' + FORMAT(#DateLookBack, 'yyyyMMdd') +
'AND siteUrl = ' + #siteUrl
EXEC sp_executesql #Sql
END
When I pass in a url, like 'https://stackoverflow.com', I get an error message:
Incorrect syntax near 'https:'
How do I format the url string so that it can pass into the query successfully?
I'd strongly advise against this method. Having so many tables of the same structure that it requires a single procedure where the table name is dynamic is a code smell in itself.
If you must use dynamic sql though, at least use parameters as much as possible and only inject your table name, i.e.
SET #sql = CONCAT(N'DELETE FROM [stg].' QUOTENAME(#tableName),
' WHERE Date = #Date AND SiteUrl = #SiteUrl;');
EXECUTE sp_executesql #sql, N'#Date date, #SiteUrl nvarchar(100)', #date, #SiteUrl;
To find such issue, all you need is to PRINT the query before you use it! You could examine the query which is executed, if you printed it first.
Replace the commend Exec sp_executesql #Sql with the command PRINT #Sql and examine the query you get.
In your case, after you do it, then when you execute the procedure using the following command, then I can see all the issues.
EXECUTE dbo.[usp_Delete_Data]
#DateLookBack = '2022-02-27' ,#siteUrl = 'https://stackoverflow.com' , #tableName = 'c'
GO
The printed text which we get is: DELETE FROM [stg].[c]WHERE date = 20220227and siteUrl = https://stackoverflow.com
Now we can go over the errors (yes there are multiple errors here) one by one
(1) Notice that the 'WHERE date = ' missing a space before the "where" which might combine the word "where" with the table name that comes before it. You need to add space like ' WHERE date = '
same with the part after the and siteUrl - missing space before the and
(2) Notice this part: siteUrl = https://stackoverflow.com. in the query you are building you do not have quotation marks around the text of the URL => this lead to the error message.
instead of 'and siteUrl = ' + #siteUrl it should be: 'and siteUrl = ''' + #siteUrl + ''''
(3) same issue you have with the date - you do not have quotation marks around the text of the date
instead of ' WHERE date = ' + format(#DateLookBack,'yyyyMMdd') it should be ' WHERE date = ''' + format(#DateLookBack,'yyyyMMdd') + ''''
So, after adding these fixes, you get the following SP (I use PRING instead of execute but you can change this back)
CREATE OR ALTER PROCEDURE [usp_Delete_Data] (
#DateLookBack date,#siteUrl nvarchar(100), #tableName SYSNAME
) AS BEGIN
SET QUOTED_IDENTIFIER ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'DELETE FROM ' + CONCAT('[stg].[',#tableName,']')
--+ ' WHERE date = ' + format(#DateLookBack,'yyyyMMdd')
+ ' WHERE date = ''' + format(#DateLookBack,'yyyyMMdd') + ''''
+ ' and siteUrl = ''' + #siteUrl + ''''
--+ 'and siteUrl = ' + #siteUrl
PRINT #Sql
--Exec sp_executesql #Sql
END
and now if I execute the same query
EXECUTE dbo.[usp_Delete_Data]
#DateLookBack = '2022-02-27' ,#siteUrl = 'https://stackoverflow.com' , #tableName = 'c'
GO
It will print something that looks like:
DELETE FROM [stg].[c] WHERE date = '20220227'and siteUrl = 'https://stackoverflow.com'
BUT! NOW WE CAN GO TO THE MOST PROBLEMATIC ISSUE! Your procedure is open to SQL Injection! You should NOT use such code.
You should use parameters whenever you can when you use sp_executesql and not combine text text. Read the documentation of sp_executesql on how to use parameters as input: https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-executesql-transact-sql
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
DECLARE #Description NVARCHAR(128) = N'MS_Description'
--Just for good measure
SET #Description = N'MS_Description'
The first statement is me trying to use sp_sqlexec by storing my SQL with dynamic parameters in a string:
SELECT #query = #query + 'SELECT * FROM TABLE
WHERE COLUMN = ' + #Description
EXEC sp_sqlexec #query
The above doesn't work, I get the following error:
Invalid column name 'MS_Description'
When I debug through this, the statement is exactly the same as the below query, that works and returns the results that I want.
SELECT *
FROM table
WHERE column = #Description
Could someone please explain the difference and why the below works if it is the exact same thing that's stored in #query? Thank you
The issue with the first query is that you're not adding your quotes back in. It treats the + as a concat, so your statement ends up being
SELECT * FROM TABLE
WHERE COLUMN = MS_Description
We know this won't work, as MS_Description should be 'MS_Description'
What you need to do for the top one to work is
SELECT #query = #query + 'SELECT * FROM TABLE
WHERE COLUMN = ''' + #Description + ''''
The below dynamic SQL throws an error:
The conversion failed when converting character string to smalldatetime data type
My code:
DECLARE #pTimeStamp smalldatetime
SET #pTimeStamp = '2017-05-22 12:15:00'
DECLARE #SQLQuery AS NVARCHAR(4000)
Set #SQLQuery = N'Select *' +
' From SampleTable' +
' Where TimeStamp = ' + #pTimeStamp
EXECUTE sp_executesql #SQLQuery
I've also tried
Convert(smalldatetime, #pTimeStamp, 20)
as well as
CAST(#pTimeStamp AS smalldatetime)
but I only get other errors. I also tried declaring #pTimeStamp as varchar(50) and then converting but still got errors.
Doing something simple like:
DECLARE #pTimeStamp smalldatetime
SET #pTimeStamp = '2012-01-22 12:15:00'
Select *
From SampleTable
Where TimeStamp = #pTimeStamp
ran fine so I'm guessing it has to do with the dynamic SQL.
Please help....
The only truly safe formats for date/time literals in SQL Server, at least for datetime and smalldatetime, are: YYYYMMDD and YYYY-MM-DDThh:mm:ss[.nnn] - Bad habits to kick : mis-handling date / range queries - Aaron Bertrand
You are already using sp_executesql, so why not take advantage of its parameters?
declare #pTimeStamp smalldatetime;
declare #params nvarchar(4000);
declare #sqlquery nvarchar(4000);
set #pTimeStamp = '2017-05-22T12:15:00';
set #params = N'#pTimeStamp smalldatetime';
set #sqlquery = N'
select *
from SampleTable
where TimeStamp = #pTimeStamp';
execute sp_executesql #sqlquery, #params, #pTimeStamp;
rextester demo: http://rextester.com/FVC44260
Dynamic sql reference:
sp_executesql
The curse and blessings of dynamic SQL - Erland Sommarskog
You need to embed the timestamp in single quotes. Try:
Set #SQLQuery = N'Select *' +
' From SampleTable' +
' Where TimeStamp = ''' + #pTimeStamp + ''''
I have a stored procedure that updates several columns in a table and then selects out those columns so I can save them out for a report I run. Currently I am doing the exporting and saving manually though by setting column size in 'Query Options' to 333, turning off all the other options, putting the results to text and then saving the file out with the name and format. I know that there must be a way to automate this though the export and save process though.
I looked into using a job with Vb script, but this is a simple report that is run on demand and not on a schedule; so a job seemed to be overkill. The other option I found was BCP, which looks like what I need. I only know of this as a CMD tool though and can't quite figure out how to leverage this within a SQL query. In case it is needed here is an example of what my stored procedure is doing. Any help is appreciated and thank you in advance. I am using SQL 2008 R2 btw.
UPDATE Table#1 SET Column1 = '' WHERE Column1 = 'XX'
UPDATE Table#1 SET Column2 = '' WHERE Column2 = '000000'
SELECT Column1 +
Column2 +
Column3
FROM Table#1 Where Column4 = 'T'
BCP is a command line utility, however it can be access through SQL with the use of XP Command Shell so you will need xp_cmdshell enabled. The following is a parameterized example of how to call this inside of SQL
DECLARE #Server varchar(50) = 'ServerName' /* Source SQL Server */
DECLARE #FileName varchar(50) = ''
DECLARE #SourceProc varchar(50) = ''
DECLARE #sql varchar(8000)
DECLARE #RunDate varchar(10) = REPLACE(CONVERT(date, getdate()), '-','')
DECLARE #FilePath as varchar(255) = '\\UNCPathtoOutputFile\'
DECLARE #StartDate as Date = (select dateadd(month,datediff(month,0,GETDATE())-2,0))--'1/1/2013' /* Example of required Date as parameter */
DECLARE #EndDate as Date = (SELECT dateadd(month,datediff(month,0,GETDATE())-0,-1))--'2/1/2013' /* Example of required Date as parameter */
-- BCP Export
SET #SourceProc = '[Schema].[StoredProcName]'
SET #FileName = 'SomeOutputFile' + #RunDate + '.txt'
SET #FilePath = #FilePath + #FileName
SET #sql = 'bcp "EXEC [Database].' + #SourceProc + ' ''' + CONVERT(varchar(10),#StartDate, 101) + ''',''' + CONVERT(varchar(10),#EndDate, 101) + '''" QUERYOUT "' + #FilePath + '" -c -t"|" -r\n -S' + #Server + ' -T'
--PRINT(#SQL)
exec master.dbo.xp_cmdshell #sql