Calculating variances on dates in T-SQL - sql

Guys, I am trying to write a stored procedure in T-SQL (SQL Server) that will select records based on a date field, keeping a variance of minutes in mind. Something like this:
CREATE PROCEDURE spGetCustomers(#DateRange DATETIME, #Variance int) AS
-- The next line is where I need help
-- I'm trying to subtract X amount of minutes from the date
-- So if #Variance = 4 AND #DateRange = '6/10/2009 1:15pm'
-- Then #StartDate should equal '6/10/2009 1:11pm'
DECLARE #StartDate = #DateRange - #Variance
-- I also need an #EndDate, which will be X amount of minutes
-- in the future. So if #Variance = 4 AND #DateRange = '6/10/2009 1:15pm'
-- Then #EndDate should equal '6/10/2009 1:19pm'
DECLARE #EndDate = #DateRange + #Variance
SELECT * FROM Customers WHERE Created BETWEEN #StartDate AND #EndDate
Hopefully this makes sense and someone can help me out! Thanks in advance

Check this out:
http://msdn.microsoft.com/en-us/library/ms186819(SQL.90).aspx
The DATEADD function allows you to add virtually any part of a date to another date object, it should be everything you need.
So basically do:
SELECT DATEADD(second, #Variance, #DateRange)

The following script provides an example that should get you started.
create table tmp_Customers
(
ID int identity(1,1),
CreatedDate datetime default getDate() not null,
Description varchar(15)
);
go
insert into tmp_Customers(Description) values('SomeData');
insert into tmp_Customers(Description) values('SomeData2');
insert into tmp_Customers(Description) values('SomeData3');
go
create procedure usp_GetCustomers
#iVarianceMinutes int,
#iDateRange datetime
as
set nocount on
declare #startDate datetime
declare #endDate datetime
--Define the date ranges for the select query
set #startDate = dateAdd(minute,-#iVarianceMinutes,#iDateRange)
set #endDate = dateAdd(minute,#iVarianceMinutes,#iDateRange)
--Get the Customers that were created within this time range.
SELECT *
FROM tmp_Customers
WHERE CreatedDate >= #startDate and CreatedDate < #endDate
return(0);
go
--Execute the procedure
declare #testDate datetime;
set #testDate = getDate();
exec usp_GetCustomers 5,#testDate
--drop procedure usp_GetCustomers
--drop table tmp_Customers

Related

What I'm trying to do is get a running stock level for every day for the past year for each item [duplicate]

This question already has answers here:
Calculate a Running Total in SQL Server
(15 answers)
Closed 1 year ago.
I have the below SQL query that works but it's very slow. it takes about 1 min to run the query. This would be made into a stored procedure. which is not the problem. but that store procedure would be called for every item of which there are about 600 items. The estimated run time probably would end up taking about 10 hours. Does anyone have any suggestions of a better way of doing it?
What I'm trying to do is get a running stock level for every day for the past year for each item.
If you need any more information. Please let me know.
DECLARE #StartDate AS DATETIME
DECLARE #EndDate AS DATETIME
DECLARE #CurrentDate AS DATETIME
DECLARE #ItemName As Varchar(450)
DECLARE #QOH DECIMAL(19,4)
SET #QOH = 0
SET #ItemName = 'TUR001-02'
SET #StartDate = '2020-04-01'
SET #EndDate = GETDATE()
SET #CurrentDate = #StartDate
CREATE TABLE #TempTable
(
Date datetime,
ItemName char(450),
QOH DECIMAL(19,4)
);
WHILE (#CurrentDate < #EndDate)
BEGIN
DECLARE #daySales DECIMAL(19,4)
SELECT #daySales = SUM(Quantity)
FROM qbInvoiceLineDetail
WHERE TxnDate = #CurrentDate AND FullName = #ItemName;
SET #QOH = #QOH - #daySales
INSERT INTO #TempTable (Date, ItemName, QOH)
SELECT #CurrentDate, #ItemName, #QOH;
SET #CurrentDate = DATEADD(DAY, 1, #CurrentDate);
END
SELECT * FROM #TempTable
DROP TABLE #TempTable
You can use a tally table to generate your dates between start and end, then insert all your data in one hit into your table.
Caveat - this is untested as I have nothing to check it against, assumes the dates are dates only, if they include time then will need to use convert - hopefully will be what you are looking for:
/*first, create a tally table - this should be a permanent feature */
select top 1000 N=Identity(int, 0, 1)
into dbo.Digits
from master.dbo.syscolumns a cross join master.dbo.syscolumns
declare #StartDate datetime='20200401', #EndDate datetime=GetDate()
select DateAdd(day,N,#startDate) currentDate, FullName ItemName, Sum(Quantity) over(order by d.N) QOH
from Digits d
left join qbInvoiceLineDetail q on q.TxnDate=DateAdd(day,N,#startDate)
where DateAdd(day,N,#startDate)<=#EndDate
group by TxnDate, ItemName

Generate random records for datetime columns by stored procedure in SQL

I want to generate 5 random records from a field which is a datetime column and contains several records of (OrderDate) for a given date range using stored procedure for the table named Orders
CREATE PROCEDURE test
#StartDate DATETIME = NULL,
#EndDate DATETIME = NULL,
AS
BEGIN
SELECT OrderDate = DATEADD(......)
FROM Orders
END
May I get some help!
A while loop works ok for this purpose, especially if you're concerned with limiting your randomness to a bounded date range.
The downside is that potentially many insert queries get executed vs. a single insert for a recursive CTE as in the other answer.
create procedure dbo.spGenDates2
#MinDate datetime,
#MaxDate datetime,
#RecordCount int = 5
as
SET NOCOUNT ON;
DECLARE #Range int, #DayOffset int, #Cnt int
SET #Range = DATEDIFF(dd, #MinDate, #MaxDate)
SET #Cnt = 1
WHILE #Cnt <= #RecordCount
BEGIN
SET #DayOffset = RAND() * (#Range + 1)
INSERT INTO _test (Dt) VALUES(DATEADD(dd, #DayOffset, #MinDate))
SET #Cnt = #Cnt + 1
END
Based on your syntax I'm assuming you're using SQL Server...
Note that you cannot reliably use the sql random number generator function RAND() within the context of a single query because it does not get reseeded per row so you end up receiving the same, single random number for each row result. Instead, an approach using NEWID() converted into a numeric does the trick when generating random values within the execution of a single query.
Here's a procedure that will give you n number of sample dates in the near past.
create procedure dbo.spGenDates
#MaxDate datetime,
#RecordCount int = 5
as
WITH dates as (
SELECT DATEADD(MILLISECOND, ABS(CHECKSUM(NEWID())) * -1, #MaxDate) D,
1 as Cnt
UNION ALL
SELECT DATEADD(MILLISECOND, ABS(CHECKSUM(NEWID())) * -1, #MaxDate) D,
x.Cnt + 1 as Cnt
FROM dates x
WHERE x.Cnt < #RecordCount
)
INSERT INTO _test (Dt)
SELECT D
FROM dates
The wording of the question has been clarified (see comments on another answer) to be a desire to SELECT 5 random sample dates within a bounded range from a table.
A query like this will yield the desired result.
SELECT TOP (5) OrderDate
FROM Orders
WHERE OrderDate >= #StartDate
AND OrderDate < #EndDate
ORDER BY NEWID()

How can I create a stored procedure which takes values from a table and insert them into new table

How to create a stored procedure in SQL which accepts name,area,startdate,enddate as inputs from a table and inserts name,area and date into a table(having 3 columns name,area,date) for every date between startdate and enddate.
This is not possible. You cannot perform DDL and DML operations in functions in SQL Server.
As Gordon suggested, you need to use a stored procedure to achieve this.
Here is an example to start with
http://www.sqlinfo.net/sqlserver/sql_server_stored_procedure_INSERT.php
DECLARE #name NVARCHAR(20) = 'name';
DECLARE #area NVARCHAR(20) = 'area';
DECLARE #startDate DATE = '2016-11-30';
DECLARE #endDate DATE = '2016-12-30';
DECLARE #currentDate DATE = #startDate;
SELECT
#currentDate AS Date
INTO
#dates;
WHILE(#currentDate < #endDate)
BEGIN
SET #currentDate = DATEADD(d, 1, #currentDate);
INSERT INTO #dates
VALUES( #currentDate);
END;
SELECT
#name,
#area,
*
FROM
#dates;
You can get variables as parameter and use the last select statement to create your new table.

Changing Parameter Values in Stored Procedures

I have a stored procedure for a view that is so massive it always times out, it is used to find data for certain date ranges. This is an entirely new concept to me, I have the stored procedure set up for the main date range, I just cant figure out how to Execute it properly if I need specific dates. Here is the code and issue
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[COL_Run_DOM_Parameters]
#StartDate varchar (50),
#EndDate varchar (50)
AS
SET NOCOUNT ON
SELECT *
FROM dbo.COL_V_GEMS_DOM_FCT
WHERE REC_EFF_STT_DT BETWEEN '2010-01-01' AND '2012-12-31'
When I execute I do it like:
Execute COL_Run_DOM_Parameters #StartDate = '2011-12-22', #EndDate '2012-05-17'
But when I execute it still gives me all the data between 2010 and 2012 instead of the date range I asked for. Where in my code is there a mistake?
You need to change your query to reference the parameters!
ALTER PROCEDURE [dbo].[COL_Run_DOM_Parameters]
#StartDate varchar (50),
#EndDate varchar (50)
AS
SET NOCOUNT ON
SELECT *
FROM dbo.COL_V_GEMS_DOM_FCT
WHERE REC_EFF_STT_DT BETWEEN #StartDate and #EndDate
Execute just like you have been.
SELECT *
FROM dbo.COL_V_GEMS_DOM_FCT
WHERE REC_EFF_STT_DT BETWEEN '2010-01-01' AND '2012-12-31'
you have hardcoded the dates my friend , you are not using your variables
Change the query to
SELECT *
FROM dbo.COL_V_GEMS_DOM_FCT
WHERE REC_EFF_STT_DT BETWEEN #StartDate AND #EndDate
and call the SP like
Declare #StartDate = '2012-02-01'
Declare #EndDate = '2013-02-01'
EXEC COL_Run_DOM_Parameters #StartDate #EndDate

Looping in SELECT statement in ms sqlserver [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
SQL Server 2008 Generate a Series of date times
I have to Loop through a startDate and endDate
The SELECT statement should produce result as..
Expected Output :
------------
Date
------------
09/01/2012 -> startDate
09/02/2012
09/03/2012
.
.
.
.
09/30/2012 -> endDate
i tried
declare #startDate datetime , #endDate endDate
set #startDate='09/01/2012'
set #endDate='09/30/2012'
while DATEDIFF(#startDate,#endDate)!=-1
begin
select #startDate as Date
set #startDate = DATEADD(day,2,#startDate)
end
But its not working out..
it generates 30 outputs..
i want the dates in a single output as in the expected output..
where am i going wrong here guys ?
That will give you a resultset for each loop iteration as you select per iteration.
If you want a single resultset insert into a temp table/variable per iteration then select from it or
;with T(day) as
(
select #startDate as day
union all
select day + 1
from T
where day < #endDate
)
select day as [Date] from T
If you want to use a WHILE loop:
declare #startDate datetime , #endDate datetime
set #startDate='09/01/2012'
set #endDate='09/30/2012'
create table #temp (startDate datetime)
while #startDate <= #endDate
begin
insert into #temp
select #startDate as Date
set #startDate = DATEADD(day,1,#startDate)
end
select *
from #temp
drop table #temp
see SQL Fiddle with Demo
You could create a temp table for the values and select from that in the end, after the iteration.
declare #temp table (TheDate date)
declare #startDate datetime , #endDate datetime
set #startDate='09/01/2012'
set #endDate='09/30/2012'
while DATEDIFF(day, #startDate, #endDate)!=-1
begin
insert into #temp (thedate) values (#startDate)
set #startDate = DATEADD(day,2,#startDate)
end
select * from #temp
edit: The cte Alex suggest is imo a much cleaner way to do it, and more of a sql way to do it, without using loops or cursors.