Not able to execute the stored procedure - sql

I have table in which my date column value is saved with time also
like this 2016-06-10 14:56:11.000
Now while executing my SP, I pass one parameter as date like this exec UserReportData '06-10-2016' but it is not showing any records. As it has 4 records in the table.
Why?
UPDATE
ALTER PROCEDURE [dbo].[UserReportData]
#As_ONDATE Datetime
AS
BEGIN
DECLARE #REPORTDATE datetime
DECLARE #OPENING INT
SELECT *
INTO #temptable
FROM
(SELECT DISTINCT
a.CUser_id, b.User_Id,a.U_datetime as REPORTDATE,
b.first_name + ' ' + b.last_name AS USERNAME,
0 OPENING, 0 TOTAL_DOCUMENT, 0 INWARD, 0 FIRST_LEVEL_PROCESSING, 0 DATA_ENTRY
FROM
inward_doc_tracking_trl a, user_mst b
WHERE
a.CUser_id = b.mkey
AND a.U_datetime = CONVERT(varchar(10), #As_ONDATE, 103)) AS x
DECLARE Cur_1 CURSOR FOR
SELECT CUser_id, User_Id
FROM #temptable
OPEN Cur_1
DECLARE #CUser_id INT
DECLARE #User_Id INT
FETCH NEXT FROM Cur_1 INTO #CUser_id, #User_Id
WHILE (##FETCH_STATUS = 0)
BEGIN
SELECT #REPORTDATE
FROM inward_doc_tracking_trl
WHERE U_datetime = CONVERT(varchar(10), #As_ONDATE, 103)
UPDATE #temptable
SET REPORTDATE = #REPORTDATE
WHERE CUser_id = #CUser_id
AND User_Id = #User_Id
FETCH NEXT FROM Cur_1 INTO #CUser_id, #User_Id
END
CLOSE Cur_1
DEALLOCATE Cur_1
SELECT *
FROM #temptable
DROP TABLE #temptable
END

You are passing in a date as a string (with implicit time being 00:00) which you are casting to be a date, still with time being 00:00, and trying to match dates with times. There won't be any results as the time doesn't match.
You have to either:
Cast the datetime to a date to match an exact date (not good, requires recalculating every date in the column)
Change the search to look between date + '00:00' to date + '23:59' (or if you are happy, you could just add a day)
Update for your where clause to take the easy option 2:
where a.CUser_id = b.mkey
and a.U_datetime BETWEEN CONVERT(varchar(10), #As_ONDATE, 103)
AND DATEADD(day, 1, CONVERT(varchar(10), #As_ONDATE, 103))

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];

Dates returned as columns in SQL Select

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

SQL Query, bring data between 2 dates with limitation

In SQL, I am going to write a query which insert all data between 2 dates and also I want to bring then in a 1000 batch but since the number of data between those days are more than my limitation I was going to write a loop which makes the smaller period to bring the data.
here is my code:
DECLARE #StartDate DATETIME = CAST('2021-06-02 01:00:00.000' AS DATETIME)
DECLARE #EndDate DATETIME = CAST('2021-06-23 01:00:00.000' AS DATETIME)
DECLARE #RealRowCount INT = (SELECT DISTINCT SUM(##ROWCOUNT) OVER() FROM GetReport (
#StartDate, #EndDate))
DECLARE #TransactionCount INT = (SELECT DISTINCT TransactionCount FROM GetReport (
#StartDate, #EndDate))
WHILE #RealRowCount < #TransactionCount
BEGIN
DECLARE #DiffDate INT = (SELECT DATEDIFF(DAY, #StartDate, #EndDate))
SET #EndDate = DATEADD(DAY, #DiffDate/2 ,#StartDate)
SELECT *,#StartDate, #EndDate FROM GetReport (#StartDate, #EndDate)
END
PS: I was thinking about find the middle of the period of date and then change them into the new EneDate and StartDate but there is problem here!
Your question is not very clear. Suppose you have 10,000 records between two dates and you do not want to retrieve more than a thousand records at a time. In this case, you can use pagination. Both in the program code and in SQL.
DECLARE #StartDate DATETIME = CAST('2021-06-02 01:00:00.000' AS DATETIME)
DECLARE #EndDate DATETIME = CAST('2021-06-23 01:00:00.000' AS DATETIME)
DECLARE #RealRowCount INT = (SELECT DISTINCT COUNT(*) FROM Products WHERE InsertDate BETWEEN #StartDate AND #EndDate)
DECLARE #Counter INT = 0
WHILE #Counter <= #RealRowCount
BEGIN
SELECT *
FROM Products
WHERE InsertDate BETWEEN #StartDate AND #EndDate
ORDER BY InsertDate
OFFSET #Counter ROWS -- skip #Counter rows
FETCH NEXT 1000 ROWS ONLY -- take 1000 rows
SET #Counter = #Counter + 1000
END
Or you can get the time difference between the two dates and add the start date each time in a specific step and retrieve the data of that date.
For example, the date difference is 20 days. Increase the start date by 5 steps each time to the start date with the end date
I create another table to put Dates and if this table has any rows I can get 'EndDate', but if it has not any records I simply just use the date that I specified.
AccSync is the table that I insert details of my records and AccTransformation is the table wich I want to insert all of my records.
DECLARE #Count INT = (SELECT COUNT(*) FROM [AccTransaction])
DECLARE #Flag BIT = (SELECT IIF(#Count > 1, 1, 0))
DECLARE #End DATETIME = GETDATE();
DECLARE #Start DATETIME
IF(#Flag = 0)
BEGIN
SET #Start = CAST('2021-03-08' AS DATETIME2);
SET #Flag = 1
END
ELSE IF(#Flag = 1)
BEGIN
SET #Start = (SELECT TOP 1 EndDate FROM (SELECT EndDate FROM [AccSync] ORDER BY ActionDate DESC OFFSET 0 ROW) AS TT);
END
DECLARE #RealRowCount INT = (SELECT DISTINCT SUM(##ROWCOUNT) FROM [GetReport] (#Start, #End));
DECLARE #TransactionCount INT = (SELECT DISTINCT TransactionCount FROM [GetReport] (#Start, #End));
----------------------------------------------------------------------------------------------
WHILE (#RealRowCount <> #TransactionCount)
BEGIN
DECLARE #DiffDate INT = (SELECT DATEDIFF(SECOND, #Start, #End))
SET #End = DATEADD(SECOND, (#DiffDate/2), #Start)
SET #RealRowCount = (SELECT DISTINCT SUM(##ROWCOUNT) FROM [GetReport] (#Start, #End))
SET #TransactionCount = (SELECT DISTINCT TransactionCount FROM [GetReport] (#Start, #End))
END
----------------------------------------------------------------------------------------------
INSERT INTO [AccTransaction]
SELECT *
FROM [GetReport](#Start, #End)
----------------------------------------------------------------------------------------------
INSERT INTO [AccSync]
VALUES(NEWID(), GETDATE(), #Start, #End, ISNULL(#TransactionCount,0), DATEDIFF(SECOND, #Start, #End))

Looping distinct values from one table through another without a join

I know looping is not ideal in SQL, but I couldn't think of another way of doing this.
I want each distinct row from this Table 1 to have each distinct date and hour produced on Table 2.
In other words, Table 2 has the dates between 05/01/2014 through 04/30/2015, with each distinct date having 24 rows, one for each hour of the day. I now want each distinct row in Table 1 to have each distinct date on Table 2, with each of its 24 hours.
Table 1:
DROP TABLE Baylor_Raw..MEDICAL_SERVICE_DESC
SELECT MEDICAL_SERVICE_DESC
INTO Baylor_Raw..MEDICAL_SERVICE_DESC
FROM Baylor_Raw..Raw_ADT
WHERE MEDICAL_SERVICE_DESC IS NOT NULL AND MEDICAL_SERVICE_DESC NOT IN ('#N/A','CANCEL','DAY SURGERY','HOSPICE','INFUSION')
Table 2:
DECLARE #DATE DATE
SET #DATE = '05/01/2014'
DECLARE #HOUR INT
SET #HOUR = 0
DROP TABLE Baylor_Raw..DateTable
CREATE TABLE Baylor_Raw..DateTable
(DATE_OF_DISCHARGE DATE
,HOUR_OF_DISCHARGE INT)
WHILE #DATE<'05/01/2015' BEGIN
WHILE #HOUR<25 BEGIN
INSERT INTO Baylor_Raw..DateTable (DATE_OF_DISCHARGE,HOUR_OF_DISCHARGE)
VALUES (#DATE,#HOUR)
SET #HOUR = #HOUR+1
END
SET #DATE = DATEADD(DD,1,#DATE)
SET #HOUR = 0
END
This below attempt did not work. I canceled after the run time exceeded several minutes.
DECLARE #MEDICAL_SERVICE_DESC NVARCHAR(255)
SET #MEDICAL_SERVICE_DESC = (SELECT MIN(MEDICAL_SERVICE_DESC) FROM Baylor_Raw..MEDICAL_SERVICE_DESC)
DECLARE #DATE DATE
SET #DATE = '05/01/2014'
DECLARE #HOUR INT
SET #HOUR = 0
DROP TABLE Baylor_Raw..DateTable
CREATE TABLE Baylor_Raw..DateTable
(MEDICAL_SERVICE_DESC NVARCHAR,
DATE_OF_DISCHARGE DATE
,HOUR_OF_DISCHARGE INT)
WHILE #MEDICAL_SERVICE_DESC IS NOT NULL BEGIN
WHILE #DATE<'05/01/2015' BEGIN
WHILE #HOUR<25 BEGIN
INSERT INTO Baylor_Raw..DateTable (MEDICAL_SERVICE_DESC,DATE_OF_DISCHARGE,HOUR_OF_DISCHARGE)
VALUES (#MEDICAL_SERVICE_DESC,#DATE,#HOUR)
SET #HOUR = #HOUR+1
END
SET #DATE = DATEADD(DD,1,#DATE)
SET #HOUR = 0
END
DELETE FROM Baylor_Raw..MEDICAL_SERVICE_DESC WHERE MEDICAL_SERVICE_DESC = #MEDICAL_SERVICE_DESC
SET #MEDICAL_SERVICE_DESC = (SELECT MIN(MEDICAL_SERVICE_DESC) FROM Baylor_Raw..MEDICAL_SERVICE_DESC)
SET #DATE = '05/01/2014'
END
So you want all distinct records from table1 paired with all records in table2? That is a cross join:
select *
from (select distinct * from table1) t1
cross join table2;
Or do you want them related by date? Then inner-join:
select *
from (select distinct * from table1) t1
inner join table2 t2 on t1.date = t2.date;
You might get better performance from building lists of dates and hours using loops first, and then combining it with the service names just one time using a cross join, something like this. You may need to tweak it a bit because you understand the source data:
DECLARE #dates TABLE (DATE DATE)
DECLARE #hours TABLE (hours INT)
DECLARE #hour INT
,#date DATE
SET #hour = 0
SET #date = '05/01/2014'
WHILE (#hour < 25)
BEGIN
INSERT INTO #hours
SELECT #hour
SET #hour = #hour + 1
END
WHILE (# DATE < '05/01/2015')
BEGIN
INSERT INTO #dates
SELECT #date
SET #DATE = DATEADD(DD, 1, #DATE)
END
INSERT INTO Baylor_Raw..DateTable (
MEDICAL_SERVICE_DESC
,DATE_OF_DISCHARGE
,HOUR_OF_DISCHARGE
)
SELECT MEDICAL_SERVICE_DESC
,DATE
,hour
FROM Baylor_Raw..MEDICAL_SERVICE_DESC
CROSS JOIN #date d
CROSS JOIN #hours h

How can I use a cursor with a common table expression in SQL Server 2005 [duplicate]

I need a cursor for the below query so I can loop through to fetch/update/insert some other data. Can somebody help me with this?
DECLARE #FROMDATE DATETIME
DECLARE #TODATE DATETIME
SELECT #FROMDATE = Getdate()
SELECT #TODATE = Getdate() + 7
;WITH DATEINFO(DATES)
AS (SELECT #FROMDATE
UNION ALL
SELECT DATES + 1
FROM DATEINFO
WHERE DATES < #TODATE)
SELECT *
FROM DATEINFO
OPTION (MAXRECURSION 0)
I tried so many ways, but didn't find any that worked.
I'm Using
declare #adate datetime
DECLARE #FROMDATE DATETIME
DECLARE #TODATE DATETIME
select #FROMDATE=getdate()
select #TODATE =getdate()+7
declare #weekdates cursor for
WITH DATEINFO(DATES) AS (SELECT #FROMDATE UNION ALL SELECT DATES + 1 FROM DATEINFO WHERE DATES < #TODATE)
SELECT * FROM DATEINFO OPTION (MAXRECURSION 0)
open #weekdates
fetch next from #weekdates into #adate
while ##fetch_status=0
begin
print 'success'
fetch next from #weekdates into #adate
end
close #weekdates
deallocate #weekdates
Still I'm getting errors
Just put it in before the common table expression:
DECLARE #FROMDATE DATETIME
DECLARE #TODATE DATETIME
select #FROMDATE=getdate()
select #TODATE =getdate()+7
declare boris cursor for
WITH DATEINFO(DATES)
AS (SELECT #FROMDATE
UNION ALL
SELECT DATES + 1
FROM DATEINFO
WHERE DATES < #TODATE)
SELECT *
FROM DATEINFO
OPTION (MAXRECURSION 0)
(However, insert usual cautions about cursors almost always being the wrong tool for the job. If you can find a way to do the whole operation in a set based manner, it's usually preferable, and likely to perform better (or at least be more amenable to performance tuning))
It is fine to use # in a cursor name but the syntax you are using is wrong.
DECLARE #adate DATETIME
DECLARE #FROMDATE DATETIME
DECLARE #TODATE DATETIME
SELECT #FROMDATE = getdate()
SELECT #TODATE = getdate() + 7
DECLARE #weekdates CURSOR;
SET #weekdates = CURSOR FOR
WITH DATEINFO(DATES)
AS (SELECT #FROMDATE
UNION ALL
SELECT DATES + 1
FROM DATEINFO
WHERE DATES < #TODATE)
SELECT *
FROM DATEINFO
OPTION (MAXRECURSION 0)
OPEN #weekdates
FETCH next FROM #weekdates INTO #adate
WHILE ##fetch_status = 0
BEGIN
PRINT 'success'
FETCH next FROM #weekdates INTO #adate
END
When declared as a local # variable the cursor is automatically closed and deallocated when the variable goes out of scope.