Reducing an extensive Query - sql

I am compiling historical data on work tickets from our db. I am using the last day of the month for the past 12 months. On that date I want to see how many tickets were open (datecreated before or equal to last day of month and dateclose after last day or null). How many of those tickets had been open for more than 30 days as of the last day of the month, and how many tickets were closed during that month.
My query returns 4 values for each of the previous 12 months. I developed a query where I gathered the data for one month at a time and then used Union to get the next month and so forth.
I am now attempting to develop a query which does not need a Union for each month of data collected. Here is a sample month.
Select Convert(Varchar,
DATEADD(day,
-1,
DATEADD(mm, DATEDIFF(m, 0, GETDATE()) - 12, 0)),
101) as [ DateRun ],
t1. [ data1 ],
sum(t2. [ data2 ] + t3. [ data3 ]) as [ Total Open ],
(t1. [ data1 ] + 0.0) /
sum((t2. [ data2 ] + 0.0) + (t3. [ data3 ] + 0.0)) as [ Percent Aged Over 30 Days ]
From (Select count(*) as [ data1 ]
From (Select s.ticketnumber, s.datecreated, s.dateclosed
from mydb2 i
inner join mydb1 s
on i.ticketNumber = s.ticketNumber
Where datediff(dd,
s.dateCreated,
DATEADD(day,
-1,
DATEADD(mm,
DATEDIFF(m, 0, GETDATE()) - 12,
0))) > '30'
AND (s.dateclosed is null OR
s.dateclosed >=
DATEADD(day,
-1,
DATEADD(mm, DATEDIFF(m, 0, GETDATE()) - 12, 0)))
Group by s.ticketNumber, s.datecreated, s.dateclosed) as tb1) as t1,
(Select count(*) as [ data2 ]
From (Select s.ticketnumber, s.datecreated, s.dateclosed
from mydb2 i
inner join mydb1 s
on i.ticketNumber = s.ticketNumber
Where s.datecreated <
DATEADD(day,
-1,
DATEADD(mm, DATEDIFF(m, 0, GETDATE()) - 12, 0))
AND (s.dateclosed is null OR
s.dateclosed >=
DATEADD(day,
-1,
DATEADD(mm, DATEDIFF(m, 0, GETDATE()) - 12, 0)))
Group by s.ticketNumber, s.datecreated, s.dateclosed) as tb2) as t2,
(Select count(*) as [ data3 ]
From (Select s.ticketnumber, s.datecreated, s.dateclosed
from mydb2 i
inner join mydb1 s
on i.ticketNumber = s.ticketNumber
Where s.dateclosed >
DATEADD(day,
-1,
DATEADD(mm, DATEDIFF(m, 0, GETDATE()) - 13, 1))
AND s.dateclosed <
DATEADD(day,
-1,
DATEADD(mm, DATEDIFF(m, 0, GETDATE()) - 12, 0))
Group by s.ticketNumber, s.datecreated, s.dateclosed) as tb3) as t3
Group by t1. [ data1 ]
Through research I was able to get the past 12 months last day with the following code, but I have not been able to update the code above so that I don't need 12 Unions.
Select dateadd(month, 1 + datediff(month, 0, s.datecreated), -1) as [ Date Run ]
from mydb1 s
Where s.datecreated >
DATEADD(day, -1, DATEADD(mm, DATEDIFF(m, 0, GETDATE()) - 12, 0))
and s.datecreated <
DATEADD(day, -1, DATEADD(mm, DATEDIFF(m, 0, GETDATE()), 0))
Group by dateadd(month, 1 + datediff(month, 0, s.datecreated), -1)
Order by 1

You might try generating the months using a CTE, use that as the basis for your query, then run the aggregates as subqueries. In other words, something like this:
with Months( ClosingDate, n ) as
(
select DATEADD(dd, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) as ClosingDate, 1 as n
union all
select DATEADD(dd, -1, DATEADD(mm, -1, DATEADD(dd, 1, ClosingDate))), n + 1
from Months
where n < 12
)
select DATENAME(mm, m.ClosingDate) MonthLabel, DATEADD(dd, 1 - DATEPART(dd, m.ClosingDate), m.ClosingDate) OpeningDate, m.ClosingDate,
ISNULL((select COUNT(*)
from mydb1 s
where s.dateCreated < DATEADD(dd, -29, m.ClosingDate)
and (s.dateClosed is null or s.dateClosed >= DATEADD(dd, 1, m.ClosingDate))
), 0) [Total Open 30+ Days]
from Months m
For clarity I included only one of the aggregates and omitted your joins and grouping.

Related

Subtracting one month from a date but making sure it is the first business day of that month

I need to subtract one month from a date called ArchiveDate but I want the first business day of that month. For example if my ArchiveDate is 9/2/2018 I would like to have 8/1/2019.
This is what I have:
DECLARE #ArchiveDate date = '9/2/2019'
SELECT ArchiveDate = DATEADD(day,
CASE WHEN
DATEPART(weekday, DATEADD(MONTH, -1, #ArchiveDate)) = 1
THEN 1
WHEN DATEPART(weekday, DATEADD(MONTH, -1, #ArchiveDate)) = 7 THEN 2
ELSE 0
END
, DATEADD(MONTH, -1, #ArchiveDate))
What I get from this is 8/2/2019 but as you can see I want 8/1/2019.
SELECT
CASE
WHEN DATENAME(WEEKDAY, DATEADD(mm, DATEDIFF(mm, 0, #ArchiveDate) - 1, 0)) = 'Saturday'
THEN DATEADD(mm, DATEDIFF(mm, 0, #ArchiveDate) - 1, 0) + 2
WHEN DATENAME(WEEKDAY, DATEADD(mm, DATEDIFF(mm, 0, #ArchiveDate) - 1, 0)) = 'Sunday'
THEN DATEADD(mm, DATEDIFF(mm, 0, #ArchiveDate) - 1, 0) + 1
ELSE
DATEADD(mm, DATEDIFF(mm, 0, #ArchiveDate) - 1, 0)
END
This will return the first BUSINESS DAY of the previous month.
you can use eomonth along with your logic to get first day of previous month as below:
DECLARE #ArchiveDate date = '9/2/2019'
select dateadd(day, 1, eomonth(dateadd(month, -2, #ArchiveDate)));
You can use EOMONTH with DATEADD():
SELECT DATEADD(DAY, 1, EOMONTH(#ArchiveDate, -2)) AS ArchiveDate

How to return just the yyyy-mm-dd from the following SQL queries [duplicate]

This question already has answers here:
How to get a date in YYYY-MM-DD format from a TSQL datetime field?
(25 answers)
Closed 4 years ago.
Below are the queries I created. Query #1 returns 2018-07-06 00:00:00.000 and query #2 returns 2018-07-31 23:59:59.997.
I can't figure out how to modify the queries so that they'll return the result in the yyyy-mm-dd format. Please advice.
Query #1 - get fifth business day of the month
SELECT
FifthWeekDay = DATEADD(dd, CASE
WHEN DATEDIFF(dd, -1, ca.FirstOfMonth) % 7 > 1 -- -1 is a Sunday
THEN 7
ELSE 6 - DATEDIFF(dd, -1, ca.FirstOfMonth) % 7 -- -1 is a Sunday
END, ca.FirstOfMonth - 1)
FROM
(SELECT
DATEADD(mm, (SELECT DATEPART(YEAR, GETDATE())) * 12 - 22801 +
(SELECT DATEPART(M, GETDATE())), 0)) ca(FirstOfMonth)
Query #2 - get last business day of the month
SELECT
DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0))
- CASE DATENAME(dw, DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0)))
WHEN 'SUNDAY' THEN 2
WHEN 'SATURDAY' THEN 1
ELSE 0
END AS LastBusinessCurrentMonth
You can subquery the results you already have and add a cast( as date):
SELECT CAST(LastBusinessCurrentMonth AS DATE) AS LastBusinessCurrentMonth FROM(
SELECT
DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0))
- CASE DATENAME(dw, DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0)))
WHEN 'SUNDAY' THEN 2
WHEN 'SATURDAY' THEN 1
ELSE 0
END AS LastBusinessCurrentMonth) AS X
SELECT CAST(FIFTHWEEKDAY AS DATE) AS FIFTHWEEKDAY FROM(
SELECT
FifthWeekDay = DATEADD(dd, CASE
WHEN DATEDIFF(dd, -1, ca.FirstOfMonth) % 7 > 1 -- -1 is a Sunday
THEN 7
ELSE 6 - DATEDIFF(dd, -1, ca.FirstOfMonth) % 7 -- -1 is a Sunday
END, ca.FirstOfMonth - 1)
FROM
(SELECT
DATEADD(mm, (SELECT DATEPART(YEAR, GETDATE())) * 12 - 22801 +
(SELECT DATEPART(M, GETDATE())), 0)) ca(FirstOfMonth)) AS X
Or you could declare a variable as Date and set the results of your queries to that variable :
DECLARE #DATEVAR DATE
SET #DATEVAR =(
SELECT
DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0))
- CASE DATENAME(dw, DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0)))
WHEN 'SUNDAY' THEN 2
WHEN 'SATURDAY' THEN 1
ELSE 0
END AS LastBusinessCurrentMonth)
SELECT #DATEVAR AS LastBusinessCurrentMonth
SET #DATEVAR = (SELECT
DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0))
- CASE DATENAME(dw, DATEADD(ms, -3, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) + 1, 0)))
WHEN 'SUNDAY' THEN 2
WHEN 'SATURDAY' THEN 1
ELSE 0
END AS LastBusinessCurrentMonth)
SELECT #DATEVAR AS LastBusinessCurrentMonth

Incorrect syntax near my alias when joining sub-queries?

My code is provided below. I get the error
"Incorrect syntax near the keyword 'otb'" (line 48)
and
"Incorrect syntax near the keyword 'otb_ly' "
I have no idea what this could mean! Because it makes sense to me to join my two sub-queries (that I've named otb and otb_ly).
On their own the sub-queries work just fine.
declare #snapLY table (hotel_id tinyint, import_date date)
insert into #snapLY select hotel_id, max(import_date) from [UKRMC].[dbo].[block_res]
where import_date <= convert(date, DATEADD(day, 1, DATEADD(year, -1, GETDATE()) ) )
group by hotel_id
select otb.sita,
otb.month_TY,
otb.year_TY,
otb.Market_segment,
otb.rn_TY as OTB_rn_TY,
otb.rev_TY as OTB_rev_TY
--otb_ly.rev_LY as OTB_rev_LY,
--otb_ly.rn_LY as OTB_rn_LY
(
select contacts.sita,
data.hotel_id,
data.month_TY
,data.year_TY
,Market_segment = seg.SEG
,rn_TY = ISNULL(datatwo.rn_TY,0)
,rev_TY = ISNULL(datatwo.rev_TY, 0)
from (
SELECT hotel_id, datename(month, DATEARRIVED) as month_TY, datename(year, DATEARRIVED) year_TY
FROM [UKRMC].[dbo].[revenue] rev
JOIN [UKRMC].[dbo].[contacts] contacts on rev.hotel_id = contacts.ID
WHERE DATEARRIVED BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()), '19000101') -- first day of the month
AND DATEADD(MONTH, 5, DATEADD(DAY,-DAY(DATEADD(MONTH, 1, GETDATE())), DATEADD(MONTH, 1, GETDATE()))) -- 6 months later
and sita not like '%GLARR%'
group by hotel_id, datename(month, DATEARRIVED), datename(year, DATEARRIVED)
) data
cross join (
select SEG
from [UKRMC].[dbo].[Segmentation]
where SEG in ('RAC', 'BIT', 'BIQ', 'CBI', 'TOF', 'QOF', 'BAO', 'FIT', 'LYO', 'RER', 'OTH', 'NRG', 'XXX', 'CRW', 'BGR', 'BGO', 'LGR', 'LGS')
) seg
left join (
SELECT hotel_id, market_segment, datename(month, DATEARRIVED) month_TY, datename(year, DATEARRIVED) year_TY, sum(AMTROOM) as rev_TY, sum(STAYDAYS) as rn_TY
FROM [UKRMC].[dbo].[revenue] revtwo
WHERE DATEARRIVED BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()), '19000101') -- first day of the month
AND DATEADD(MONTH, 5, DATEADD(DAY,-DAY(DATEADD(MONTH, 1, GETDATE())), DATEADD(MONTH, 1, GETDATE()))) -- 6 months later
AND hotel_id != 61 --not GLARR, id taken from contacts table
GROUP BY hotel_id, datename(month, DATEARRIVED), datename(year, DATEARRIVED), market_segment
) datatwo on data.hotel_id = datatwo.hotel_id and seg.SEG = datatwo.market_segment and data.month_TY = datatwo.month_TY and data.year_TY = datatwo.year_TY
join [UKRMC].[dbo].[contacts] contacts on contacts.id = data.hotel_id
) otb
LEFT JOIN
(
SELECT sita, market_seg, month_LY, year_LY, sum(rev_LY) as rev_LY, sum(rn_LY) as rn_LY
FROM (
SELECT block.hotel_id, SITA
,datename(month,stay_date) as month_LY
,datename(year, stay_date) as year_LY
,sum(rev_room) as rev_LY
,sum(quantity) as rn_LY
,market_seg
FROM [UKRMC].[dbo].[block_res] block
JOIN #snapLY spit on block.hotel_id = spit.hotel_id and block.import_date = spit.import_date
JOIN [UKRMC].[dbo].[Contacts] contacts on block.hotel_id = contacts.ID
WHERE stay_date >= DATEADD(year, -1, DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()), '19000101'))
--stay_date >= DATEADD(year, -1, getdate())
and stay_date <= DATEADD(year, -1, DATEADD(MONTH, 5, DATEADD(DAY,-DAY(DATEADD(MONTH, 1, GETDATE())), DATEADD(MONTH, 1, GETDATE()))))
group by sita, market_seg, block.hotel_id, datename(month,stay_date),datename(year, stay_date)
UNION ALL
SELECT revenue.HOTEL_ID, SITA
,datename(month,DATEARRIVED) as month_LY
,datename(year,DATEARRIVED) as year_LY
,sum(AMTROOM) as rev_LY
,sum(STAYDAYS) as rn_LY
,market_segment
FROM [UKRMC].[dbo].[revenue] revenue
JOIN [UKRMC].[dbo].[Contacts] contacts on revenue.HOTEL_ID = contacts.ID
JOIN #snapLY spit on revenue.HOTEL_ID = spit.hotel_id
WHERE DATEARRIVED between DATEADD(year, -1, DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()), '19000101'))
and DATEADD(day, -1, DATEADD(year, -1, getdate()))
and DATEARRIVED < spit.import_date
GROUP BY sita, revenue.HOTEL_ID, datename(month,DATEARRIVED), datename(year,DATEARRIVED), market_segment
) union_LY
GROUP BY sita, market_seg, hotel_id, month_LY, year_LY
) otb_ly
on otb.sita = otb_ly.sita and otb.Market_segment = otb_ly.market_seg and otb.month_LY = otb_ly.month_LY and otb.year_LY = otb_ly.year_LY
You're missing a FROM on Line 14:
...
--otb_ly.rn_LY as OTB_rn_LY
FROM
(
...
That query, in all honestly, needs a massive rework... That is really difficult to read.

SQL setting start date to Friday, and read Data between 2 dates

I'm trying to set the start date to friday on a sql query. Which I have done as you can see below. What I need to do now is show all the GameID's between Friday and Saturday, and it refreshes every week (so that every week it shows other games that have been played in that week).
I'm a complete beginner at SQL so any help is greatly appreciated!
I have tried the sql query below.
DECLARE #StartFriday datetime
DECLARE #EndSaturday datetime
SET DATEFIRST 6 -- Set the start of the week to Friday
SELECT *
FROM
(
SELECT GameDate,
DATEADD(w, 0, DATEADD(w, DATEDIFF(w, 0,GETDATE()), -5)) AS 'StartFriday',
DATEADD(w, 0, DATEADD(w, DATEDIFF(w, 0,GETDATE()), 1)) AS 'EndSaturday'
FROM VW_Resultaat_Score
WHERE GameDate BETWEEN 'StartFriday' AND 'EndSaturday' --Show all GameDates between #StartFriday and #EndSaturday
)
I would love any help I can get!
Cheers
Perhaps this will work better:
DECLARE #StartFriday datetime
DECLARE #EndSaturday datetime
SET DATEFIRST 6
Set #StartFriday = DATEADD(w, 0, DATEADD(w, DATEDIFF(w, 0,GETDATE()), -5))
Set #EndSaturday = DATEADD(w, 0, DATEADD(w, DATEDIFF(w, 0,GETDATE()), 1))
SELECT *
FROM
(
SELECT GameDate
FROM VW_Resultaat_Score
WHERE GameDate BETWEEN #StartFriday AND #EndSaturday
)
If you will only ever need the weekend previous, this code will work:
SELECT *
FROM VW_Resultaat_Score
WHERE GameDate BETWEEN
(SELECT DATEADD(d, 1 - datepart(weekday, dateadd(d, 2, getdate())), getdate()))
AND
(SELECT DATEADD(d, 1 - datepart(weekday, dateadd(d, 1, getdate())), getdate()))
Code looks a little crazy, but it works. If you may need to query other specific weekends, this may be an option:
DECLARE #getdate date
SET #getdate='2017-05-16'
SELECT *
FROM VW_Resultaat_Score
WHERE GameDate BETWEEN
(SELECT DATEADD(d, 1 - datepart(weekday, dateadd(d, 2, #getdate)), #getdate))
AND
(SELECT DATEADD(d, 1 - datepart(weekday, dateadd(d, 1, #getdate)), #getdate))
Taking it a step further, you may need to report on each of these weekends. The following code gives you all the Friday Saturdays of each week for 2017.
WITH Fri as
(SELECT DATEPART(YEAR,DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), n.num)) yyyy, DATEPART(wk,DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), n.num)) weeknumber, Fridays = CAST(DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), n.num) as Date)
FROM (SELECT TOP 366 num = ROW_NUMBER() OVER(ORDER BY a.NAME)-1 FROM dbo.syscolumns a, dbo.syscolumns b) n
WHERE DATENAME(weekday, DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), n.num)) = 'Friday')
,
Sat as
(SELECT weeknumber=DATEPART(wk,DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), n.num)), Saturdays = CAST(DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), n.num) as Date)
FROM (SELECT TOP 366 num = ROW_NUMBER() OVER(ORDER BY a.NAME)-1 FROM dbo.syscolumns a, dbo.syscolumns b) n
WHERE DATENAME(weekday, DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), n.num)) = 'Saturday')
Select Fri.weeknumber, fri.yyyy, Fridays, Saturdays
FROM Fri
JOIN Sat on Fri.weeknumber=Sat.weeknumber

MS SQL Convert date to short

I am trying to get all of the records from a table where the ExpiryDate field is exactly one month away.
The problem however is that the ExpiryDate is stored with the hours, minutes and seconds. How do I therefore say - Get me all of the records from my table where the ExpiryDate (dd/MM/yyyy) is one month ahead of now (dd/MM/yyyy).
This is what I have currently:
SELECT * FROM dbo.Custom_MembershipTransaction mt (nolock)
WHERE mt.ExpiryDate = DATEADD(MONTH, 1, GETDATE())
AND mt.IsComplete = 1;
You need some buffertime like
SELECT * FROM dbo.Custom_MembershipTransaction mt (nolock)
WHERE mt.ExpiryDate < DATEADD(MONTH, 1, GETDATE())
AND mt.ExpiryDate > DATEADD(DAY, -1, DATEADD(MONTH, 1, GETDATE()))
AND mt.IsComplete = 1;
This will get you all recors that have an expiredate between 1 month ahead an (1 month - 1 day) ahead.
SELECT * FROM dbo.Custom_MembershipTransaction mt (nolock)
WHERE mt.ExpiryDate >= DATEADD(DAY, DATEDIFF(DAY, 0, DATEADD(MONTH, 1, GETDATE())), 0)
AND mt.ExpiryDate < DATEADD(DAY, DATEDIFF(DAY, 0, DATEADD(MONTH, 1, GETDATE()) + 1), 0)
AND mt.IsComplete = 1;
I didn't make operation on ExpiryDate as it might be used by an index
Try this:
SELECT * FROM dbo.Custom_MembershipTransaction mt (nolock)
WHERE convert(varchar, mt.ExpiryDate, 102) = convert(varchar, DATEADD(MONTH, 1, GETDATE()),102)
AND mt.IsComplete = 1;