Dates returned as columns in SQL Select - sql

My user will submit a FromDate and a ToDate. What I want to happen is to select the dates that fall in between these dates, which I have accomplished with the script below. The dates will by dynamic.
DECLARE #fromDateParam DATETIME = '2022-01-24 00:00:00.000'
DECLARE #toDateParam DATETIME = '2022-01-29 00:00:00.000'
;WITH fnDateNow(DayOfDate) AS
(
SELECT #fromDateParam AS TransactionDate
UNION ALL
SELECT DayOfDate + 1
FROM fnDateNow
WHERE DayOfDate < #toDateParam
)
SELECT fnDateNow.DayOfDate AS TransactionDate
FROM fnDateNow
This returns that dates as rows. What I am looking for is a way to make these dates return as the columns for a different script.
This table is called DailyTransactionHeader and it has a column [TransactionDate] and another one called [Amount].
There is the probability that their is not a DailyTransactionHeader with the specified Date for this I am looking to return 0.
So I am trying to have the data look like this (I formatted the date) There would be more than one row, but I just wanted to show an example of what I am trying to accomplish.
I appreciate any help,
Thanks

You can do it using dynamic sql. For example:
CREATE PROCEDURE [GET_DATE_TABLE]
(
#FROMDATE DATETIME,
#TODATE DATETIME
)
AS
DECLARE #PDATE DATETIME
DECLARE #SQL VARCHAR(MAX)
DECLARE #SEP VARCHAR(10)
SET #PDATE = #FROMDATE
SET #SQL = 'SELECT '
SET #SEP = ''
WHILE #PDATE < #TODATE
BEGIN
SET #SQL = #SQL + #SEP + 'NULL as [' + CONVERT(VARCHAR, CONVERT(DATE, #PDATE)) + ']'
SET #PDATE = #PDATE + 1
SET #SEP = ', '
END;
EXEC(#SQL)
Test Example:
DECLARE #fromDateParam DATETIME = '2022-01-24 00:00:00.000'
DECLARE #toDateParam DATETIME = '2022-01-29 00:00:00.000'
exec dbo.GET_DATE_TABLE #fromDateParam, #toDateParam

Related

SQL Server: fetching a variable name from a table and assigning value inside the stored procedure

I have some variable name stored in a table, which I need to populate in a stored procedure based on a condition.
For example:
Query: select column1 from TestTable
Output of Query: #FromDate
Now inside the stored procedure, I have the following:
DECLARE #FromDate DATE = '2022-06-01'
DECLARE #QueryResult Varchar(50);
DECLARE #SQLCommand Varchar(50);
SELECT #QueryResult = column1
FROM TestTable
SET #SQLCommand = 'SELECT * FROM emp WHERE joindate >= ''' + #QueryResult + ''';'
EXEC (#SQLCommand);
Now I am expecting that result should be all the employee whose joindate >= '2022-06-01'. Or in other words, I am expecting to use #FromDate variable to fetch data. But when i run query, I get the following error:
Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "#FromDate"
When I run:
print #SQLCommand;
I get:
select * from emp where joindate >= '#FromDate';
While I am expecting that #FromDate value should be populated here at run time.
Will be thankful for any help regarding this.
Update: actually, there is a loop inside my sp, which fetches the data from table (data contains variable names to be used in the stored procedure in different logic I) like for a particular record: I need to add 20 days in #fromdate, and for another record I need to add 30 days. Now when my loop will run, it will fetch either dateadd(day, 20, #fromdate) or dateadd(day, 30, #fromdate) from table based on where clause and then I need to fill in the value of #fromdate (this is parametrise variable) and fetch the results accordingly.
Update 2:
Please see below my code
USE [GBI_archive]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_Process_Data]
(#StartDate DATE = NULL,
#EndDate DATE = NULL)
AS
DECLARE #FromDate DATE = ISNULL(#StartDate, DATEADD(DAY, 1, EOMONTH(GETDATE(), -1)));
DECLARE #ToDate DATE = ISNULL(#EndDate, GETDATE());
DECLARE #CalculationMethodFromDate VARCHAR(255);
DECLARE #SelectStatement VARCHAR(255);
DECLARE #TableIntoStatement VARCHAR(255);
DECLARE #FromStatement VARCHAR(255);
DECLARE #SQLCommand VARCHAR(255);
DECLARE cursor_product CURSOR FOR
SELECT calculation_method_from_date
FROM [dbo].[Calculation_Method_Configuration];
-- Here output can be DATEADD(DAY, -6, #FromDate) or DATEADD(DAY, -14, #FromDate) or so on
OPEN cursor_product;
FETCH NEXT FROM cursor_product INTO #CalculationMethodFromDate
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #CalculationMethodFromDate
SET #SelectStatement = 'SELECT CURRENT_TIMESTAMP, * ';
SET #TableIntoStatement = 'INTO [dbo].[Table_For_Function_Output]';
SET #FromStatement = 'FROM [dbo].[EmployeeData] where joindate >= ''' + #CalculationMethodFromDate + ''';'
-- SET #SQLCommand = concat (#SelectStatement , ' ', #TableIntoStatement , ' ', #FromStatement);
PRINT #SQLCommand;
EXEC (#SQLCommand);
FETCH NEXT FROM cursor_product INTO #CalculationMethodFromDate,
END;
CLOSE cursor_product;
DEALLOCATE cursor_product;
GO
Now for anyone iteration of loop, print #SQLCommand shows this (if #CalculationMethodFromDate = 'DATEADD(DAY, -6, #FromDate)') :
SELECT CURRENT_TIMESTAMP, * INTO [dbo].[Table_For_Function_Output] FROM [dbo].[EmployeeData] where joindate >= 'DATEADD(DAY, -6, #FromDate)';
and exec command throws this error:
Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "#FromDate"
But if I am passing #FromDate = '2022-06-07' as parameter to this sp, my expectations for print #SQLCommand shows is:
SELECT CURRENT_TIMESTAMP, * INTO [dbo].[Table_For_Function_Output] FROM [dbo].[EmployeeData] where joindate >= '2022-06-01';
In short: #FromDate variable coming from database at runtime, should be assigned a value from stored procedure.
You don't need a cursor here, you just need to build one big UNION ALL statement. And you need to pass the #FromDate and #ToDate into the dynamic SQL.
CREATE OR ALTER PROCEDURE [dbo].[sp_Process_Data]
#StartDate DATE = NULL,
#EndDate DATE = NULL
AS
DECLARE #FromDate DATE = ISNULL(#StartDate, DATEADD(DAY, 1, EOMONTH(GETDATE(), -1)));
DECLARE #ToDate DATE = ISNULL(#EndDate, GETDATE());
DECLARE SQLCommand nvarchar(max) = (
SELECT STRING_AGG(N'
SELECT CURRENT_TIMESTAMP, e.*
FROM dbo.EmployeeData e
where e.joindate >= ' + CAST(cm.calculation_method_from_date AS nvarchar(max))
, '
UNION ALL ')
FROM dbo.Calculation_Method_Configuration cm
);
PRINT #SQLCommand;
EXEC sp_executesql
#SQLCommand,
N'#FromDate DATE, #ToDate DATE',
#FromDate = #FromDate,
#ToDate = #ToDate;
go
The design itself is questionable. You should really just have a column which tells you how many days to add, then you can just do
SELECT CURRENT_TIMESTAMP, e.*
FROM dbo.EmployeeData e
JOIN dbo.Calculation_Method_Configuration cm
ON e.joindate >= DATEADD(day, -cm.days, #FromDate);
well actually you could simply use sp_executesql for this.
Simplified sample:
-- demo table:
SELECT DATEADD(day, -7, GETDATE()) [Date] INTO [#demo] UNION ALL SELECT DATEADD(day, 1, GETDATE());
-- demo:
DECLARE #CalculationMethodFromDate NVARCHAR(MAX) = N'DATEADD(DAY, -6, #FromDate)';
DECLARE #FromDate DATE = GETDATE();
DECLARE #SQL NVARCHAR(MAX) = N'SELECT * FROM [#demo] WHERE [Date] >= '+#CalculationMethodFromDate+N';';
EXEC sp_executesql #SQL, N'#FromDate DATE', #FromDate=#FromDate;
--cleanup
drop table [#demo];

Conversion date error in SQL

When executing the below dynamic SQL statement, I get an error:
Conversion failed when converting date and/or time from character string
[ReturnDate] is defined as datetime and #FromDate and #ToDate parameters are being passed as type datetime as well. What am I missing ?
Set #SQLString =
'Select
[ID], [ReturnDate], [PolicyNumber]
From
Bil_ReturnsRepository
Where
(' + #PolicyNumber + ' is null or PolicyNumber = (' + #PolicyNumber + '))
and (ReturnDate) >= Convert(date, ' + #FromDate + '))
and (ReturnDate) <= Convert(date, ' + #ToDate + '))
and PaymentAmount > 0.00'
Presumably, you are using SQL Server. If so, learn to use sp_executesql. One of its powers is the ability to pass in parameters:
Set #SQLString = '
Select [ID], [ReturnDate], [PolicyNumber]
From Bil_ReturnsRepository
Where (#PolicyNumber is null or PolicyNumber = #PolicyNumber) and
(ReturnDate >= #p_FromDate) and
(ReturnDate <= #p_ToDate) and
PaymentAmount > 0.00
';
declare #p_fromdate date;
declare #p_todate date;
select #p_fromdate = convert(date, #fromdate),
#p_todate = convert(date, #todate);
exec sp_executesql #sql,
N'#p_fromdate date, #p_todate date, #policynumber int',
#p_fromdate=#p_fromdate, #p_todate=#p_todate, #policynumber=#policynumber;
The variables #p_fromdate and #p_todate are not necessary if #fromdate and #todate already have the correct types.
You cannot concatenate string with datetime, I would suggest you to
use sp_executesql to parameterize the dynamic sql
declare #SQLString nvarchar(max)--should be nvarchar
Set #SQLString =
'Select
[ID]
,[ReturnDate]
,[PolicyNumber]
From Bil_ReturnsRepository
Where
(#PolicyNumber is null or PolicyNumber = #PolicyNumber) and
ReturnDate >= #FromDate and
ReturnDate <= #ToDate and
PaymentAmount > 0.00'
exec sp_executesql #SQLString,
N'#FromDate datetime, #ToDate datetime, #PolicyNumber int',
#FromDate, #ToDate, #PolicyNumber
By this way your query is much safer and cleaner without so many string concatenation.
Note : use appropriate datatype for #PolicyNumber in sp_executesql

Dynamic SQL running way too longer

I am trying to run a dynamic SQL query that is supposed to load more than 200M records. I tried to load all the records at once but got 'System.OutOfMemory' Exception hence decided to break the time-interval into months.The following runs for more than an hour even though if I run it for just a month. I hard-coded the dates and ran it without the 'While' and it runs normally. Can someone check and let me know if there is some error in it.
Below is my query
DECLARE #FromDate VARCHAR(MAX)='',
#params nvarchar(max) = N'#StartDate Date out,#EndDate Date out,#FromDate date out,#ToDate date out',
#SQL NVARCHAR(MAX)=’’,
#ToDate VARCHAR(MAX)='',
#StartDate VARCHAR(MAX)=’’,
#EndDate VARCHAR(MAX)=’’;
SELECT #FromDate= DATEADD(DAY,-365, GETUTCDATE()), #ToDate = GETUTCDATE();
SELECT #StartDate=#FromDate, #EndDate=CAST(DATEADD(MONTH,1, #FromDate) AS DATE);
SET #SQL = '
WHILE ''' + #FromDate + ''' < ''' + #ToDate + '''
BEGIN
INSERT INTO dbo.Sales
(
ProductID,
SaleDate,
Quantity
)
Select
ProductID,
SaleDate,
Quantity
from
OPENQUERY(TeraData1,''
Select
PR_ID AS ProductID,
SL_Date AS SaleDate,
PR_QTY AS Quantity
FROM
Sales.Product
where
SaleDate BETWEEN ' + #StartDate + 'AND '+ #EndDate + '
'')
SET #FromDate =DATEADD(MONTH,1,'''+ #FromDate +''')
SET #StartDate =DATEADD(MONTH,1,'''+ #StartDate +''')
SET #EndDate =DATEADD(MONTH,1,'''+ #EndDate +''')
END’
EXECUTE sp_executesql #SQL, #params,
#FromDate=#FromDate,
#ToDate=#ToDate,
#StartDate = #StartDate out,
#EndDate = #EndDate out;
DECLARE #FromDate DATE
SET #FromDate = DATEADD(YEAR,-1,GETUTCDATE())
WHILE #FromDate < GETUTCDATE()
BEGIN
INSERT INTO dbo.Sales
(
ProductID,
SaleDate,
Quantity
)
Select
ProductID,
SaleDate,
Quantity
from
OPENQUERY(TeraData1,
Select
PR_ID AS ProductID,
SL_Date AS SaleDate,
PR_QTY AS Quantity
FROM
Sales.Product
where
SaleDate >= #FromDate AND SaleDate < DATEADD(MONTH,1,#FromDate)
)
SET #FromDate =DATEADD(MONTH,1,#FromDate)
END
It looks like you have way more variables/dates than you need and that you don't need dynamic SQL unless you are wanting to pass the linked server name or some other column dynamically.
Also stick with the appropriate datatype for the parameter instead of letting SQL infer the values you want.
Also your use of BETWEEN for the dates would have duplicated the certain dates because it would be inclusive, to fix limit 1 side of the comparison.
If you do want to do this dynamically keep the control flow in your non dynamic SQL and pass the parameter here is an example:
DECLARE #FromDate DATE
SET #FromDate = DATEADD(YEAR,-1,GETUTCDATE())
WHILE #FromDate < GETUTCDATE()
BEGIN
DECLARE #LinkedServerName NVARCHAR(MAX) = 'TeraData1'
DECLARE #ParamDef NVARCHAR(MAX) = '#FromDate DATE'
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = '
INSERT INTO dbo.Sales
(
ProductID,
SaleDate,
Quantity
)
Select
ProductID,
SaleDate,
Quantity
from
OPENQUERY(' + #LinkedServerName + ',
Select
PR_ID AS ProductID,
SL_Date AS SaleDate,
PR_QTY AS Quantity
FROM
Sales.Product
where
SaleDate >= #FromDate AND SaleDate < DATEADD(MONTH,1,#FromDate)
)'
EXECUTE sp_executesql #SQL, #PramDef, #FromDate = #FromDate
SET #FromDate =DATEADD(MONTH,1,#FromDate)
END

Getting Datetime by Year, Month, Date

I want to get date by Using Year, Month and Day functions. Example
declare #Date smalldatetime
select #Date = Year('20140530') + Month('20140530') + Day('20140530')
What I want is to assign #Date = '20140530' as smalldatetime. But I want to do this by means of somwething similar to above expression. How can Ido this. Thanks in advance.
Instead try something like below
declare #Date varchar(20)
select #Date = cast(Year('20140530') as varchar) +
cast(Month('20140530') as varchar) +
cast(Day('20140530') as varchar)
select #Date
results in: 2014530.
(OR) like below
declare #Date VARCHAR(20)
select #Date = cast(Year('20140530') as varchar) + '-' +
cast(Month('20140530') as varchar) + '-' +
cast(Day('20140530') as varchar)
select cast(#Date as smalldatetime)
results in: 2014-05-30 00:00:00
Year()/Month()/DaY() functions returns the year/Month/Day as Integer. What you are actually doing can be simulated as below
declare #Date smalldatetime
set #Date = 2049
select #Date
which will result in : 1905-08-12 00:00:00
Use Like, Set will give the Date in #Date instead of select
declare #Date smalldatetime
set #Date = Year('20140530') + Month('20140530') + Day('20140530')
print #Date

Datetime syntax error

I'm newbie at SQL Server. I'm stuck on a problem that I can't solve. I want to write a stored procedure.
TimeStamp column's datatype is datetime.
This my stored procedure:
#fetchtype int,
#startdate nvarchar(22),
#finishdate nvarchar(22)
AS
if (#fetchtype = 0)
BEGIN
PRINT('Select TimeStamp ' From WindData Where TimeStamp between '+#startdate+' and '+#finishdate)
EXEC('Select TimeStamp ' From WindData Where TimeStamp between '+#startdate+' and '+#finishdate)
END
An also my execution query is
DECLARE #return_value int
EXEC #return_value = [dbo].[Get_Values]
#columnnames = N'V81_Avg',
#fetchtype = 0,
#startdate = N'2013-04-23 12:58:40.000',
#finishdate = N'2013-04-23 12:59:00.000'
SELECT 'Return Value' = #return_value
But when I execute my query I get this error
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '12'.
I think I didn't write properly datetime format.
The problem here is in SQL query string:
It should be:
PRINT('Select TimeStamp From WindData Where TimeStamp between '''+#startdate+''' and '''+#finishdate+'''');
EXEC('Select TimeStamp From WindData Where TimeStamp between '''+#startdate+''' and '''+#finishdate+'''')
But the best way is to use these parameters as DATETIME and avoid dynamic query and replace EXEC() with just SELECT:
#startdate datetime,
#finishdate datetime
...
Select TimeStamp From WindData Where TimeStamp between #startdate and #finishdate;
...
You need to put quotes around the dates:
declare #sql nvarchar(max) = 'Select TimeStamp From WindData Where TimeStamp between '''+#startdate+''' and '''+#finishdate+'''')
EXEC(#sql);
Or, better yet, use sp_executesql:
declare #sql nvarchar(max) = 'Select TimeStamp From WindData Where TimeStamp between #startdate and #finishdate')
exec sp_executesql #sql, N'#startdate date, #finishdate date', #startdate = #startdate, #finishdate = #finishdate;
CREATE PROC yourSPName
(#fetchtype int,
#startdate nvarchar(22),
#finishdate nvarchar(22)
)
AS
DECLARE #sqlstr varchar(2500)
if (#fetchtype = 0)
BEGIN
Select TimeStamp From WindData Where TimeStamp between convert(datetime,#startdate) and convert(datetime,#finishdate)
END