Creating datetime sequence in 2008 R2 - sql

I need to create a dateime sequence with minute variable time increments in a temp table . The output should look something like when 5 is used
2012-12-13 04:20:00.000
2012-12-13 04:25:00.000
2012-12-13 04:30:00.000
2012-12-13 04:35:00.000
2012-12-13 04:40:00.000
2012-12-13 04:50:00.000
Can this be done?

WITH DateTimeSequence
AS
(
SELECT CONVERT(datetime, '2012-12-13 04:20:00', 120) AS [datetime] -- Start Date
UNION ALL
SELECT DATEADD(mi, 5, [datetime])
FROM DateTimeSequence
WHERE DATEADD(mi, 5, [datetime]) <= CONVERT(datetime, '2012-12-13 04:50:00', 120) -- End Date
)
SELECT [datetime]
FROM DateTimeSequence
SQLFiddle Demo

I would suggest using a sequence table - every database should have one because they are so useful generating datetime sequences quickly and easily.
CREATE TABLE Sequence
(Number int PRIMARY KEY)
Now fill this table with the integers from 0 to 1,000,000 - don't worry, you only need to do this once.
You can then generate datetime sequences as long as you like (well up to 1,000,001) with a variation of
SELECT DATEADD(minute, Number * #stepsize, #StartDateTime)
FROM Sequence
WHERE Number<#NumberRequired
See this SQL Fiddle
This will generally be faster than using CTE and will be almost as fast as retrieving the info direct from a table. In fact, you may consider not using a temporary table but building a SP (or table valued function) with this at the guts as it will be roughly the same speed and a lot more flexible.

Related

SQLSVR - not able to create index with computed GETDATE column

What I want to achieve: To create an index with an existing date column data converted into UTC timing (Query is written below)
Issue: There's a column in table with local server date values, I need to convert them into UTC date value and then create an Index over it.
Why I need this: I have the same thing done in oracle, and I am trying to migrate stuff along with queries into Sql Server for a new client
Problem: Index doesn't take variables or user defined functions. But only takes table columns as parameters.
Only Work around: is to make a computed column on table and use it to create the index.
Steps I followed:
Ran the below queries at first
ALTER TABLE dbo.tableClient ADD tempComp1 AS DATEADD(minute, datediff(minute, GETUTCDATE(), getdate()), [svrDate])
GO
create index idx1 on dbo.tableClient([key] asc, [tempComp1] desc, [type])
GO
It gives the below error:
Column 'tempComp1' in table 'dbo.tableClient' cannot be used in an index or statistics or as a partition key because it is non-deterministic.
So I tried making the column as PERSISTED
ALTER TABLE dbo.tableClient ADD tempComp1 AS DATEADD(minute, datediff(minute, GETUTCDATE(), getdate()), [svrDate]) PERSISTED
it now giving the error:
Computed column 'tempComp1' in table 'tableClient' cannot be persisted because the column is non-deterministic.
Now, the funny thing is, if I do
SELECT datediff(minute, GETUTCDATE(), getdate())
it gives result: 330
Now if I try the same commands with 330
ALTER TABLE dbo.tableClient ADD tempComp1 AS DATEADD(minute, 330, [svrDate]) PERSISTED
GO
create index idx1 on dbo.tableClient([key] asc, [tempComp1] desc, [type])
GO
it works absolutely fine.

How to assign variable to insert into a Table in SQL Server?

I have two tables.
NewTransaction_tb
OldTransaction_tb
I want to move the records from old to new table including date. But the OldTransaction_tb it doesn't have the Date column.
This is what I am trying.
For example
DECLARE #VarDate Datetime = CONVERT(datetime,GETDATE(),102)
INSERT INTO HQMatajer.dbo.NewTransaction_tb
SELECT
Name, class, Qualification, #VarDate //this #VarDate is not in OldTransaction_tb
FROM
HQMatajer.dbo.OldTransaction_tb
What is the solution for this scenario? Thanks,
You don't have to declare a variable for doing this, you can directly convert the string from the old table and insert to the new one.
INSERT into HQMatajer.dbo.NewTransaction_tb
SELECT Name,class,Qualification,CONVERT(datetime,GETDATE(),102)
FROM HQMatajer.dbo.OldTransaction_tb
You can use directly Date in select column
SELECT
Name,class,Qualification,CONVERT(datetime,GETDATE(),102)
See, the answer to this can be what you wrote or what others suggested.
The question is what you want in your result set.
For example, if you are processing a data set all at once, say entire of OldTransaction table, and you want that all the rows being transferred to NewTransaction should have the same DateTime, then it is preferred to do it by first declaring a variable and then calling it.
This is better than using the function in a SELECT clause because the function is then called once for every row. So if you have a billion rows in OldTransaction table then the function will be called a billion times and you will have a small speed impact.
But if your require all rows to have the exact date time of insertion, in case your insert takes a prolonged time over an hour or so, then there is no choice but to use the function within the SELECT statement.
SELECT
Name, Class, Qualification, CONVERT(Datetime, GETDATE(), 102)
FROM HQMatajer.dbo.OldTransaction_tb
Check this:
if table does not yet exist then use :
Select *
Into NewTransaction_tb
From
(select
* ,CONVERT(datetime, GETDATE(), 102) as Date
from
OldTransaction_tb) a
OR
if table already exists, then use :
insert into NewTransaction_tb
select
*, CONVERT(datetime, GETDATE(), 102) as Date
from
OldTransaction_tb

How do you choose specific id and time in SQL Server

I have this small program in C# that is constantly sending data to one of my tables (DataTable). The data format is always the same as well as the length.
There are 4 different IDs I am working with here: 2000,2001,2002, ...which are all in a different table. The ID column is the foreign key in my DataTable column.
Initially I thought I could just retrieve the last inserted row in my DataTable for a specific ID. However, I realized that the insert statement does allocate the values into the database in the order they are sent. Therefore, I decided to simply take an ID and get the last row of data based on the timestamp.
I have tried using DatePart but this limits me to only hours. I would want to display a time based on hours and min. ex: 2002 between '4:30:00' and '5:30:00'.
Also, would I have to do a join statement since I would be calling the ID column from another table?
Ive tried this so far: `
use LogDatabase
select * from dbo.DataTable
join CustomerTable
on(Customer_ID = CustIDFk)
where DATEPART(HH, TimeStamp)between 4 and 5 `
The incoming data string looks alot like this:
3-13-2011 3:30:21 2002: 45 Temp:81 Albany NY etc....
I have made columns for the every field of data in my DataTable. As you can see
2002 is the ID which is called Customer_ID in my CustomerTable. I have set this
as my primary key in the CustomerTable and CustIDFk is the foreign key to be linked
with Customer_ID. As you can see, I'm trying to join my Customer table with my Data
table in order to specify the ID. The DATEPART statement allows to give a time range
by either hour or min among others but does not allow a "between 4:30 and 5:30.
Would something like this work?
DECLARE #today DATETIME = CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME)
SELECT *
FROM dbo.DataTable
WHERE TIMESTAMP BETWEEN DATEADD(mi, 30, DATEADD(hh, 4, #today)) AND DATEADD(hh, 5, #today)

How automatically add 1 year date to an existing date in SQL Server

I have a task to automatically bill all registered patients in PatientsInfo table an Annual Bill of N2,500 base on the DateCreated column.
Certainly I will use a stored procedure to insert these records into the PatientDebit table and create a SQL Job to perform this procedure.
How will I select * patients in PatientsInfo table where DateCreated is now 1 yr old for me to insert into another table PatientDebit.
I have my algorithm like this:
select date of registration for patients from PatientsInfo table
Add 1 year to their DateCreated
Is date added today? if yes,
Insert record into PatientDebit table with the bill of N2,500
If no, do nothing.
Please how do I write the script?
Use DATEADD, i.e.:
SELECT DATEADD(year, 1, '2006-08-30')
Ref.: http://msdn.microsoft.com/en-us/library/ms186819.aspx
Assuming the columns of the 2 tables are the same:
INSERT INTO PatientDebit
SELECT * from PatientsInfo WHERE DateCreated<DATEADD(year, -1, GETDATE())
Make sure you have an index on DateCreated if PatientsInfo has a lot of records as it could potentially be slow otherwise
there should be .add or addyear() function in sql. You add like .add(year, day, month). Read upon sql datetime add year, month and seconds. It is pretty straightforward. It is just like c#.
Dateadd(info). now time is. getdate().

Recursive SQL query to speed up non-indexed query

This question is largely driven by curiosity, as I do have a working query (it just takes a little longer than I would like).
I have a table with 4 million rows. The only index on this table is an auto-increment BigInt ID. The query is looking for distinct values in one of the columns, but only going back 1 day. Unfortunately, the ReportDate column that is evaluated is not of the DateTime type, or even a BigInt, but is char(8) in the format of YYYYMMDD. So the query is a bit slow.
SELECT Category
FROM Reports
where ReportDate = CONVERT(VARCHAR(8), GETDATE(), 112)
GROUP BY Category
Note that the date converstion in the above statement is simply converting it to a YYYYMMDD format for comparison.
I was wondering if there was a way to optimize this query based on the fact that I know that the only data I am interested in is at the "bottom" of the table. I was thinking of some sort of recursive SELECT function which gradually grew a temporary table that could be used for the final query.
For example, in psuedo-sql:
N = 128
TemporaryTable = SELECT TOP {N} *
FROM Reports
ORDER BY ID DESC
/* Once we hit a date < Today, we can stop */
if(TemporaryTable does not contain ReportDate < Today)
N = N**2
Repeat Select
/* We now have a smallish table to do our query */
SELECT Category
FROM TemproaryTable
where ReportDate = CONVERT(VARCHAR(8), GETDATE(), 112)
GROUP BY Category
Does that make sense? Is something like that possible?
This is on MS SQL Server 2008.
I might suggest you do not need to convert the Date that is stored as char data in YYYYMMDD format; That format is inherently sortable all by itself. I would instead convert your date to output in that format.
Also, the way you have the conversion written, it is converting the current DateTime for every individual row, so even storing that value for the whole query could speed things up... but I think just converting the date you are searching for to that format of char would help.
I would also suggest getting the index(es) you need created, of course... but that's not the question you asked :P
Why not just create the index you need?
create index idx_Reports_ReportDate
on Reports(ReportDate, Category)
No, that doesn't make sense. The only way to optimize this query is to have a covering index for it:
CREATE INDEX ndxReportDateCategory ON Reports (ReportDate, Category);
Update
Considering your comment that you cannot modify the schema, then you should modify the schema. If you still can't, then the answer still applies: the solution is to have an index.
And finally, to answer more directly your question, if you have a strong correlation between ID and ReportData: the ID you seek is the biggest one that has a ReportDate smaller than the date you're after:
SELECT MAX(Id)
FROM Reports
WHERE ReportDate < 'YYYYMMDD';
This will do a reverse scan on the ID index and stop at the first ID that is previous to your desired date (ie. will not scan the entire table). You can then filter your reports base don this found max Id.
I think you will find the discussion on SARGability, on Rob Farley's Blog to be very interesting reading in relation to your post topic.
http://blogs.lobsterpot.com.au/2010/01/22/sargable-functions-in-sql-server/
An interesting alternative approach that does not require you to modify the existing column data type would be to leverage computed columns.
alter table REPORTS
add castAsDate as CAST(ReportDate as date)
create index rf_so2 on REPORTS(castAsDate) include (ReportDate)
One of the query patterns I occasionally use to get into a log table with similiar indexing to yours is to limit by subquery:
DECLARE #ReportDate varchar(8)
SET #ReportDate = Convert(varchar(8), GetDate(), 112)
SELECT *
FROM
(
SELECT top 20000 *
FROM Reports
ORDER BY ID desc
) sub
WHERE sub.ReportDate = #ReportDate
20k/4M = 0.5% of the table is read.
Here's a loop solution. Note: might want to make ID primary key and Reportdate indexed in the temp table.
DECLARE #ReportDate varchar(8)
SET #ReportDate = Convert(varchar(8), GetDate(), 112)
DECLARE #CurrentDate varchar(8), MinKey bigint
SELECT top 2000 * INTO #MyTable
FROM Reports ORDER BY ID desc
SELECT #CurrentDate = MIN(ReportDate), #MinKey = MIN(ID)
FROM #MyTable
WHILE #ReportDate <= #CurrentDate
BEGIN
SELECT top 2000 * INTO #MyTable
FROM Reports WHERE ID < #MinKey ORDER BY ID desc
SELECT #CurrentDate = MIN(ReportDate), #MinKey = MIN(ID)
FROM #MyTable
END
SELECT * FROM #MyTable
WHERE ReportDate = #ReportDate
DROP TABLE #MyTable