Dynamic SQL to randomize all datetime columns in a database - sql-server

I'm having trouble figuring out how to use a dynamic SQL Server query to change the datetime fields in my database, called OnlineStore, to be random and in the current year.
It should be noted that this relates to homework. My class is fairly unstructured, so I'm having a hard time knowing where to go from here.
My question is: How can I write a dynamic SQL Server query that may use loops or table variables and takes the 2 datetime columns in my database (Product.LastOrderDate, Orders.OrderDate) and assigns each row a random date in the current year?
This is what I have so far. I'm open to any changes.
Declare #SQL varchar(max) = '
Declare #D1 float = cast(cast(''2017-01-01 00:00:00'' as datetime) as float);
Declare #D2 float = cast(cast(''2017-12-31 23:59:59'' as datetime) as float);

Based on this answer I came up with the following. It randomly adds n seconds to the date 2017-01-01 capped at the number of seconds in 2017.
The first bit is just me generating a table with 50 rows, all 2017-01-01.
You'll want to focus on the parts from update on...
if object_id('tempdb..#test') is not null drop table #test
create table #test (orderDate datetime)
-- add 50 rows to test table
;with x as
(
select 1 as t
union all
select t+1
from x
)
insert into #test
select top 50 '2017-01-01'
from x
option(maxrecursion 50)
--select * from #test
update t
set OrderDate = dateadd(second,ABS(CHECKSUM(NewId())) % datediff(second,'2017-01-01 00:00:00','2017-12-31 23:59:59'),'2017-01-01 00:00:00')
from #test t
select * from #test

Based on this answer: https://stackoverflow.com/a/18408615
This gets you almost all the way there for generating a random date, I capped the days at 28 due to February being February.
select cast('2017-' + CAST(ABS(Checksum(NEWID()) % 12) + 1 AS varchar(2)) + '-' + CAST(ABS(Checksum(NEWID()) % 28) + 1 AS varchar(2)) as date)
You can adapt this to fit your needs.

Related

SQL Server - DECLARE SET is taking too much time to execute than hardcoding the parameters in where condition

I have a simple select statement of a CTE where I have Declared and SET values before the WITH and I'm fetching data for a single day which would be having nearly 200,000 rows of data. If I execute that query, it is taking more time(not completed in 10 minutes). But If I remove those DECLARE, SET and hardcoded those input values in WHERE condition, the results are shown in 15 SECONDS.
This table has nearly 350 million rows of data with Proper Indexing of Primary Key columns.
What could be the possibility of this slowness?
Actual Query
DECLARE #StartTime DATETIME
DECLARE #EndTime DATETIME
DECLARE #ApplicationName VARCHAR(100)
SET #StartTime = '2018-12-10'
SET #EndTime = '2018-12-10'
SET #Applicationname = 'APPNAME'
;WITH TOTAL as (
SELECT * FROM TABLE WHERE DATETIME >= + #StartTime + '00:00:01' AND
DATETIME <= + #EndTime + '23:59:59'
AND APPLICATIONID=(SELECT APPLICATIONID FROM APPLICATION WHERE ApplicationName=#Applicationname
)
SELECT * FROM TOTAL
After Change
SELECT * FROM TABLE WHERE DATETIME >= '2018-12-10 00:00:01' AND
DATETIME <= '2018-12-10 23:59:59'
AND APPLICATIONID=(SELECT APPLICATIONID FROM APPLICATION WHERE ApplicationName='APPNAME'
Actually the DB has an SP with Long query, here I have provided the first CTE table only and the same kind of table conditions applicable to my rest of the CTE tables. If I get a clue for this slowness, I would fix the rest of my queries.
Since SQL server have to compile the variables StartTime and EndTime for each record on the TABLE for filtering, it takes longer. if you do something like the following:
DECLARE #StartTime DATETIME
DECLARE #EndTime DATETIME
DECLARE #ApplicationName VARCHAR(100)
SET #StartTime = '2018-12-10 00:00:01'
SET #EndTime = '2018-12-10 23:59:59'
SET #Applicationname = 'APPNAME'
SELECT *
FROM TABLE
WHERE DATETIME >= #StartTime AND DATETIME <= #EndTime
AND APPLICATIONID=(SELECT APPLICATIONID FROM APPLICATION WHERE
ApplicationName=#Applicationname
By doing this, you are reducing the load at the filtering time and doing pre-computing the required fixed variables.

Copying data with different dates in SQL Server

I have a table with 4 columns and 8000 rows of data with a datetime column as 2016-01-05. I want to copy these 8000 rows of data to all the days of January from 1st to 31st.
Meaning, I should have 8000 * 31 days of data even though its the same data.
How do I do it without using an Excel document.
By creating a quick date sequence and cross joining your table to it you can update your table however you need to:
CREATE TABLE #t (c1 INT, c2 INT, c3 INT, c4 INT);
INSERT INTO #t
VALUES (10, 10, 10, 10),
(20, 20, 20, 20);
;
WITH CTE_Dates AS (
SELECT TOP 31
DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY ao.object_id) - 1, '2016-01-01') AS Date
FROM sys.all_objects AS ao
)
SELECT #t.c1,
#t.c2,
#t.c3,
#t.c4,
CTE_Dates.Date
FROM #t
CROSS JOIN CTE_Dates;
First, create a temporary date table with values for each day in January 2016.
CREATE TABLE #TEMPDATE (DateCol DATETIME)
DECLARE #DAY INT = 1
DECLARE #DATE DATE = '2016-01-01'
WHILE #DAY <= 31
BEGIN
INSERT #TEMPDATE
VALUES (#DATE)
SET #DAY +=1
SET #DATE = DATEADD(DD,1,#DATE)
END
Next, you can SELECT desired columns and CROSS JOIN as others have said as well. Should get you the cartesian product between the two tables (8000 x 31 rows).
SELECT c.Column1, c.Column2, c.Column3, t.DateCol
FROM #TEMPDATE t
CROSS JOIN YourTableName c

Creating local variables from parameters increases sproc performance

I have a relatively simple stored procedure that is used to group data inside a relatively nasty view I have no control over based on the supplied parameters. A simplified version of the stored procedure is:
CREATE PROCEDURE dbo.GroupList
#list VARCHAR(MAX),
#start DATETIME,
#end DATETIME,
#resolution INT
AS
BEGIN
SET NOCOUNT ON
declare #elements ListTVP;
insert into #elements select Value as elementID from udf_Split(#localList, ',');
IF #resolution = 1 -- group by month
BEGIN
SELECT *
FROM (
SELECT
Timestamp = CAST(CONVERT(VARCHAR, DATEPART(YEAR, Timestamp)) + '-' + CONVERT(VARCHAR, DATEPART(MONTH, Timestamp)) + '-01' AS DATETIME)
, Total = SUM(Cost)
FROM eLP e
INNER JOIN #elements m ON e.elementID = m.elementID
WHERE Timestamp >= #start AND Timestamp <= #end
GROUP BY
DATEPART(YEAR, Timestamp),
DATEPART(MONTH, Timestamp)
) AS t1
END
ELSE IF #resolution = 2 -- group by year
BEGIN
SELECT *
FROM (
SELECT
Timestamp = CAST(CONVERT(VARCHAR, DATEPART(YEAR, Timestamp)) + '-01-01' AS DATETIME)
, Total = SUM(Cost)
FROM eLP e
INNER JOIN #elements m ON e.elementID = m.elementID
WHERE Timestamp >= #start AND Timestamp <= #end
GROUP BY
DATEPART(YEAR, Timestamp)
) AS t1
END
END
If I run the SQL code in the stored procedure inside SSMS, the code is relatively fast. If I run the stored procedure, the code is between 10 to 100 times slower for the exact same data. Why is this happening?
Also, I've noticed that if I create local variables from the supplied parameters, performance improves dramatically:
CREATE PROCEDURE dbo.GroupListWithVariables
#list VARCHAR(MAX),
#start DATETIME,
#end DATETIME,
#resolution INT
AS
BEGIN
DECLARE #localList VARCHAR(MAX) = #list
DECLARE #localStart DATETIME = #start, #localEnd DATETIME = #end
DECLARE #localResolution INT = #resolution
Comparing the execution time of the 2 versions of the stored procedure, I have:
GroupList:
568 ms average execution time
9 seconds reported by SSMS to actually run the sproc and retrieve the results
355 kB of data received from server
GroupListWithVariables:
1040 ms average execution time
1 second reported by SSMS to actually run the sproc and retrieve the results
239 kB of data received from server
Why is there such a large difference between the 2 versions? I've noticed the same behavior in both SQL Server 2008 R2, as well as in SQL Server 2012.
You may want to read about SQL Parameter Sniffing. http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx
This might help explain the performance difference.

How to compare datetime in SQL Server in where clause

I have CreatedDate as datetime column in my database table. I want to fetch the rows where CreatedDate and current time difference is more than 1 hour
Select * from TableName where (DateDiff(hh,CreatedDate,GetDate())>1
Answer by #Amit Singh works if you only care about the hour value itself, versus any 60 minute period.
The problem with using DATEDIFF(hh) that way is that times of 13:01 and 14:59 are only one "hour" apart.
Like:
select datediff(hh,'1/1/2001 13:59','1/1/2001 14:01')
I think doing this would address that issue:
declare #cd datetime='9/12/2013 03:10';
declare #t table(id int,CreatedDate datetime);
insert #t select 1,'9/12/2013 02:50';
insert #t select 2,'9/12/2013 02:05';
select * from #t where #cd>(DateAdd(hh,1,CreatedDate))
Dan Bellandi raises a valid point, but if it really matters if the dates should be 60 minutes apart, then just check if they are 60 minutes apart:
SELECT * FROM TableName WHERE DATEDIFF(MINUTE, DateColumnName, GETDATE()) >= 60
If you don't expect any rows created in the future...
where CreatedDate < dateadd(hour, -1, getdate())
CREATE TABLE trialforDate
(
id INT NULL,
NAME VARCHAR(20) NULL,
addeddate DATETIME NULL
)
INSERT INTO trialforDate VALUES (1,'xxxx',GETDATE())
INSERT INTO trialforDate VALUES (2,'yyyy',GETDATE())
INSERT INTO trialforDate VALUES (1,'zzzz','2013-09-12 11:20:40.533')
SELECT *
FROM trialforDate
WHERE GETDATE() > DATEADD(HOUR, 1, addeddate)
C# Code
DateTime param1= System.DateTime.Now;
DateTime param2= System.DateTime.Now.AddHours(1);
SQL Query:
SELECT * FROM TableName WHERE CreatedDate = param1 AND CreatedDate =param2;

T-SQL query with date range

I have a fairly weird 'bug' with a simple query, and I vaguely remember reading the reason for it somewhere a long time ago but would love someone to refresh my memory.
The table is a basic ID, Datetime table.
The query is:
select ID, Datetime from Table where Datetime <= '2010-03-31 23:59:59'
The problem is that the query results include results where the Datetime is '2010-04-01 00:00:00'. The next day. Which it shouldn't.
Anyone?
Cheers
Moo
Take a look at How Are Dates Stored In SQL Server? and How Does Between Work With Dates In SQL Server?
If that is a smalldatetime it has 1 minute precision so if rounds up, for datetime it is 300 miliseconds
example
DECLARE #d DATETIME
SELECT #d = '2001-12-31 23:59:59.999'
SELECT #d
2002-01-01 00:00:00.000
DECLARE #d DATETIME
SELECT #d = '2001-12-31 23:59:59.998'
SELECT #d
2001-12-31 23:59:59.997
Always use less than next day at midnight, in your case
< '20100401'
try doing it like:
select ID, Datetime from Table where Datetime < '2010-04-01'
I always floor the datetime and increment the day and just use "<" less than.
to floor a datetime to just the day use:
SELECT DATEADD(day,DATEDIFF(day,0, GETDATE() ),0)
you can easily increment a datetime by using addition:
SELECT GETDATE()+1
by using the '23:59:59' you can miss rows, try it out:
DECLARE #YourTable table (RowID int, DateOf datetime)
INSERT INTO #YourTable VALUES (1,'2010-03-31 10:00')
INSERT INTO #YourTable VALUES (2,'2010-03-31')
INSERT INTO #YourTable VALUES (3,'2010-03-31 23:59:59')
INSERT INTO #YourTable VALUES (4,'2010-03-31 23:59:59.887')
INSERT INTO #YourTable VALUES (5,'2010-04-01')
INSERT INTO #YourTable VALUES (6,'2010-04-01 10:00')
select * from #YourTable where DateOf <= '2010-03-31 23:59:59'
OUTPUT
RowID DateOf
----------- -----------------------
1 2010-03-31 10:00:00.000
2 2010-03-31 00:00:00.000
3 2010-03-31 23:59:59.000
(3 row(s) affected
this query is wrong, because it does not find the missed rowID=4 record.
if you try to fix this with:
select * from #YourTable where DateOf <= '2010-03-31 23:59:59.999'
then RowID=5 will be included as well, which is wrong.
It's very odd that you are seeing that; I don't know why. But I will suggest that you write the query this way instead:
select ID, Datetime from Table where Datetime < '2010-04-01'

Resources