How to write this SQL Server query in Teradata SQL? - sql-server

We are migrating the data from SQL Server to Teradata and I am unable to replicate the same code from SQL Server to Teradata.
Description: I want to generate report between the dates received from the Rstart and Rend, which is basically 6 month duration (1. jan to jun & 2. jul to dec ). For this, I need to store the dates in two variables (Rstart,Rend) and inorder to fetch records between those two dates
SQL Server code
DECLARE #REnd Date;
DECLARE #RStart Date;
SET #REnd = (SELECT MAX(CalendarDate) AS #REnd
FROM Table1
WHERE CalendarDate = MonthEndDate
AND Monthofyear IN ('June', 'December')
AND CalendarDate < CURRENT_DATE());
SET #RStart = (SELECT MAX(CalendarDate) AS #RStart
FROM Table1
WHERE CalendarDate = (CalendarDate - Extract(Day From CalendarDate) + 1)
AND Monthofyear IN ('January', 'July')
AND CalendarDate < #REnd);
SELECT *
FROM Table2
WHERE ReviewDate BETWEEN #REnd AND #RStart;
This is what I have tried in Teradata:
Create Procedure Demo()
Begin
Declare REnd Date;
Declare RStart Date;
Set REnd = (select max(CalendarDate) as REnd
from Table1
where CalendarDate = MonthEndDate
and Monthofyear in ('June', 'December')
and CalendarDate < Current_date()
);
Set RStart = (select max(CalendarDate) as RStart
from Table1
where CalendarDate = (CalendarDate - Extract(Day From CalendarDate)+1)
and Monthofyear in ('January', 'July')
and CalendarDate < REnd
);
Call dbc.sysexecsql(('select * from table 2 where reviewdate between' ||REnd|| 'and' ||RStart|| ');');
End;

Assuming Table1 is a calendar table and you just want to return the previous half-year:
SELECT *
FROM Table2 -- first day of Jan/Jul
WHERE ReviewDate BETWEEN Trunc(Add_Months(Current_Date, -6 -(Extract(MONTH From Current_Date) -1) MOD 6), 'mon')
-- end of Jun/Dec
AND Last_Day(Add_Months(Current_Date, -1 -(Extract(MONTH From Current_Date) -1) MOD 6))

Related

Get dates between date of ID and date of plus or minus days

I have the following sample data:
CREATE TABLE tblDates
(
ID int,
Dates DATE
);
SELECT * FROM tblDates
INSERT INTO tblDates VALUES(1,'2019-12-01');
INSERT INTO tblDates VALUES(2,'2019-12-05');
INSERT INTO tblDates VALUES(3,'2019-12-02');
INSERT INTO tblDates VALUES(4,'2019-12-09');
INSERT INTO tblDates VALUES(5,'2019-12-11');
Here I am looking for dates between date of ID = 4 and plus or minus of days 1,2,....n days.
Try 1: I tried using UNION ALL.
SELECT Dates FROM tblDates WHERE ID = 4
UNION ALL
SELECT DATEADD(day,1,Dates) FROM tblDates WHERE ID = 4;
This approach is not good for when I am looking for 50 or more number of days difference.
Try 2:
SELECT Dates FROM tblDates WHERE ID = 4 AND Dates between Dates AND DATEADD(day,1,Dates);
Got single date.
Try 3:
Created function: function for get dates
CREATE FUNCTION udf_GetDates(#MinDate DATE,#MaxDate DATE)
RETURNS TABLE
AS
RETURN
SELECT TOP (DATEDIFF(DAY, #MinDate, #MaxDate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #MinDate)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b;
Query:
SELECT f.*
FROM udf_GetDates(t.Dates,DATEADD(day,1,t.Dates)) f
INNER JOIN tblDates t ON f.[Date] = t.[Dates]
WHERE t.ID = 4
Got an error:
Msg 4104, Level 16, State 1, Line 2 The multi-part identifier
"t.Dates" could not be bound. Msg 4104, Level 16, State 1, Line 2 The
multi-part identifier "t.Dates" could not be bound.
Expected Output:
Given: ID = 4 and day=+1
Dates
-----------
2019-12-09
2019-12-10
Given: ID = 4 and day=+10
Dates
-----------
2019-12-09
2019-12-10
2019-12-11
2019-12-12
2019-12-13
2019-12-14
2019-12-15
2019-12-16
2019-12-17
2019-12-18
Given: ID = 4 and day=-5
Dates
----------
2019-12-05
2019-12-06
2019-12-07
2019-12-08
2019-12-09
Try this query
FIDDLE DEMO
Function
CREATE FUNCTION udf_GetDates (#StartDate DATE, #Range INT)
RETURNS TABLE
AS
RETURN
SELECT
DATEADD(DAY, nbr - 1, #StartDate) myDate
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY c.object_id) AS Nbr
FROM
sys.columns c) nbrs
WHERE
nbr - 1 <= #Range
Query usage #1:
SELECT f.myDate
FROM udf_GetDates((SELECT dates FROM tblDates WHERE ID = 4), 2) f
Query usage #2:
SELECT t.*, P.*
FROM tblDates t
OUTER APPLY udf_GetDates(t.Dates, 5) p
WHERE t.ID = 4
Updated answer:
Next Dates
CREATE FUNCTION udf_GetDates (#StartDate DATE, #Range INT)
RETURNS TABLE
AS
RETURN
SELECT
DATEADD(DAY, nbr - 1, #StartDate) myDate
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY c.object_id) AS Nbr
FROM
sys.columns c) nbrs
WHERE
nbr - 1 <= #Range
Previous Dates
CREATE FUNCTION [udf_GetDates_Minuus] (#StartDate DATE, #Range INT)
RETURNS TABLE
AS
RETURN
SELECT
DATEADD(DAY, -(nbr - 1), #StartDate) myDate
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY c.object_id) AS Nbr
FROM
sys.columns c) nbrs
WHERE
nbr - 1 <= #Range
Next and previous dates in single function
CREATE FUNCTION udf_GetDatesNextandPrevious(#StartDate DATE, #Range INT)
RETURNS TABLE
AS
RETURN
SELECT
DATEADD(DAY, nbr - 1, #StartDate) myDate
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY c.object_id) AS Nbr
FROM
sys.columns c) nbrs
WHERE
nbr - 1 <= #Range
UNION
SELECT
DATEADD(DAY, -(nbr - 1), #StartDate) myDate
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY c.object_id) AS Nbr
FROM
sys.columns c) nbrs
WHERE
nbr - 1 <= #Range
Updated Fiddle
Try this code in sql server
DECLARE #selecteddate DATE
DECLARE #day INT = 10
DECLARE #id INT = 4;
DECLARE #count INT = 0;
DECLARE #table1 TABLE
(
date_ DATETIME
)
SELECT #selecteddate = dates
FROM tbldates
WHERE id = #id;
IF( #count <= #day )
BEGIN
if(#day > 1)
begin
set #day = #day - 1
end
WHILE #count <= #day
BEGIN
INSERT INTO #table1
VALUES (Dateadd(day, #count, #selecteddate))
SET #count = #count + 1
END
END
ELSE
BEGIN
WHILE #count > #day
BEGIN
INSERT INTO #table1
VALUES (Dateadd(day, #count, #selecteddate))
SET #count = #count - 1
END
END
SELECT *
FROM #table1
ORDER BY 1
I tried to create function using another format
create FUNCTION udf_GetDates(#MinDate DATE,#MaxDate DATE)
RETURNS #_result table (dt date)
AS
begin
insert into #_result
SELECT TOP (DATEDIFF(DAY, #MinDate, #MaxDate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #MinDate)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b;
return
end
and select the result like this
declare #_date date=(select Dates from tblDates where ID=4)
select *
from udf_GetDates(#_date,DATEADD(day,1,#_date))
and I got the result what you wanted
dt
2019-12-09
2019-12-10
This SQL will return the correct dates between two ranges. Just adapt it to suite your needs.
DECLARE #From DATETIME,
#To DATETIME
SELECT #From = '2019-11-13',
#To = '2019-11-19'
;WITH Numbers AS
(
SELECT 0 AS Number
UNION ALL
SELECT Number + 1 AS Number
FROM Numbers
WHERE Number < DATEDIFF(d, #From, #To)
)
SELECT DATEADD(d,
Number, #From) AS Date
FROM Numbers
-- Results
2019-11-13 00:00:00.000
2019-11-14 00:00:00.000
2019-11-15 00:00:00.000
2019-11-16 00:00:00.000
2019-11-17 00:00:00.000
2019-11-18 00:00:00.000
2019-11-19 00:00:00.000

SSRS 2017 Cascading parameters with dates

I have a parameter called Year and you can choose one year at a time. I have a date/time parameter with a calendar called start date and another one called end date.
I would like it to work such that if I pick the year to be 2017 it will show the calendar start and end dates for 2017.
Since my start date and end date parameters are not defaulted from a dataset I am not sure how to control that.
Any help will be appreciated.
You can do it as an expression, but as its easier in SQL you can just create a second dataset with the following:
select convert(date, '1 jan ' + convert(varchar(4), #Year)), dateadd(day, -1, dateadd(year, 1, convert(date, '1 jan ' + convert(varchar(4), #Year))))
I used a recursive CTE common table expression that references itself to solve this. Then you can set the Dataset of the start_date and end_date parameters.
Dataset for the default values of the start and end date parameters
DECLARE #year AS INT
SET #year = 2018
SELECT [start_date] = DATEFROMPARTS(#year, 1, 1), [end_date] = DATEFROMPARTS(#year, 12, 31)
Dataset for the available values of the start and end date parameters
DECLARE #year AS INT
SET #year = 2018
;WITH
source_data_dates
AS
(
SELECT
[date_start] = DATEFROMPARTS(#year, 1, 1)
, [date_end] = DATEFROMPARTS(#year, 12, 31)
)
,
year_date_list([rn], [date_value])
AS
(
SELECT
[rn] = 1
, [date_value] = CAST([date_start] AS DATETIME)
FROM
source_data_dates
UNION ALL
SELECT
[rn] = [rn] + 1
, [date_start] = CAST(DATEADD(DAY, [rn], [date_start]) AS DATETIME)
FROM
year_date_list
, source_data_dates
WHERE
[rn] <= DATEDIFF(DAY, [date_start], [date_end])
)
SELECT
[rn]
, [date_value]
FROM
year_date_list
OPTION (MAXRECURSION 0)
Results:

TSQL get last day of previous months upto a specified month

I need to get last day of all previous months including current month, upto a specified month. For example, I need last days of september, aug, july, june, may, april, march, feb, jan, dec 2015 like so:
temptable_mytable:
last_day_of_month
-----------------
2016-09-30
2016-08-31
2016-07-31
2016-06-30
2016-05-31
2016-04-30
2016-03-31
2016-02-30
2016-01-31
2015-12-31
I need to specify the month and year to go back to - in above case it's December 2015, but it could also be September 2015 and such. Is there a way that I can do a loop and do this instead of having to calculate separately for each month end?
Use a recursive CTE with the EOMONTH function.
DECLARE #startdate DATE = '2016-01-01'
;WITH CTE
AS
(
SELECT EOMONTH(GETDATE()) as 'Dates'
UNION ALL
SELECT EOMONTH(DATEADD(MONTH, -1, [Dates]))
FROM CTE WHERE Dates > DATEADD(MONTH, 1, #startdate)
)
SELECT * FROM CTE
with temp as (select -1 i union all
select i+1 i from temp where i < 8)
select DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+i*-1,0)) from temp
declare #LASTMONTH date = '2018-10-01';
WITH MTHS AS (
SELECT dateadd(month,month(getdate()),dateadd(year,year(getdate()) - 1900, 0)) aday
UNION ALL
SELECT DATEADD(month,1,aday) from MTHS WHERE aday <= #LASTMONTH
),
LASTDAYS AS (SELECT DATEADD(day,-1,aday) finaldayofmonth from MTHS)
select * from LASTDAYS
Here is a version that goes forward or backwards as appropriate
declare #LASTMONTH date = '2013-10-01';
WITH DIF AS (SELECT CASE WHEN
YEAR(#LASTMONTH) * 12 + MONTH(#LASTMONTH)
>= YEAR(GETDATE()) * 12 + MONTH(getdate()) THEN 1 ELSE -1 END x),
MTHS AS (
SELECT dateadd(month,month(getdate()),dateadd(year,year(getdate()) - 1900, 0)) aday
UNION ALL
SELECT DATEADD(month,(SELECT X from dif),aday) from MTHS
WHERE month(aday) != month(dateadd(month,1,#LASTMONTH)) or YEAR(aday) != YEAR(dateadd(month,1,#LASTMONTH))
),
LASTDAYS AS (SELECT DATEADD(day,-1,aday) finaldayofmonth from MTHS)
select * from LASTDAYS order by finaldayofmonth
Here's one approach, using a CTE to generate a list of incrementing numbers to allow us to then have something to select from and use in a DATEADD to go back for the appropriate number of months.
Typically, if you're doing this quite frequently, instead of generating numbers on the fly like this with the CROSS JOIN, I'd recommend just creating a "Numbers" table that just holds numbers from 1 to "some number high enough to meet your needs"
DECLARE #Date DATE = '20151201'
DECLARE #MonthsBackToGo INTEGER
SELECT #MonthsBackToGo = DATEDIFF(mm, #Date, GETDATE()) + 1;
WITH _Numbers AS
(
SELECT TOP (#MonthsBackToGo) ROW_NUMBER() OVER (ORDER BY o.object_id) AS Number
FROM sys.objects o
CROSS JOIN sys.objects o2
)
SELECT EOMONTH(DATEADD(mm, -(Number- 1), GETDATE())) AS last_day_of_month
FROM _Numbers
This should scale out no matter how far you go back or forward for your originating table or object.
SET NOCOUNT ON;
DECLARE #Dates TABLE ( dt DATE)
DECLARE #Start DATE = DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)
DECLARE #End DATE = DATEADD(YEAR, 1, #Start)
WHILE #Start <= #End
BEGIN
INSERT INTO #Dates (dt) VALUES (#Start)
SELECT #Start = DATEADD(DAY, 1, #Start)
END
; With x as
(
Select
dt
, ROW_NUMBER() OVER(PARTITION BY DATEPART(YEAR, Dt), DATEPART(MONTH, Dt) ORDER BY Dt Desc) AS rwn
From #Dates
)
Select *
From x
WHERE rwn = 1
ORDER BY Dt
This was cribbed together quick based on a couple different SO answers for the parts:
DECLARE #startdate datetime, #enddate datetime
set #startdate = '2015-12-01'
set #enddate = getdate()
;WITH T(date)
AS
(
SELECT #startdate
UNION ALL
SELECT DateAdd(day,1,T.date) FROM T WHERE T.date < #enddate
)
SELECT DISTINCT
DATEADD(
day,
-1,
CAST(CAST(YEAR(date) AS varchar) + '-' + CAST(MONTH(date)AS varchar) + '-01' AS DATETIME))
FROM T OPTION (MAXRECURSION 32767);

TSQL Substract from report parameter to get previous month

I can really use some help. I'm trying to subtract 1 from a VARCHAR report parameter that is within a CTE. I'm working in SQL 2008 R2
This works fine:
AND MONTH(CAST(c.DATETIME AS DATE)) = CONVERT(INT,#Maand)
But this just doesn't seem to work:
AND MONTH(CAST(c.DATETIME AS DATE)) = CONVERT(INT,#Maand) -1
Thanks
Here is some of my code:
ALTER PROCEDURE [rpt].[usp_F_Telefonie_Bereikbaarheid](#Jaar AS VARCHAR(4), #Maand AS VARCHAR(2))
AS
BEGIN
WITH CTE AS(
SELECT
C.DATETIME AS Datum
,d.NAME
,COUNT(Callid) AS Aantal
,'Vorige' AS Gesprekken
,DURATIONSEC
FROM DM.dm.F_CDRS AS c
JOIN DM.dm.D_DEPARTMENTS AS d
ON d.DEPARTMENTID = c.DEPARTMENTID
WHERE Direction = 1
AND YEAR(CAST(c.DATETIME AS DATE)) = #Jaar
AND MONTH(CAST(c.DATETIME AS DATE))= CONVERT(INT,#Maand)
AND WAITTIMESEC <=10
GROUP BY LEFT(D.NAME, 2), D.NAME, C.DATETIME, DURATIONSEC
)
SELECT
,CASE CTE.Gesprekken
WHEN 'Vorige'
THEN SUM(CTE.Aantal)
END AS Vorige
FROM CTE
WHERE MONTH(CAST(CTE.Datum AS DATE)) = #Maand
AND YEAR(CAST(CTE.Datum AS DATE)) = #Jaar
GROUP BY CTE.NAME, CTE.Gesprekken, CTE.DURATIONSEC, CTE.Aantal
You need to convert varchar --> datetime and then use datediff function.
Instead this:
YEAR(CAST(c.DATETIME AS DATE)) = #Jaar
AND MONTH(CAST(c.DATETIME AS DATE))= CONVERT(INT,#Maand)
use:
datediff(month, cast(#Jaar + right('0' + #Maand, 2) + '01' as datetime), c.[datetime]) = 1

How to insert all dates in 2015 in Date field?

I am using SQL Server and have a table (Table_Date) with a 'date' field. I want to insert all 2015 dates in this field.
It should have 365 distinct rows, 1 row for each day of 2015.
One method is with a recursive CTE:
with dates as (
select cast('2015-01-01' as date) as thedate
union all
select dateadd(day, 1, thedate)
from dates
where thedate < '2015-12-31'
)
select *
from dates
option (maxrecursion 0);
An alternative is to use a table that has at least 365 rows. master..spt_values is often used for this purpose:
select dateadd(day, seqnum - 1, '2015-01-01')
from (select row_number() over (order by ()) as seqnum
from master..spt_values
) t
where seqnum <= 365;
Here's one way:
CREATE TABLE #nums(num INT);
INSERT INTO #nums VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
WITH cteDays AS
(
SELECT 100*d100.num + 10*d10.num + d1.num AS YearDay
FROM #nums AS d1
CROSS JOIN #nums AS d10
CROSS JOIN #nums AS d100
WHERE d100.num <=3
)
SELECT CAST('2015-01-01' AS DATETIME) + YearDay AS YearDate
FROM cteDays
WHERE YEAR(CAST( CAST('2015-01-01' AS DATETIME) + YearDay AS DATETIME)) = 2015
Something like this could work as well:
declare #count int = 0
while (#count < 365)
begin
--make this the insert
select DATEADD(DD, #count, getdate())
set #count = #count + 1
end
Not sure what context this will applied to though... This is very basic, but if this is a one-time event it won't matter.

Resources