stored procedure concatenate two parameters in where clause - sql

I've got an annoying problem, where I pass two parameters into a stored procedure and join them together for use within the WHERE clause of my statement. The first parameter is used in an equals expression, whereas the second is to form an AND clause.
The below extract of the stored proc, shows what I am attempting to do.
Declare #CombinedWhereClause varchar(500), #Sender varchar(10), #AndClause char(200)
Set #Sender = 'Wayne';
Set #AndClause = ' AND Convert(varchar(8), MessageDate, 112) < DATEADD(day, -10, GETDATE())';
Set #CombinedWhereClause = #Sender + #AndClause;
SELECT Messages.Id, Messages.IdExternal, Messages.MessageReference,
FROM Messages
WHERE Messages.Sender =#CombinedWhereClause
If I replace the #CombinedWhereClause with #Sender only then I get back the expected records. If I change the where clause to be:
WHERE Message.MessageDate Convert(varchar(8), MessageDate,112) < DATEADD(day, -10, GETDATE())
then I get all records which are 10 days old. However, when combined I get no results.

In your statement are several flaws:
The comma behind the MessageReference
You try to have WHERE Messages.sender=Wayne but you need quotes ...='Wayne'
You think the db engine is somehow magic :-)
This is - for sure! - not the approach one should chose...
Try this dynamic approach (SQL Server syntax)
Declare #CombinedWhereClause varchar(500), #Sender varchar(10), #AndClause char(200)
Set #Sender = '''Wayne'''; --you need to wrap the word in quotes!
Set #AndClause = ' AND Convert(varchar(8), MessageDate, 112) < DATEADD(day, -10, GETDATE())';
Set #CombinedWhereClause = #Sender + #AndClause;
DECLARE #cmd VARCHAR(MAX)=
'SELECT Messages.Id, Messages.IdExternal, Messages.MessageReference
FROM Messages
WHERE Messages.Sender =' + #CombinedWhereClause;
--check the command
SELECT #cmd;
--if the command is OK you might execute it
--EXEC(#cmd);

Related

SQL set WHERE statement with CASE puts an error with add operator

In the following script, I want to set the WHERE statement only if the CASE is set.
DECLARE #cmdINSERT varchar(8000);
declare #dowhere binary;
declare #date varchar(10);
set #dowhere = 1;
set #date = '14.03.2020';
set #cmdINSERT =
'SELECT *
FROM [TABLE]
WHERE [Changed At] >=
CASE WHEN ' + #dowhere + '
when 1 THEN ''' + #date + '''
ELSE [Changed At]
end;'
EXEC(#cmdINSERT)
But I am getting the error:
The data types varchar and binary are incompatible in the add operator
It seems like you're overly complicating the matter. You don't need a dynamic statement here, nor do you need 2 parameters. Use a single parameter, and pass the value NULL if you don't want to consider it. This is what is known as a "catch up" or "kitchen sink" query:
DECLARE #Date date = '20200314'; --Notice it is NOT a varchar
SELECT {Your Columns} --Replace this with a list of your columns
FROM dbo.YourTable --Replace this with your actual schema and table
WHERE [Changed At] >= #Date --Ideally, don't use names that must be delimit Identified
OR #Date IS NULL
OPTION (RECOMPILE);
The OPTION (RECOMPILE) is there to stop caching of the wrong plan, as if #Date has a value of NULL a full table scan will be required, however, if not then (depending on your indexes) one may not be required, which could be far faster. As the query is incredibly simple, the expense of regenerating query plan will be negligible, and likely <=1ms in cost.
It seems that you have complicated the solution. Why you do not try this?
SELECT *
FROM [Table]
WHERE #dowhere = 0
OR [Changed At] >= #date;
However it would be better if you change the data type of #dowhere to BIT instead of BINARY
Your approach is silly. Get rid of the case in the where altogether if no filtering is desired:
set #cmdINSERT = '
SELECT *
FROM [TABLE]
[where]';
SET #cmdInsert = REPLACE(#cmdInsert,
'[where]',
(CASE WHEN #dowwhere = 1
THEN 'WHERE [Changed At] = #date'
ELSE ''
END)
);
exec sp_executesql #cmdInsert, N'#date date', #date=#date;
Note that this also properly passes in the date as a parameter rather than munging the query string. If the date parameter is not used, that is fine: SQL Server just ignores parameters that are not used.

How to create/add columns using a variable in a loop

I am very new to SQL in that I just finished reading Sams Teach Yourself SQL in 10 Minutes and that is my only SQL knowledge. So now that I'm done with the book, I'm trying to create some tables so I can play around with them. I can easily create a table with a known amount of columns and specified header. Where I am having trouble is creating a table with an unknown amount of columns and a date as the header. What I have tried so far is this:
DECLARE #start_date AS DATE
DECLARE #end_date AS DATE
DECLARE #curr_date AS DATE
DECLARE #column_name AS CHAR(10)
SET #start_date = 2016-01-02
SET #end_date = 2016-12-31
SET #curr_date = #start_date
WHILE #curr_date < #end_date
SET #curr_date = DATEADD(DD, 7, #curr_date)
ALTER TABLE Project_1
ADD #curr_date DOUBLE
What I tried to do here is make a start and end point for the loop and use the loop condition which is stored in a local variable as my column header since that is what I need the column to be titled. I also tried using CAST to cast it as a char but the DBMS is delighted to let me know that there is Incorrect syntax near '#curr_date' on that last line (the ADD line) because it doesn't like that I'm trying to name a column with a local variable (I think). I don't have a sample output but the output should be a table with the first column defined as CHAR and titled emp_name because it will be holding names. All other columns defined as type DOUBLE and should be NULL because they will be holding a number of hours and must have the current date as the header #curr_date. I think all columns added to a table through the ALTER method are defaulted to NULL anyways. I've seen examples of dynamic SQL where you declare a variable to hold the select statement but I don't really understand how they add columns to a table. I'm not sure if this can be done in the CREATE statement but if it can that would be great to see. Also, this needs to be variable in the fact that I could change the #end_date to lets say... they year 2046.
Security is not an issue here
I agree with all of the comments about using ROWs not dynamically adding columns you can always dynamically pivot those latter and it will have more flexibily. So maybe some schema considerations but just to answer your specific question you where close.....
DECLARE #start_date AS DATE
DECLARE #end_date AS DATE
DECLARE #curr_date AS DATE
DECLARE #column_name AS CHAR(10)
SET #start_date = '2016-01-02'
SET #end_date = '2016-12-31'
SET #curr_date = #start_date
WHILE #curr_date < #end_date
BEGIN
DECLARE #SQL NVARCHAR(MAX)
SET #curr_date = DATEADD(DD, 7, #curr_date)
SET #SQL = 'ALTER TABLE TableB
ADD [' + CAST(#curr_date AS VARCHAR(10)) + '] FLOAT'
--PRINT #SQL
EXECUTE (#SQL)
END

Column Set to 0 Instead of Date Stored Procedure

I am trying to set a column to the current date (in the form dd/mm/yyyy) in a stored procedure, however the column simply sets to 0. The code is as below:
USE [DBDataOne]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
declare #dateone varchar(max)
declare #dodate varchar(max)
select #dateone=convert(varchar,GETDATE(),103 )
select #dodate='Update [dbo].[tabfget] set DATEIN='+#dateone
exec (#dodate)
If datein is stored properly (as a date/time), then you don't need to worry about conversion.
Also, you don't need dynamic SQL for this. Just:
Update [dbo].[tabfget]
set DATEIN = cast(getdate() as date);
If -- horror of horrors -- you are storing dates as strings instead of the proper format, then you should fix the database. If that is not possible, you can do:
Update [dbo].[tabfget]
set DATEIN = convert(varchar(10), GETDATE(), 103);
However, if dates have to be stored as strings, then you should always use an ISO-standard format, such as YYYY-MM-DD.
Why can't you directly do like
Update [dbo].[tabfget] set DATEIN = #dateone
(OR)
Update [dbo].[tabfget] set DATEIN = convert(varchar,GETDATE(),103 )
Yes, the format/style 103 should get you / instead of - like
select GETDATE()
will result in 2015-05-29 20:43:38.547
select CONVERT(varchar(15), GETDATE(), 103)
Will result in 29/05/2015
Try this:
declare #dateone varchar(max)
declare #dodate varchar(max)
select #dateone=convert(varchar,GETDATE(),103 )
select #dodate='Update [dbo].[tabfget] set DATEIN='+quotename(#dateone,char(39));
Exec(#dodate);
You definitely should do the update without dynamic sql. But the reason for the zero is that you're not quoting the date as a literal and it gets evaluated as integer division. (Format 103 is mm/dd/yyyy.)

use a variable in the table name when renaming a table in SQL

I am trying to rename a table in SQL Server 2008 R2 using the code below;
declare #date varchar(8)
set #date = convert( varchar(8), getdate(), 112)
exec sp_rename 'LM_SM_Billing_and_Send_Data', 'LM_SM_Billing_and_Send_Data_#date'
My intention is to rename the table with the current date appended.
select convert( varchar(8), getdate(), 112)
returns 20141219
but when I run the rename it names the table;
LM_SM_Billing_and_Send_Data_#date
instead of inserting the date
I'm wondering if it is possible to have it rename to;
LM_SM_Billing_and_Send_Data_20141219
by using the variable in the table name.
I've been googling quite a bit and things seem to point to using dynamic SQL, but I've never used it and not sure what the syntax would be to get the results I am looking for.
The issue you've ran into here, as John Saunders pointed out in his comment, SQL won't substitute the value of your variable into your parameter. (String interpolation)
Another issue you might run into, when trying to work around this problem, is concatenating in the procedure call. The following will also not work.
exec sp_rename 'LM_SM_Billing_and_Send_Data', 'LM_SM_Billing_and_Send_Data_' + #date
The reason the above will also error, is because a parameter can be either a variable, or a constant, not an expression as the above shows. If we declare #myNewName, and set the desired value into that variable, we can then pass that to the procedure.
Give this a try:
declare #date varchar(8)
set #date = convert( varchar(8), getdate(), 112)
declare #myNewName varchar(255) = 'LM_SM_Billing_and_Send_Data_' + #date
exec sp_rename 'LM_SM_Billing_and_Send_Data', #myNewName
This may be a good reference as one continues to work with SQL parameters: http://msdn.microsoft.com/en-us/library/ms189260(v=sql.105).aspx
Use Dynamic Sql to append the variable to the new table name.
Use select * into syntax to copy the data from new old table to new table this part has to be done dynamically.
Then finally drop the old table
declare #date varchar(8),
set #date = convert( varchar(8), getdate(), 112)
set #sql ='select * into LM_SM_Billing_and_Send_Data_'+#date+'
from LM_SM_Billing_and_Send_Data'
exec sp_executesql #sql
Drop table LM_SM_Billing_and_Send_Data

Dynamically create column in Table

I have Create a table within My procedure.
I have start date and end date value. I want create columns with this date range like if start date is 15 july 2013 and end date is 18 july 2013 then there are 4 columns(july1,july2,july3,july4) are created.
How can I achieve this. I have used sql server 2008..
please help me.....
Sir from front end i have fromdate and Todate fields then on submit I have called a Sp from my C# code, Now I want to create a table within my Proc. table must have no. of columns as with no. of days exists between given dates.
Try this:
DECLARE #dtmin date
DECLARE #dtmax date
DECLARE #dynsql nvarchar(3000)
DECLARE #colname varchar(20)
SET #dynsql = N'CREATE TABLE trial('
SET #dtmin = {d '2013-07-15'}
SET #dtmax = {d '2013-07-18'}
DECLARE #currdate date
SET #currdate = #dtmin
WHILE (#currdate <= #dtmax)
BEGIN
SET #colname = DATENAME(month, #currdate) + CONVERT(varchar, DATEPART(day, #currdate))
SET #dynsql = #dynsql + #colname + ' varchar(10)'
IF (#currdate < #dtmax)
BEGIN
SET #dynsql = #dynsql + ', '
END
ELSE
BEGIN
SET #dynsql = #dynsql + ')'
END
SET #currdate = DATEADD(day, 1, #currdate)
END
EXEC sp_executesql #dynsql
P.S.: I don't know the reason of your request, but generally is not correct create table in this way because the information you want to put into columns, should be put in the rows.
Example:
If I want to store sales day by day, the correct table, I named SALES, is:
SALES (id varchar(36), dt datetime, amount decimal(19,2))
instead of
SALES (ID VARCHAR(36), dt1 decimal(19,2), dt2 decimal(19,2)... and so on)
Because if you want to change your period you must rewrite your table, if you want query your table you must write several queries for each situation. It's very hard work on this table.
Please, reconsider you choice.
Have a nice day.
You may have accepted the answer above, but even wanting to do this goes well against the principles behind relational databases. I'd seriously consider what you're trying to do and your approach.