update field every hour in SQL Server - sql

I have the following query in a job, it is scheduled to run every hour of L-V.
All the records that are made in the table in the FCH_FIN field have an exact time, for example: 7:00:00 to 19:00:00.
Then I create a temporary table and pass the data from my original table, and I want to go through my temporary table to get the difference in time between the system time using GETDATE () and the time of the record in the FCH_FIN field, if this is less then update active to 0.
Query:
DECLARE #count INT;
DECLARE #fch2 DATETIME;
DECLARE #seconds INT;
CREATE table #Suple
(
ID INT PRIMARY KEY NOT NULL,
ACTIVO NCHAR(10) NOT NULL,
FCH_INICIO DATETIME NOT NULL,
FCH_FIN DATETIME NOT NULL
);
INSERT INTO #Suple
SELECT *
FROM Original
WHERE ACTIVO = 1
AND CONVERT(DATE, FCH_FIN) = CONVERT(DATE, GETDATE());
SELECT #count = COUNT(*) FROM #Suple;
WHILE #count > 0
BEGIN
SELECT
#seconds = DATEDIFF(S, GETDATE(),FCH_FIN)
FROM
#Suple
WHERE
ACTIVO = 1
AND CONVERT(DATE, FCH_FIN) = CONVERT(DATE, GETDATE())
IF (#seconds < 3)
UPDATE Original
SET ACTIVO = 0
DELETE TOP(1) FROM #Suple
SET #count = (SELECT COUNT(*) FROM #Suple);
END
DROP TABLE #Suple
This query does not update anything
Table:
Can someone help me?

Why are you doing this in a loop in the first place? But look at your update statement. You are updating every single row in Original every iteration of the loop. But this should not be using a loop at all. Your ENTIRE code block here can be reduced to a single statement. You don't need temp tables or loops for this.
Also using shorthand in date functions is a challenge.
Update Original
where ACTIVO = 0
AND CONVERT(DATE, FCH_FIN) = CONVERT(DATE, GETDATE())
and DATEDIFF(Second, GETDATE(),FCH_FIN) < 3

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()

Defining type as a variable - DATEADD(type, value, date) - SQL [duplicate]

This question already has answers here:
SQL Dynamic DatePart when using DateDiff
(6 answers)
Closed 5 years ago.
I had to change the date in one of a column of my SQL table (datetime field), increment YEAR by 1. The simple way to perform this action would be (unless someone knows a better way) to update table and SET column with DATEADD()
-- sample 1
-- DATEADD(type, value, date)
SELECT DATEADD(YEAR, 1, GETDATE())
Since I'm a lazy programmer, I don't want to keep updating the tables every time we run in to such situation. So I decided to write a small script (function) which gets TYPE, VALUE from the user and perform the operation. But I ran into a situation where I can't use TYPE as a variable.
-- Sample 2
-- Error in the code
DECLARE #type VARCHAR(10) = 'YEAR'
,#increment INT = 1
SELECT DATEADD(#type, #increment, GETDATE())
I can write a case statement where based on the 'TYPE' value I can select the update statement.
-- Sample 3
DECLARE #type VARCHAR(10) = 'YEAR'
,#increment INT = 1
UPDATE Table_name
SET Column_date = CASE #type WHEN 'YEAR' THEN DATEADD(YEAR, #increment, Column_date)
WHEN 'MONTH' THEN DATEADD(MONTH, #increment, Column_date)
-- and so on
END
But is there a way to perform the action without the case statement, or can anyone make sample code '2' run?
P.S. Its more of a knowledge based question - Its not holding me back, I'm just curious to know if its possible.
Thanks! :)
You could just get all of the type values from the user and just update them all at once.. Just default to 0 the ones they don't want to change
DECLARE #Year INT = 0,
#Month INT = 0,
#Day INT = 0
UPDATE Table_name
SET Column_date = DATEADD(YEAR, #Year, DATEADD(Month, #Month, DATEADD(Day, #Day, Column_date)))
An alternative to already provided solution is to use a dynamic SQL:
Setup:
-- drop table dbo.DateTest
create table dbo.DateTest
(
TheDate DATE,
UpdatedDate DATE
)
TRUNCATE TABLE dbo.DateTest
GO
INSERT INTO dbo.DateTest (TheDate) VALUES ('20150203'), ('20150506'), ('20141231')
GO
Code:
select * from dbo.DateTest
DECLARE #type VARCHAR(8) = 'year' -- this must be a DATEADD recognizable token
DECLARE #increment INT = 2
DECLARE #Sql NVARCHAR(1000) = N'
UPDATE dbo.DateTest SET UpdatedDate = DATEADD(' + #type + ', #increment, TheDate)'
EXEC sp_executesql #Sql, N' #increment INT', #increment
select * from dbo.DateTest
I wish date part could be provided as parameter, but it does not seem to be possible.

Autofill SQL table field with Datetime value based on input parameter

I have a datetime field in my SQL table. I have created a procedure that takes count as a variable and generates records for the table. If the count is 5 it will generate 5 records.The logic i want is that when i provide 5 as an input parameter the datetime field in the table should be autofilled with values
12/20/2015 9:00
12/20/2015 11:00
12/20/2015 13:00
12/20/2015 15:00
12/20/2015 17:00
So every time a record is inserted into a table,the 2 hours of time should be added.
Recursive CTEs are one way to create records on the fly. The key here is to create an anchor (this is the first SELECT inside the CTE, which is your starting point). And an exit check (which is the WHERE clause).
Read up on MAXRECURSION if you want to create more than 100 records at a time.
Example
DECLARE #RecordsRequired INT = 5;
DECLARE #BaseDateTime SMALLDATETIME = GETDATE();
WITH [Sample] AS
(
/* This CTE uses recursion to create the required number of
* records.
*/
SELECT
1 AS RowNumber,
#BaseDateTime AS [DateTime]
UNION ALL
SELECT
RowNumber + 1 AS RowNumber,
DATEADD(HOUR, 2, [DateTime]) AS [DateTime]
FROM
[Sample]
WHERE
RowNumber < #RecordsRequired
)
SELECT
RowNumber,
[DateTime]
FROM
[Sample]
;
You could also look into WHILE blocks.
Use this code:
------------------ INPUT ------------------------
declare #start_date datetime = '01/01/2000 14:00'
declare #loops int = 5
-------------------------------------------------
declare #i int = 0
while (#i < #loops) begin
select dateadd(hour, #i * 2, #start_date)
set #i = #i + 1
end
Try this without LOOP
Declare #count int = 5,
#incrementer int =2 -- in case if you want to change the incrementer
SELECT Dateadd(hh, num * #incrementer, dates)
FROM (SELECT Cast(CONVERT(VARCHAR(20), Dateadd(dd, 1, Getdate()), 111)
+ ' 9:00 AM' AS DATETIME) AS Dates,
num
FROM (VALUES(0),(1),(2),(3),(4),(5)) TC (num)) A
WHERE num <= #count - 1
SQL FIDDLE DEMO
Please find the sample code below, it contains the logic that you needed. Hope it helps!!
--Create a temp table for sample output
CREATE TABLE #temp
(
CreatedDate datetime
)
--Declaring variables
DECLARE #Count int
DECLARE #TimeCounter int
--intializing values
SET #Count=5
SET #TimeCounter=0
WHILE(#Count>0)
BEGIN
--SELECT getdate()+1
insert into #temp(#temp.CreatedDate) Select DATEADD(hour,#TimeCounter,getdate())
SET #TimeCounter=#TimeCounter+2
SET #Count=#Count-1
END
--Final values
SELECT * FROM #temp tmp
--Dropping table
DROP TABLE #temp
This is one of those problems that's best solved with a numbers table / function. Much less code than recursion or loops, usually faster for anything non-trivial and more reusable too.
The core code you want is
CREATE PROCEDURE usp_PopulateAppointments
(
#StartDateTime datetime2(3),
#Records int,
#Interval int = 120 --Time between appointment slots in minutes. Default to 2h if not manually specified.
)
INSERT INTO Appointments
SELECT
DATEADD(m, #Interval * Number, #StartDateTime)
FROM dbo.udfNumbers(0, #Recs)
I've assumed in this a numbers function that takes #StartAt and #NumberResults. I use one derived from Adam's final code in the comments on http://dataeducation.com/you-require-a-numbers-table/ - in my experience it's faster than a real table, and takes less space too.
Create Table dates
(
datetimefield datetime not null
)
go
Create Procedure FillDateTimeField
#insertxrows int
AS
begin
Declare #LastDateTimeInserted as datetime
set #LastDateTimeInserted = (select isnull(max(datetimefield),getdate()) from Dates)
;WITH norows AS (
SELECT 1 as num, Dateadd(hour,2,#LastDateTimeInserted) as FirstRecord
UNION ALL
SELECT num + 1, dateadd(hour,2,firstrecord) FROM
norows
WHERE num < #insertxrows
)
insert into dates
select firstrecord from norows
end

SQL write a file with a file number incremented by 1 every time

In sql I am currently writing out a CSV file called "TodaysData". I want to be able to name it with a number at the end so every time the job executes it out puts the file name with the incremented number e.g
TodaysData.001
TodaysData.002
TodaysData.003 etc
Please can someone help me with the code for this
There is number of ways you can do it. One of the easiest would be to store value in table since this job can execute multiple time per day.
CREATE TABLE MyFileCountTable
(
File_Date DATE
,File_Count INT
)
DECLARE #FileCount INT;
IF (
SELECT COUNT(*)
FROM MyTable
WHERE File_Date = CONVERT(DATE, GETDATE())
) = 0
BEGIN
INSERT INTO MyTable VALUES (CONVERT(DATE, GETDATE()), 1)
SET #FileCount = 1
END
ELSE
BEGIN
SELECT #FileCount = File_Count
FROM MyTable
WHERE File_Date = CONVERT(DATE, GETDATE())
END
--Code here to produce the file and append #FileCount
UPDATE MyTable
SET File_Count = File_Count + 1
WHERE File_Date = CONVERT(DATE, GETDATE())