Changes to a Query Based on Year - sql

select datepart(month,s1.Timeperiod) as monthofaum,
datepart(YEAR,s1.Timeperiod) as Yearofaum,
ISNULL(s2.endingAum,0) as Starting_Aum,
s1.endingAum as Ending_Aum
from #temp_1 s1
left outer join (select * from #temp_1)s2
on month(s1.Timeperiod) = dateadd(D,1,month(s2.Timeperiod))
This work perfectly for the Monthly basis, but supoose if i need to change the query to obtain the result based on the year also - where should i make changes?
Example
monthofaum Yearofaum Starting_Aum Ending_Aum
----------- ----------- --------------------- ---------------------
11 2009 0.00 0.00
12 2009 0.00 1059594254.86
1 2010 0.00 1083195051.98
2 2010 1083195051.98 1125314638.64
3 2010 1125314638.64 1212355911.70
4 2010 1212355911.70 1270374634.62
5 2010 1270374634.62 1265193377.27
6 2010 1265193377.27 1260776179.02
7 2010 1260776179.02 2599205697.44
8 2010 2599205697.44 1323838670.57
If you look at the data can see that for 2010 the Ending Aum value of previous month will be equal to Starting Aum of next month, but when it comes to year 2009 the dec Ending Aum is not assigned to Jan 2010 Starting Aum.
This is the bug which i need to fix.

To adjust it for year, compare just the month and year. For example,
select convert(varchar(7), getdate(), 120)
Prints 2010-10. Applied to your query, you could rewrite the on like:
on convert(varchar(7), s1.TimePeriod, 120) =
convert(varchar(7), DateAdd(year, 1, s2.TimePeriod), 120)
P.S. the subquery is not required. This line:
left outer join (select * from #temp_1)s2
is exactly the same as:
left outer join #temp_1 s2

This is assuming you don't care about the time I think this will work...
select datepart(month,s1.Timeperiod) as monthofaum,
datepart(YEAR,s1.Timeperiod) as Yearofaum,
ISNULL(s2.endingAum,0) as Starting_Aum,
s1.endingAum as Ending_Aum
from #temp_1 s1
left outer join (select * from #temp_1) s2
on s1.TimePeriod = DateAdd(year,1,s2.TimePeriod)
EDIT:
Or if you do care about time you could try this (I have a function for convenience)...
1.Create dateonly function
CREATE FUNCTION [dbo].[fn_DateOnly](#DateTime DATETIME)
-- Returns #DateTime at midnight; i.e., it removes the time portion of a DateTime value.
RETURNS DATETIME
AS
BEGIN
RETURN DATEADD(dd,0, DATEDIFF(dd,0,#DateTime))
END
2. This allows you to:
select datepart(month,s1.Timeperiod) as monthofaum,
datepart(YEAR,s1.Timeperiod) as Yearofaum,
ISNULL(s2.endingAum,0) as Starting_Aum,
s1.endingAum as Ending_Aum
from #temp_1 s1
left outer join (select * from #temp_1) s2
on dbo.fn_DateOnly(s1.TimePeriod) = DateAdd(year,1,dbo.fn_DateOnly(s2.TimePeriod))

select
datepart(month,s1.Timeperiod) as monthofaum,
datepart(YEAR,s1.Timeperiod) as Yearofaum,
ISNULL(s2.endingAum,0) as Starting_Aum,
s1.endingAum as Ending_Aum
from
#temp_1 s1
left outer join
(select * from #temp_1) s2 on (month(s1.Timeperiod)-1 = month(s2.Timeperiod)
or (month(s1.Timeperiod) = 1 and month(s2.Timeperiod) = 12))
The above query works if the table contains only data for 2 years. I will keep you all posted if I figure out the problem for above query

Related

YTD for the below query

I want to add add the Year to date component to this code. I have tried some other ways but I am not getting what I would like to see. Can someone please help me revised this to include the YTD in addition to the Month to date that is already there?
SELECT
COST__DESC,
ST.AD_SRV_MTN AS MONTH_OF_AD,
COUNT(DISTINCT CM.CM_NBR) AS CMS,
MEM_MO AS MBR_MTH,
CMS/MBR_MTH*1000 AS CMS_PER_1000
FROM XTR.FT_CM AS CM
JOIN XTR.FT_ST AS ST ON ST.CM_NBR = CM.CM_NBR
JOIN XTR.DIM_MED_CST AS MC ON ST.CST_CK = MCC.CST_CK
JOIN XTR.DIM_AF AS AFF ON ST.PRO_CK = AFF.AFF_CK
JOIN XTR.DIM_ADJDCTN_STAT AS A_S ON ST.ADJDCTN_STAT_CK = A_S.ADJDCTN_STAT_CK
JOIN XTR.DIM_ADJ_OT AS OT ON ST.ADJ_CK = OT.ADJ_CK
LEFT JOIN
(SELECT
CALENDAR_YEAR_MONTH as YEAR_MO,
SUM(MBR.COUNT_NBR) as MEM_MO
FROM XTR.FT_MBR_MONTHS MBR
INNER JOIN DIM_MBR_C ON MBR.DB_MBR_CK = DIM_MBR_C.DB_MBR_CK
AND MBR.DATE_CK BETWEEN DIM_MBR_C.DB_eff_date_ck
AND DIM_MBR_C.DB_END_DATE_CK
INNER JOIN DIM_DATE DT ON ELI_DATE_CK = DT.DATE_CK
WHERE MBR.F_C_CK = 500058321 AND YEAR_MO >= 201701
GROUP BY 1) MM ON ST.AD_SRV_MTN = MM.YEAR_MO
WHERE ST.F_C_CK = 500058321 AND ST.ST_START_DATE_CK >= 20200101
AND ST.AD_SRV_MTN > 201912 AND MC.MED_DESC IN ('Er', 'IP')
AND ST.AD_SRV_MTN < ((EXTRACT (YEAR FROM CURRENT_DATE) *100) +
EXTRACT (MONTH FROM CURRENT_DATE))
GROUP BY 1,2,4
ORDER BY 1,2
Honestly I don't really get your SQL and what is counted, but: Your can play with dates quite easy in Teradata, as Dates are stored (and can be used) internally as INTEGER. Just keep in mind year 1900 as year 0 and format YYYYMMDD.
So e.g. 16-Apr-2020 is in Format YYYYMMDD 20200416 and if you take 1900 as 0 you'll end up with 1200416 which is the internal format. Just try SELECT CURRENT_DATE (INT); - So if you want compare YearNumers you just have to divide by 10000.
With this your can implement YTD as SUM (CASE WHEN CURRENT_DATE/10000 = <YourDateField>/10000 THEN <YourKPI> else 0 END) as YourKPI_YTD. Counting can be done by SUM...THEN 1 ELSE 0 END....

SQL Server 2012 - find duplicate month (string) but different year

Having difficulty getting my head around this one.
I've been asked to create a report showing customers who signed up in the same month in previous year.
Invoice table looks a bit like this: (can't figure out how to create a nicer table)
invoiceid customerid monthinvoice yearinvoice
1 50 July 2016*
2 51 July 2016
3 52 July 2016*
4 53 July 2016
5 54 August 2016
6 50 July 2017*
7 51 August 2017
8 52 July 2017*
9 53 August 2017
10 54 September 2017
The only proper date column used is date the invoice was generated and the date payment received.
The records marked with * are the ones I'm only interested in, I just want to see 2 records returned when I pass a month as a parameter (I'll be asked to show how many customers have renewed in August for example. If the 1st invoice was in July 2016 and next invoice in August 2017 they will be treated as a new customer, not a renewal (must be exactly 12 months))
1) 50
2) 52
Any help much appreciated.
Here is one way. First we get all invoices for this month, current year, then union to the same month of the previous year. Then, we filter on customers who have a record for both using HAVING.
;with cte as(
select *
from yourtable
where
(monthinvoice = #monthinvoice
and yearinvoice = datepart(year,getdate()))
union
select *
from yourtable
where
(monthinvoice = #monthinvoice
and yearinvoice = datepart(year,dateadd(year,-1,getdate()))))
select *
from cte
where customerid in (select customerid from cte group by customerid having count(invoiceid) > 1)
I think this should do the trick for you-
SELECT I1.invoiceid, I1.customerid, I1.monthinvoice, I1.yearinvoice, I2.yearinvoice
FROM Invoice_table I1
INNER JOIN Invoice table I2
ON I1.customerid = I2.customerid
AND I1.monthinvoice = I2.monthinvoice
AND I1.yearinvoice = I2.yearinvoice + 1
something like this
select customerid , monthinvoice from yourtable
where yearinvoice in (2016, 2017) and monthinvoice = 'July'
group by customerid , monthinvoice
having count(*) = 2
Something like the following should give you some ideas as to how to build the report out.
Declare #ReportYear as int = 2017;
--this should show all customers with invioices for these months in both 2017 and 2016
select a.customerid, a.monthinvoice
from
(
--get people with invoice last year
Select distinct customerid, monthinvoice
from Invoices i0
where yearinvoice = #ReportYear - 1
) a
join
(
--get people with invoice this year
Select distinct customerid, monthinvoice
from Invoices i0
where yearinvoice = #ReportYear
) b on a.customerid = b.customerid
and a.monthinvoice = b.monthinvoice
If Im following your question correctly...
SELECT customerid FROM InvTblName T
INNER JOIN (SELECT customerID
FROM InvTblName
HAVING Z.invyear=T.invyear+1) Z
ON T.invmonth=Z.invmonth

SQL: Count of records by consecutive date, even when no records exist for a date

I'm using SQL Server 2008 R2.
I’m querying a table of Hospital Appointment Slots and trying to return a list of how many appointment slots for a specific doctor are flagged as being booked, grouped by week number/year.
There are some instances of weeks that don’t have any booked appointments yet, but I want the result to list ALL the forthcoming weeks, even where the count of booked appointment slots is zero.
The output I’m looking for is along these lines:
-------------------------------------------
Year | Week Number | Number of Booked Slots
-------------------------------------------
2017 | 48 | 10
2017 | 49 | 0
2017 | 50 | 4
2017 | 51 | 2
2017 | 52 | 0
2018 | 1 | 5
I understand that a standard select aggregating the results won’t show those weeks where there's a zero count of records, because there’s nothing to return – so I’ve tried to get around this by using a cte to first produce a list of all the forthcoming weeks.
However, try as I might, I can’t get the query to display the zero weeks...
I’ve seen a number of solutions to similar problems to this, but despite experimenting I haven’t been able to apply them to my particular problem (including SQL Count to include zero values)
This is the latest iteration of the query I’ve written so far.
WITH CTE_Dates AS
(
SELECT DISTINCT Slot_Start_Date AS cte_date
FROM [Outpatients.vw_OP_Clinic_Slots WITH (NOLOCK)
)
SELECT
DATEPART(year,OPCS.Slot_Start_Date) [Year]
,DATEPART(week,OPCS.Slot_Start_Date) [Week Number]
,count(OPCS.Slot_Start_Date) [Number of Booked Slots]
FROM
Outpatients.vw_OP_Clinic_Slots OPCS WITH (NOLOCK)
LEFT OUTER JOIN CTE_Dates ON OPCS.Slot_Start_Date=CTE_Dates.cte_date
LEFT OUTER JOIN Outpatients.vw_OP_Clinics CLIN ON OPCS.Clinic_Code=CLIN.Clinic_Code
WHERE
OPCS.Slot_Start_Date >= '14/08/2017'
AND OPCS.Booked_Flag = 'Y'
AND CLIN.Lead_Healthcare_Professional_Name = 'Dr X'
GROUP BY
DATEPART(year,OPCS.Slot_Start_Date)
,DATEPART(week,OPCS.Slot_Start_Date)
ORDER BY
DATEPART(year,OPCS.Slot_Start_Date)asc
,DATEPART(week,OPCS.Slot_Start_Date)asc
The result it’s returning me is correct, BUT I just need it to include those weeks in the list where the count is zero.
Please can anyone explain where I’m going wrong? I’m guessing I’m not joining the cte correctly, but I’ve tried both right and left joins which produce the same result. I’ve also tried inverting the query by swopping the above query statement and cte around, but this doesn’t work either.
Appreciate any guidance anyone can suggest.
Just RIGHT JOIN #ListOfWeeks table to the result set you have:
DECLARE #ListOfWeeks TABLE ([Week_No] int, [Year_Number] int);
DECLARE #i tinyint = 1, #y int = 2010;
WHILE #i <= 52 AND #y < 2018
BEGIN
INSERT INTO #ListOfWeeks([Week_No], [Year_Number]) VALUES (#i, #y);
IF #i = 52 BEGIN
SET #i = 0
SET #y +=1
END
SET #i += 1
END
SELECT * FROM #ListOfWeeks
WITH [Your_Part] AS(
SELECT
DATEPART(year,OPCS.Slot_Start_Date) [Year]
,DATEPART(week,OPCS.Slot_Start_Date) [Week Number]
,count(OPCS.Slot_Start_Date) [Number of Booked Slots]
FROM
Outpatients.vw_OP_Clinic_Slots OPCS WITH (NOLOCK)
LEFT OUTER JOIN CTE_Dates ON OPCS.Slot_Start_Date=CTE_Dates.cte_date
LEFT OUTER JOIN Outpatients.vw_OP_Clinics CLIN ON OPCS.Clinic_Code=CLIN.Clinic_Code
WHERE
OPCS.Slot_Start_Date >= '14/08/2017'
AND OPCS.Booked_Flag = 'Y'
AND CLIN.Lead_Healthcare_Professional_Name = 'Dr X'
GROUP BY
DATEPART(year,OPCS.Slot_Start_Date)
,DATEPART(week,OPCS.Slot_Start_Date)
),
SELECT xxx.[Year_Number], xxx.[Week_No], yp.[Number of Booked Slots]
FROM [Your_Part] yp
RIGHT JOIN #ListOfWeeks xxx ON yp.[Year] = xxx.[Year_Number] AND yp.[Week Number] = xxx.[Week_No]
IF OBJECT_ID(N'tempdb..##cal_weeks_temp', N'U') IS NOT NULL
DROP TABLE ##cal_weeks_temp;
create table ##cal_weeks_temp (date_of_week date, week_num int)
declare #start_date date
declare #end_date date
set #start_date='01/01/2017'
set #end_date='12/31/2018'
while #start_date<#end_date
begin
set #start_date=dateadd(day,1,#start_date)
insert into ##cal_weeks_temp values (#start_date,DATEPART(week,#start_date))
end
select YEAR(t1.date_of_week) 'YEAR',t1.week_num,
sum(case convert(varchar,t2.BookedTime,105) when convert(varchar,t1.date_of_week,105) then 1 else 0 end) 'count'
from ##cal_weeks_temp t1
left join Your_Table t2
on convert(varchar,t2.BookedTime,105)=convert(varchar,t1.date_of_week,105)
group by YEAR(t1.date_of_week) ,t1.week_num
order by YEAR(t1.date_of_week) ,t1.week_num

Trouble running a complex query in sql?

I am pretty new to SQL Server and just started playing with it. I am trying to create a table that shows attendance percentage by department.
So first i run this query:
SELECT CrewDesc, COUNT(*)
FROM database.emp
INNER JOIN database.crew on sim1 = sim2
GROUP BY CrewDesc
This gives a table like this:
Accounting 10
Marketing 5
Economics 20
Engineering 5
Machinery 5
Tech Support 10
Then i run another query:
SELECT DeptDescription, COUNT(*)
FROM database.Attendee
GROUP BY DeptDescription
This gives me the result of all the people that have attended meeting something like
Accounting 8
Marketing 5
Economics 15
Engineering 10
Tech Support 8
Then I get the current week in the year by SELECT Datepart(ww, GetDate()) as CurrentWeek To make this example easy lets assume this will be week "2".
Now the way i was going to create this was a table for each step but that seems like waste. Is there a way we can combine to tables in a query? So in the end result i would like a table like this
Total# Attd Week (Total*Week) Attd/(Total*week)%
Accounting 10 8 2 20 8/20
Marketing 5 5 2 10 5/10
Economics 20 15 2 40 15/40
Engineering 5 10 2 10 10/10
Machinery 5 NULL 2 10 0/10
Tech Support 10 8 2 20 8/20
Ok, note that my recommendation below is based on your exact existing queries - there are certainly other ways to construct this that may be more performant, but functionally this should work for your requirement. Also, it illustrates the key features of different join types that happen to be relevant for your request, as well as inline views (aka nested queries), which are a super-powerful technique in the SQL language as a whole.
select t1.CrewDesc, t1.Total, t2.Attd, t3.Week,
(t1.Total*t3.Week) as Total_x_Week,
case when isnull(t1.Total*t3.Week, 0) = 0 then 0 else isnull(t2.Attd, 0) / isnull(t1.Total*t3.Week, 0) end as PercentageAttd
from (
SELECT CrewDesc, COUNT(*) AS Total
FROM database.emp INNER JOIN database.crew on sim1 = sim2
GROUP BY CrewDesc
) t1
left outer join /* left outer to keep all rows from t1 */ (
SELECT DeptDescription, COUNT(*) AS Attd
FROM database.Attendee GROUP BY DeptDescription
) t2
on t1.CrewDesc = t2.DeptDescription
cross join /* useful when adding a scalar value to all rows */ (
SELECT Datepart(ww, GetDate()) as Week
) t3
order by t1.CrewDesc
Good luck!
Try something like this
SELECT COALESCE(a.crewdesc,b.deptdescription),
a.total,
b.attd,
Datepart(ww, Getdate()) AS week,
total * Datepart(ww, Getdate()),
b.attd/(a.total*Datepart(ww, Getdate()))
FROM (query 1) a
FULL OUTER JOIN (query 2) b
ON a.crewdesc = b.deptdescription
WITH Total AS ( SELECT CrewDesc, COUNT(*) AS [Count]
FROM database.emp
INNER JOIN database.crew on sim1 = sim2
GROUP BY CrewDesc
),
Attd AS ( SELECT DeptDescription, COUNT(*) AS [Count]
FROM database.Attendee
GROUP BY DeptDescription
)
SELECT COALESCE(CrewDesc,DeptDescription) AS [Dept],
Total.[Count] AS [Total#],Attd.[Count] AS [Attd],
Total.[Count] * Datepart(ww, GetDate()) AS [(Total*Week)],
CAST(Attd.[Count] AS VARCHAR(10))+'/'+ CAST((Total.[Count] * Datepart(ww, GetDate()))AS VARCHAR(10)) AS [Attd/(Total*week)%]
FROM Total INNER JOIN Attd ON Total.CrewDesc = Attd.DeptDescription
I'm assuming your queries are correct -- you give no real information about your model so I've no way to know. They look wrong since the same data is called CrewDesc in one table and Dept in another. Also the join sim1 = sim2 seems very strange to me. In any case given the queries you posted this will work.
With TAttend as
(
SELECT CrewDesc, COUNT(*) as TotalNum
FROM database.emp
INNER JOIN database.crew on sim1 = sim2
GROUP BY CrewDesc
), Attend as
(
SELECT DeptDescription, COUNT(*) as Attd
FROM database.Attendee
GROUP BY DeptDescription
)
SELECT CrewDesc as Dept, TotalNum, ISNULL(Attd, 0) as Attd ,Datepart(ww, GetDate()) as Week,
CASE WHEN ISNULL(Attd, 0) > 0 THEN 0
ELSE ISNULL(Attd, 0) / (TotalNum * Datepart(ww, GetDate()) ) END AS Percent
FROM TAttend
LEFT JOIN Attend on CrewDesc = DeptDescription

Bring through a newly created calculated column in another query

I have 2 separate queries below which run correctly.Now I've created a calculated column to provide a count of working days by YMs and would like to bring this through to query1(the join would be query1.Period = query2.Yms)
please see the query and outputs below.
SELECT Client, ClientGroup, Type, Value, Period, PeriodName, PeriodNumber, ClientName
FROM metrics.dbo.vw_KPI_001_Invoice
select YMs,sum(case when IsWorkDay = 'X' then 1 else 0 end) from IESAONLINE.Dbo.DS_Dates
where Year > '2013'
group by YMs
Query 1
Client ClientGroup Type Value Period PeriodName PeriodNumber ClientName
0LG0 KarroFoods Stock 5691.68 201506 Week 06 2015 35 Karro Foods Scunthorpe
Query 2
YMs (No column name)
201401 23
Would the following work:
SELECT Client, ClientGroup, Type, Value, Period, PeriodName, PeriodNumber, ClientName, cnt
FROM metrics.dbo.vw_KPI_001_Invoice q1
INNER JOIN (select YMs,sum(case when IsWorkDay = 'X' then 1 else 0 end) as cnt from IESAONLINE.Dbo.DS_Dates
where Year > '2013'
group by YMs ) q2 ON q1.Period = q2.YMs
If a value isn't always available then you might consider changing the INNER JOIN to an OUTER JOIN.