Merging two SELECT queries with same date fields - sql

I have a table of Tasks where I have records for a particular date. I want to have all dates in one month displayed with numbers of tasks per date. If on some date there were no record of a task it should be written 0.
I have results with duplicating records from the same date when there were tasks on a given day.
Table:
Date Tasks
2021-08-01 0
2021-08-02 0
2021-08-03 0
2021-08-03 25
2021-08-04 0
2021-08-04 18
2021-08-05 0
2021-08-05 31
2021-08-06 0
SQL code I am using:
Declare #year int = 2021, #month int = 8;
WITH numbers
as
(
Select 1 as value
UNion ALL
Select value +1 from numbers
where value + 1 <= Day(EOMONTH(datefromparts(#year, #month, 1)))
)
SELECT datefromparts(#year, #month, numbers.value) AS 'Datum', 0 AS 'Tasks' FROM numbers
UNION
SELECT CONVERT(date, added_d) AS 'Datum', COUNT(*) AS 'Tasks' FROM Crm.Task
WHERE YEAR(added_d) = '2021' AND MONTH(added_d) = '8' GROUP BY CONVERT(date, added_d)
How can I remove duplicates that I will have only one date record 21-08-03 with 25 tasks?
Thank you for your help

You requires OUTER JOIN :
WITH numbers as (
Select datefromparts(#year, #month, 1) as value
UNION ALL
Select DATEADD(DAY, 1, value) as value
from numbers
where value < EOMONTH(value)
)
select num.value, COUNT(tsk.added_d) AS Tasks
from numbers num left join
Crm.Task tsk
on CONVERT(date, tsk.added_d) = num.value
GROUP BY num.value;

If you want all dates for one month, you can do:
with dates as (
select datefromparts(#year, #month, 1) as dte
union all
select dateadd(day, 1, dte)
from dates
where dte < eomonth(dte)
)
You can then incorporate this into the logic using an outer join or subquery:
with dates as (
select datefromparts(#year, #month, 1) as dte
union all
select dateadd(day, 1, dte)
from dates
where dte < eomonth(dte)
)
select d.dte, count(t.added_d)
from dates d left join
Crm.Task t
on convert(date, t.added_d) = d.dte
group by d.dte
order by d.dte;
You can easily extend the logic for the CTE for more than one month, by adjusting the where clause in the second clause.

Related

SQL Server for last 12 months with begin_date and end_date

I'm having trouble to display the last 12 months for each record, can anyone help?
Right now I can only display one month for each record.
DECLARE #DateEnd as DATETIME = DATEADD(month,((YEAR(getdate())-1900)*12) + MONTH(getdate())-1,-1)
-- SET #DateEnd = '20191130'
DECLARE #Frequency_List table (FREQUENCY_ID char(3)); INSERT into #Frequency_List values ('118') -- ('111'),('118'),('110') -- 'MTD','QTD','YTD'
DECLARE #Entity_List table (ENTITY_NAME char(50)); INSERT into #Entity_List values
('F1000'),('R2202'),('R528'),('R810'),('R567'),('R402I'),('R508'),('F1000'),('A950A'),('R557'),('R559'),('R560'),('TBNOBL'),('ALTACORP'),('R590RVME'),('Z490'),('R5070'),('R591'),('R710')
select P.PORTF_CODE, F.EXT_NAME, REPLACE(CONVERT(VARCHAR(10), AKRE.BEGIN_DATE, 102), '.', '-') as 'BEGIN_DATE', REPLACE(CONVERT(VARCHAR(10), AKRE.END_DATE, 102), '.', '-') as 'END_DATE',
ISNULL(AKRE.PTF_END_OAD,0) 'PTF End Duration', ISNULL(AKRE.BMK_END_OAD,0) 'BMK End Duration', (ISNULL(AKRE.PTF_END_OAD,0)-ISNULL(AKRE.BMK_END_OAD,0)) 'Diff End Duration',
ISNULL(AKRE.PTF_END_OAS,0)*10000 'PTF End Spread', ISNULL(AKRE.BMK_END_OAS,0)*10000 'BMK End Spread', (ISNULL(AKRE.PTF_END_OAS,0)-ISNULL(AKRE.BMK_END_OAS,0))*10000 'Diff End Spread',
((ISNULL(AKRE.PTF_END_OAD,0)*(ISNULL(AKRE.PTF_END_OAS,0)*10000))-(ISNULL(AKRE.BMK_END_OAD,0)*(ISNULL(AKRE.BMK_END_OAS,0)*10000))) 'DIF_END_DTS'
from BISAMDW..ATTX_KEY_RATES_EFFECTS AKRE
left join BISAMDW..PORTFOLIO P on P.PORTF_ID = AKRE.PORTF_ID
left join BISAMDW..ATTR_INSTRUMENT AI on AI.ATINS_ID = AKRE.ATINS_ID
left join [BISAMDW].[dbo].[UD_GROUP] GRP on AKRE.USER_DEFINED_GROUP_ID=GRP.USER_DEFINED_GROUP_ID
left join BISAMDW..T_FREQUENCY F on F.FREQUENCY_ID = AKRE.FREQUENCY_ID
where AKRE.END_DATE = #DateEnd and P.PORTF_NAME in ( select ENTITY_NAME from #Entity_List)
and AKRE.PORTF_CONFIG_ID in ( 1 )
and AKRE.FREQUENCY_ID in (select FREQUENCY_ID from #Frequency_List)
and AKRE.PTF_RETURN is NOT null
and GRP.EXT_CODE in ('BARCLAYS','MASTER_2016')
order by 1,2
The result for the columns of start month and end month in sample resultshould be something like this:
MonthStartDate MonthEndDate
2011-04-01 2011-04-30
2011-05-01 2011-05-31
2011-06-01 2011-06-30
2011-07-01 2011-07-31
2011-08-01 2011-08-31
2011-09-01 2011-09-30
2011-10-01 2011-10-31
2011-11-01 2011-11-30
2011-12-01 2011-12-31
....
Thank you!
If what you want is generate a list of month starts and ends for the last 12 months (plus the current month), then one option is to use a recursive query:
with cte as (
select
dateadd(
year,
-1,
datefromparts(year(getdate()), month(getdate()), 1)
) monthStartDate
union all
select dateadd(month, 1, monthStartDate)
where monthStartDate < dateadd(month, -1, getdate())
)
select monthStartDate, eomonth(monthStartDate) monthEndDate from cte
If you are going to use this data several times, then you should store the results of this query in a separate table, which you can then use directly in your queries. This is called a calendar table.
Personally, I would suggest creating a Calendar Table (there are 100's of examples on how to create these), if you simply need the start and end dates of each month. Then getting the start and end dates from that table is trivial:
SELECT MIN(C.CalendarDate) AS MonthStart,
MAX(C.CalendarDate) AS MonthEnd
FROM dbo.Calendar C
WHERE C.CalendarDate >= '20110101'
AND C.CalendarDate < '20200601'
GROUP BY C.CalendarYear,
C.CalendarMonth;
Alternatively, you can use a Tally to generate these on the fly:
DECLARE #StartDate date = '20110101',
#EndDate date = '20200601';
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (SELECT DATEDIFF(MONTH, #StartDate, #EndDate)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
FROM N N1, N N2, N N3, N N4, N N5)
SELECT DATEADD(MONTH, T.I, #StartDate) AS MonthStart,
EOMONTH(DATEADD(MONTH, T.I, #StartDate)) AS MonthEnd
FROM Tally T;

get 5th previous date from current date through SQL except public holiday

i need a sql function which has to return 5th previous business date except saturday sunday and public holiday,
Ex: i should get last thursday (04-01-2018) if i won't have any public holiday inbetween im able to achieve that by,
SELECT DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 5, GETDATE()))
but how to omit public holiday from this,
Can anyone help me please
If you don't want (or you can't) create a calendar "tally" table (with columns identifying holidays and week-end days) you can try a query like following one.
sample data for holidays table
CREATE TABLE HOL_TAB (DAT DATETIME);
INSERT INTO HOL_TAB VALUES ('2018-01-05');
INSERT INTO HOL_TAB VALUES ('2018-01-04');
The query use a CTE to "create" on the fly a small tally calendar table (I used 12 as limit, but you can change it).
The last SELECT use a join with holiday table to exclude those days and then ROW_NUMBER() to extract "first" five days.
To keep query similar to the one you made I used DATENAME, but I suggest to avoid its use and use instead other methods).
WITH CAL_TAB AS (
SELECT DATEADD(dd, 0, CAST(GETDATE() AS DATE) ) AS DAT
, 1 AS COUN
UNION ALL
SELECT DATEADD(dd, -1- CASE DATENAME (WEEKDAY, DATEADD(dd,-1,B.DAT) ) WHEN 'Sunday' THEN 2 WHEN 'Saturday' THEN 1 ELSE 0 END, B.DAT ) AS DAT
, B.COUN+1 AS COUN
FROM CAL_TAB B
WHERE B.COUN<12 /* 12 is just to limit number of days */
)
SELECT DAT, WD
FROM (SELECT C.DAT, C.COUN, DATENAME(WEEKDAY, C.DAT) AS WD, ROW_NUMBER() OVER (ORDER BY COUN) AS RN
FROM CAL_TAB C
WHERE NOT EXISTS(SELECT DAT FROM HOL_TAB D WHERE D.DAT=C.DAT)
) E WHERE RN<=5;
Output:
DAT WD
1 10.01.2018 00:00:00 Wednesday
2 09.01.2018 00:00:00 Tuesday
3 08.01.2018 00:00:00 Monday
4 03.01.2018 00:00:00 Wednesday
5 02.01.2018 00:00:00 Tuesday
try This Logic
WITH CTE
AS
(
SELECT
MyDate = DATEADD(DD,-5,GETDATE())
)
SELECT
MyDate = CASE WHEN DATENAME(WEEKDAY, MyDate) IN ('Sunday','Saturday')
THEN NULL
WHEN MHL.Holiday IS NOT NULL
THEN NULL
ELSE CTE.MyDate END
FROM CTE
LEFT JOIN MyHoliDayList MHL
ON CTE.MyDate = MHL.Holiday
Try this Method:
DECLARE #Holiday TABLE(HoliDay DATE)
INSERT INTO #Holiday VALUES ('2018-01-02')
INSERT INTO #Holiday VALUES ('2018-01-05')
DECLARE #WithOutHoliDay DATETIME = (SELECT DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 5, GETDATE())))
SELECT DATEADD(DAY,0-
(SELECT COUNT(1)
FROM #Holiday
WHERE HoliDay BETWEEN #WithOutHoliDay AND GETDATE()),#WithOutHoliDay)
This should give, what exactly you need...

How can I select the 1st of every month for the last 5 years in sql?

I am trying to get a list of the 1st of the Month for the last 5 years. How can i do that ?? I have a select statement:
select convert(varchar(10), dateadd(mm,Datediff(mm,0,getdate()),0),111) as StartDate
but i am not sure how to get a list for every month.
with dates
as (
select dateadd(month, datediff(month, 0, getdate()), 0) as date
union all
select dateadd(month, - 1, date)
from dates
)
select top 60 *
from dates
with cte as (
select DATEFROMPARTS ( datepart(yyyy,getdate()), datepart(mm,getdate()), 1 ) as startdate
union all
select dateadd(month,-1,startdate) from dates
where datediff(year,startdate,getdate()) <> 5 )
select CONVERT ( varchar(12), startdate , 107 ) from cte;

How to loop SQL statement multiple times

I try to loop one sql statement multiple times to retrieve the weekly revenue of on particular store. Here is my best guess which does not work.
SELECT *
DECLARE #i int = 0
WHILE #i < 52 BEGIN
SET #i = #i + 1
FROM dbo.revenue
WHERE DATEPART(WW, date) = #i
AND storenumber = '005'
END
You actually never want to write loops in SQL.
SELECT
SUM(earnings) weekly_earnings
FROM
dbo.revenue
WHERE
storenumber = '005'
AND date >= '2015-01-01'
AND date < '2016-01-01'
GROUP BY
DATEPART(WW, date)
Left join that against a helper table that contains 52 rows (1 through 52) representing the weeks to fill in the blanks (weeks with no revenue).
Note that the date >= '2015-01-01' AND date < '2016-01-01' exists because:
you must limit the query to one year, or the week number becomes ambiguous
it is superior to DATEPART(YY, date) = 2015 because, being a calculation, that expression would not be able to use an index on the date column, whereas >= and < can use an index
EDIT: Instead of a temporary table you can use a recursive CTE on SQL Server:
WITH WeekNumbers (WkNum) AS (
SELECT 1 AS WkNum
UNION ALL
SELECT w.WkNum + 1 FROM WeekNumbers w WHERE w.WkNum <= 52
)
SELECT
w.WkNum,
SUM(r.earnings) weekly_earnings
FROM
WeekNumbers w
LEFT JOIN dbo.revenue r ON w.WkNum = DATEPART(WW, r.date)
WHERE
r.storenumber = '005'
AND r.date >= '2015-01-01'
AND r.date < '2016-01-01'
GROUP BY
w.WkNum
You could just group your data and use some aggregation?
Select Sum(Revenue) AS [TotalRevenuePerWeek],
DatePart(ww, RevenueDate) as [WeekNumber]
From dbo.Revenue
Where StoreNumber = '005'
And DatePart(year, RevenueDate) = 2015
Group By DatePart(ww, RevenueDate)

SQL: Getting a row for each passing month up to date

I have a table that stores defects.
Each defect has a detection date and a closing date.
I want to extract the info for each month up to current date, about the number of open defects in that month.
For example, lets assume these are all the defects I have in my DB:
defect 1 - Detected in (01-01-2014) , Closed in (04-03-2014)
defect 2 - Detected in (07-02-2014) , Closed in (null) (still open)
I'd like to extract the info as follows:
01-01-2014 - 1 open defect (defect 1 was created)
01-02-2014 - 2 open defects (defect 2 was created)
01-03-2014 - 1 open defect (defect 1 was closed this month)
01-04-2014 - 1 open defect (defect 2 was never closed so I would get entries up to today)
...
...
01-02-2015 - 1 open
Is there a way to get this info with a single query without using functions?
Avoiding the question of "why no functions", it is possible to go N months back (limits apply) with the query below. Just replace "16" in "WHERE n < 16" with the number of months back you want to evaluate
; WITH Numbers (n) AS (
SELECT 1
UNION ALL
SELECT n + 1
FROM Numbers
WHERE n < 16
)
, NextMonth (dt) AS (
SELECT CAST( CAST( DATEPART(YEAR,GETDATE()) AS VARCHAR ) + '-' + CAST( DATEPART(MONTH,GETDATE())+1 AS VARCHAR ) + '-1' AS DATETIME )
)
, PriorMonths (dt) AS (
SELECT DATEADD( MONTH, -1 * n, dt )
FROM NextMonth
CROSS JOIN Numbers
), RawData ( y, m, DateOpened ) AS (
SELECT DATEPART( YEAR, dt )
, DATEPART( MONTH, dt )
, t.DateOpened
FROM PriorMonths AS pm
LEFT JOIN #t AS t
ON DATEADD(MONTH,-1,t.DateOpened) < dt
AND (DATEADD(MONTH,-1,t.DateClosed) >= dt OR t.DateClosed IS NULL)
)
SELECT y, m, COUNT(DateOpened)
FROM RawData
GROUP BY y, m
ORDER BY y DESC, m DESC
First I want to point out that I've used MS SQL Server T-SQL functions DATEADD(), DATEDIFF(), and GETDATE() - there should be equivalents in whatever flavour of SQL you want to use.
The variable #startDate should be set to the start of the range on which you want to report.
DECLARE #startDate DATE;
DECLARE #endDate DATE;
SET #startDate = '20140101';
SET #endDate = DATEADD(m, DATEDIFF(m, 0, GETDATE()), 0);
WITH Dates (dEnd, dStart) AS (
SELECT DATEADD(M, 1, #endDate), #endDate
UNION ALL
SELECT DATEADD(M, -1, dEnd), DATEADD(M, -1, dStart)
FROM Dates
WHERE dEnd > #startDate
)
SELECT dStart AS 'Month start', COUNT(Defects.reportedDate) AS 'Open defects'
FROM Dates
LEFT OUTER JOIN Defects ON
Defects.reportedDate < dEnd AND (Defects.resolvedDate IS NULL OR Defects.resolvedDate > dStart)
GROUP BY dStart
ORDER BY dStart;