Converting YYYYMM format to YYYY-MM-DD in SQL Server - sql

I need to perform a query on a large table that has a datetime column that is indexed.
We need to query the data for a range from a month (at a minimum) to multiple months.
This query would be executed from Cognos TM1 and the input would be a period like YYYYMM. My question is - how to convert the YYYYMM input to a format that can be used to query that table (with the index being used).
Let's say if the input is
From Date: '201312'
To Date: '201312'
then, we need convert the same to 'between 01-12-2013 and 31-12-2013' in the query
Since we need this to be hooked up in Cognos TM1, so would not be able to write a procedure or declare variables (TM1 somehow does not like it).
Thanks in advance for your reply.

I would do something like this:
create procedure dbo.getDataForMonth
#yyyymm char(6) = null
as
--
-- use the current year/month if the year or month is invalid was omitted
--
set #yyyymm = case coalesce(#yyyymm,'')
when '' then convert(char(6),current_timestamp,112)
else #yyyymm
end
--
-- this should throw an exception if the date is invalid
--
declare #dtFrom date = convert(date,#yyyymm+'01') -- 1st of specified month
declare #dtThru date = dateadd(month,1,#dtFrom) -- 1st of next month
--
-- your Big Ugly Query Here
--
select *
from dbo.some_table t
where t.date_of_record >= #dtFrom
and t.date_of_record < #dtThru
--
-- That's about all there is to it.
--
return 0
go

Suppose you are getting this value of YYYYMM in a varchar variable #datefrom .
You can do something like
DECLARE #DateFrom VARCHAR(6) = '201201';
-- Append '01' to any passed string and it will get all
-- records starting from that month in that year
DECLARE #Date VARCHAR(8) = #DateFrom + '01'
-- in your query do something like
SELECT * FROM TableName WHERE DateTimeColumn >= #Date
Passing Datetime in a ansi-standard format i.e YYYYMMDD is a sargable expression and allows sql server to take advantage of indexes defined on that datetime column.
here is an article written by Rob Farley about SARGable functions in SQL Server.

Try this...
declare #startdate date,#endate date
select #startdate =convert(date,left('201312',4)+'-'+right('201312',2)+'-01')
select #endate= DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, #startdate) + 1, 0))
select convert(date,#startdate,102) startdate,convert(date,#endate,102) endate

In the datasource of your TM1 Turbo Integrator process, you can use parameters in the SQL query. E.g. you could take this SQL query:
SELECT Col1, Col2
FROM Table
WHERE Col1 = 'Green'
AND Col2 < 30
In TM1, to parameterise this, you would create two parameters e.g. P1 and P2 and put them in the query:
SELECT Col1, Col2
FROM Table
WHERE Col1 = '?P1?'
AND Col2 < ?P2?

Related

How to calculate average in date column

I don't know how to calculate the average age of a column of type date in SQL Server.
You can use datediff() and aggregation. Assuming that your date column is called dt in table mytable, and that you want the average age in years over the whole table, then you would do:
select avg(datediff(year, dt, getdate())) avg_age
from mytable
You can change the first argument to datediff() (which is called the date part), to any other supported value depending on what you actually mean by age; for example datediff(day, dt, getdate()) gives you the difference in days.
First, lets calculate the age in years correctly. See the comments in the code with the understanding that DATEDIFF does NOT calculate age. It only calculates the number of temporal boundaries that it crosses.
--===== Local obviously named variables defined and assigned
DECLARE #StartDT DATETIME = '2019-12-31 23:59:59.997'
,#EndDT DATETIME = '2020-01-01 00:00:00.000'
;
--===== Show the difference in milliseconds between the two date/times
-- Because of the rounding that DATETIME does on 3.3ms resolution, this will return 4ms,
-- which certainly does NOT depict an age of 1 year.
SELECT DATEDIFF(ms,#StartDT,#EndDT)
;
--===== This solution will mistakenly return an age of 1 year for the dates given,
-- which are only about 4ms apart according the SELECT above.
SELECT IncorrectAgeInYears = DATEDIFF(YEAR, #StartDT, #EndDT)
;
--===== This calulates the age in years correctly in T-SQL.
-- If the anniversary data has not yet occurred, 1 year is substracted.
SELECT CorrectAgeInYears = DATEDIFF(yy, #StartDT, #EndDT)
- IIF(DATEADD(yy, DATEDIFF(yy, #StartDT, #EndDT), #StartDT) > #EndDT, 1, 0)
;
Now, lets turn that correct calculation into a Table Valued Function that returns a single scalar value producing a really high speed "Inline Scalar Function".
CREATE FUNCTION [dbo].[AgeInYears]
(
#StartDT DATETIME, --Date of birth or date of manufacture or start date.
#EndDT DATETIME --Usually, GETDATE() or CURRENT_TIMESTAMP but
--can be any date source like a column that has an end date.
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
SELECT AgeInYears = DATEDIFF(yy, #StartDT, #EndDT)
- IIF(DATEADD(yy, DATEDIFF(yy, #StartDT, #EndDT), #StartDT) > #EndDT, 1, 0)
;
Then, to Dale's point, let's create a test table and populate it. This one is a little overkill for this problem but it's also useful for a lot of different examples. Don't let the million rows scare you... this runs in just over 2 seconds on my laptop including the Clustered Index creation.
--===== Create and populate a large test table on-the-fly.
-- "SomeInt" has a range of 1 to 50,000 numbers
-- "SomeLetters2" has a range of "AA" to "ZZ"
-- "SomeDecimal has a range of 10.00 to 100.00 numbers
-- "SomeDate" has a range of >=01/01/2000 & <01/01/2020 whole dates
-- "SomeDateTime" has a range of >=01/01/2000 & <01/01/2020 Date/Times
-- "SomeRand" contains the value of RAND just to show it can be done without a loop.
-- "SomeHex9" contains 9 hex digits from NEWID()
-- "SomeFluff" is a fixed width CHAR column just to give the table a little bulk.
SELECT TOP 1000000
SomeInt = ABS(CHECKSUM(NEWID())%50000) + 1
,SomeLetters2 = CHAR(ABS(CHECKSUM(NEWID())%26) + 65)
+ CHAR(ABS(CHECKSUM(NEWID())%26) + 65)
,SomeDecimal = CAST(RAND(CHECKSUM(NEWID())) * 90 + 10 AS DECIMAL(9,2))
,SomeDate = DATEADD(dd, ABS(CHECKSUM(NEWID())%DATEDIFF(dd,'2000','2020')), '2000')
,SomeDateTime = DATEADD(dd, DATEDIFF(dd,0,'2000'), RAND(CHECKSUM(NEWID())) * DATEDIFF(dd,'2000','2020'))
,SomeRand = RAND(CHECKSUM(NEWID())) --CHECKSUM produces an INT and is MUCH faster than conversion to VARBINARY.
,SomeHex9 = RIGHT(NEWID(),9)
,SomeFluff = CONVERT(CHAR(170),'170 CHARACTERS RESERVED') --Just to add a little bulk to the table.
INTO dbo.JBMTest
FROM sys.all_columns ac1 --Cross Join forms up to a 16 million rows
CROSS JOIN sys.all_columns ac2 --Pseudo Cursor
;
GO
--===== Add a non-unique Clustered Index to SomeDateTime for this demo.
CREATE CLUSTERED INDEX IXC_Test ON dbo.JBMTest (SomeDateTime ASC)
;
Now, lets find the average age of those million represented by the SomeDateTime column.
SELECT AvgAgeInYears = AVG(age.AgeInYears )
,RowsCounted = COUNT(*)
FROM dbo.JBMTest tst
CROSS APPLY dbo.AgeInYears(SomeDateTime,GETDATE()) age
;
Results:

Check a date (excluding year)

In SQL Server, how can I check if one calendar date consisting of a day and month is older than another certain date, programmatically?
For example: I need to check if TransactionDate is on or before June 30, in all year.
TransactionDate <= (June 30)
Use DATEPART like this:
declare #var1 date = '2016-02-07';
declare #var2 date = '2017-02-06';
SELECT CASE
WHEN DATEPART(MM, #var1 ) * 100 + DATEPART(DD, #var1 )
> DATEPART(MM, #var2 ) * 100 + DATEPART(DD, #var2 ) THEN 'YES'
ELSE 'NO' END AS LARGERDATE;
It compares the dates as two integers in form of MMDD. For example:
'2016-02-07' ==> 207, '2017-02-06' ==> 206
'2010-10-27' ==> 1027, '2017-07-29' ==> 729
Most correct way will be to use DATEPART function; especially because it is available from all versions of SQL server since 2008, Azure SQL Database, Azure SQL Data Warehouse and Parallel Data Warehouse too.
You can check using the expression assuming you have the date to be compared against stored in #yourCheckDate variable
DECLARE #yourCheckDate DATETIME
DECLARE #m INT
DECLARE #d INT
SELECT #yourCheckDate = CAST('2017-6-30 12:15:32' AS DATETIME)
SELECT #m= DATEPART(month, #yourCheckDate)
SELECT #d= DATEPART(day, #yourCheckDate)
-- expression
select 1 where
DATEPART(month,#tranDate) < #m
OR
( DATEPART(month,#tranDate) = #m AND DATEPART(day,#tranDate) <= #d )
A SQL Server 2008 solution which supports any calendar date, derived from #TheEsisia and #Sami answers
WHERE 100*MONTH(TransactionDate) + DAY(TransactionDate) <= 100*MONTH(#checkDate) + DAY(#checkDate)
This should work if you want to get all dates from a date to the end of the year. Basically constructing a 'xxxx-12-31' with the input date (example in Oracle).
BETWEEN yourDate AND TO_DATE(TO_CHAR(yourDate, 'YYYY') ||'12-31', 'YYYY-MM-DD')

Given Date parameter is considered as Date Time parameter

I'm writing a stored procedure in sql!
I have to get records in the particular date.
I am using this query:
Declare #FromDate datetime
set #FromDate = '06/02/2014'
select * from Table where Date = #FromDate
Actually, in the Database there are 10 records in that date, but it is showing only two records because the #FromDate is taking like this 06/02/2014 00:00:00.000
If I write the query like this it means it works correctly!
select * from Table
where Date between '2014-08-28 00:00:00.000' and '2014-08-28 23:59:59.999'
How to solve this? I need to get all the records in that particular date.
Please help me !
If #FromDate is of data type datetime and Table.Date is also of data type datetime then:
Declare #FromDate datetime = '2014-06-02';
Select Table.Date
From Table
Where Table.Date >= #FromDate And Date < DateAdd(day, 1, Table.Date)
Above, we create an inclusive lower boundary (anything equal to or later than 2014-06-02) and an exclusive upper boundary (anything earlier than 2014-06-03), but with a variable defined just once. So, effectively the query checks 2014-06-02 <= FromDate < 2014-06-03.
If you convert DateTime to Nvarchar your issue would be solved.
Try this query:
Declare #Date datetime='2014-08-28 00:00:00.000'
select * from Table
where CONVERT(nvarchar(20),Date,105) = CONVERT(nvarchar(20),#Date,105)

How to get date difference between two dates in same year with one date is from an input date not from the year

Well this is my case: I have an input date X (dd-mm-yyyy), and I want to count the number of days between it with the year part is changed into current year and today's date in SQL. I t comes with the following condition, after the year is changed temporarily: (Here's my current idea of the logic)
- If date X is earlier than today, then difference = datediff(X,now), with the X year is current year
- If date X is later than today, then difference = datediff(X,now), with the X year is one year before
Sample case:
1st case: The input date is 6-6-1990. Today (automatically generated) is 22-8-2011. Then the difference will be = datediff(6-6-2011,22-08-2011)
2nd case: The input date is 10-10-1990. Today (automatically generated) is 22-8-2011. Then the difference will be = datediff(10-10-2010,22-08-2011)
Any idea how to do this in SQL (in SQL Server)? Or is there any other more simple alternatives for this problem? I'd also like this to be done in the query and not using a stored procedure or function
Sorry if there's already a similar question, I just don't know the exact keyword for this problem :( if there's a question like this previously, feel free to direct me there.
Thanks in advance
Here is the implementation (if I understood the logic you need correctly):
USE YourDbName
GO
CREATE FUNCTION YearPartDiff (#date datetime)
RETURNS int
AS
BEGIN
DECLARE #dateCurrentYear datetime
SET #dateCurrentYear = DATEADD(year, YEAR(GETDATE()) - YEAR(#date), #date)
DECLARE #result int
IF #dateCurrentYear < GETDATE()
SET #result = ABS(DATEDIFF(day, #dateCurrentYear, GETDATE()))
ELSE
SET #result = ABS(DATEDIFF(day, DATEADD(year, -1, #dateCurrentYear), GETDATE()))
RETURN(#result)
END
GO
And the example of usage:
USE YourDbName
GO
DECLARE #someDate datetime
SET #someDate = '2011-06-06'
SELECT dbo.YearPartDiff(#someDate) /*returns 77*/
SET #someDate = '2010-10-10'
SELECT dbo.YearPartDiff(#someDate) /*returns 316*/
Basically, #Andrei's solution, but in a single statement:
SELECT
DayDiff = DATEDIFF(
DAY,
DATEADD(YEAR, CASE WHEN LastOcc > GETDATE() THEN -1 ELSE 0 END, LastOcc),
GETDATE()
)
FROM (
SELECT LastOcc = DATEADD(YEAR, YEAR(GETDATE()) - YEAR(#InputDate), #InputDate)
) s
This seems to do the job
SELECT DATEDIFF(DAY, CONVERT(DATETIME, N'2011-06-06'), CONVERT(DATETIME, N'2011-08-22'))
So the basic syntax is
SELECT DATEDIFF(DAY, CONVERT(DATETIME, N'yyyy-mm-dd'), CONVERT(DATETIME, N'yyyy-mm-dd '))
Alternatively, you can use GETDATE() instead of the string for today's date
I have used "SELECT DATEDIFF( D, "+myDate+", GETDATE())" in my code, on SQL Server 2005. It works for me. The value myDate of course would be the DateTime input value.
you should try this query:
create table #T (inp_date datetime)
insert #T values ('06-06-1990')
insert #T values ('08-22-1990')
insert #T values ('10-10-1990')
--select * from #T
select inp_date, GETDATE(),
CASE
WHEN DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE()),inp_date) <= GETDATE()
THEN DATEDIFF(dd,DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE()),inp_date),GETDATE())
ELSE DATEDIFF(dd,DATEADD(yy,DATEDIFF(yy,inp_date,GETDATE())-1,inp_date),GETDATE())
END
from #T

SQL Stored Procedure to get Date and Time

I wish to create a stored procedure which can retrieve the datetime less than or greater than current sys date.. in my table,startdate and enddate has the value as 'datetime'
How do I get details between startdate and enddate in SQL stored procedure?
thanks in advance
eg:
SELECT *
FROM MyTable
WHERE DATEDIFF ('d',mydatefield ,getdate() ) < 3
gets within 3 days
Considering this table definitionCREATE TABLE [dbo].[Dates](
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NOT NULL
)
I assume that if you pass a date you want to know which rows satisfy the condition: startDate < date < EndDate. If this is the case you can use the query: select *
from Dates
where convert(datetime, '20/12/2010', 103) between StartDate and EndDate;
A stored procedure could look like: ALTER PROCEDURE [dbo].[GetDataWithinRange]
#p_Date datetime
AS
BEGIN
SELECT *
from Dates
where #p_Date between StartDate and EndDate;
END
It sounds like you're trying to filter data in a table based on a date range. If this is the case (I'm having some trouble understanding your question), you'd do something like this:
select *
from MyTable m
where m.Date between #DateFrom and #DateTo
Now, I'm assuming your filtering dates are put into the variables #DateFrom and #DateTo.
There are two things:
1> To get todays date we can write
SET #today_date = GETTDDT();
2> To get Current time we can us ethe following query:
SET #today_time = (SELECT
digits(cast(hour(current time) as decimal(2,0)))||
digits(cast(minute(current time) as decimal(2,0)))||
digits(cast(second(current time) as decimal(2,0)))
FROM sysibm/sysdummy1);