SQL sum of current year commissions is higher than previous year - sql-server

Trying to compare sum of current year commissions to the previous year but having trouble creating an inner join. If thisYear is higher I will update a growth_incentive field to '.05' Currently have something like this that gets the data but I feel like its inefficient
SELECT a.emp_no, SUM(a.total_commission) AS ThisYearComm
,(select SUM(total_commission) AS LastYearComm
from tbl_comm_medmon_employees_stats
where emp_no = a.emp_no
and year(getdate())-1 = comm_year) as lastyear
FROM tbl_comm_medmon_employees_stats a
where year(getdate()) = a.comm_year
GROUP BY a.emp_no, a.comm_year

If I understand your table correctly, you don't need a join. Try using conditional aggregation instead, like this:
SELECT a.emp_no
, SUM(case when year(getdate()) = a.comm_year then a.total_commission end) AS ThisYearComm
, SUM(case when year(getdate()) - 1 = a.comm_year then a.total_commission end) AS LastYearComm
FROM tbl_comm_medmon_employees_stats a
where a.comm_year in (year(getdate()), year(getdate()) - 1)
GROUP BY a.emp_no

You could try to use a conditional SUM instead
SELECT a.emp_no,
SUM(CASE WHEN year(getdate())-1 = a.comm_year THEN a.total_commission
ELSE 0
END) [LastYear],
SUM(CASE WHEN year(getdate()) = a.comm_year THEN a.total_commission
ELSE 0
END) [ThisYearComm]
FROM tbl_comm_medmon_employees_stats a
GROUP BY a.emp_no

Related

Distinct Count when using Case When

I am having trouble getting the correct distinct count when using case when and distinct in SQL Server.
I have a column for count(distinct TA_STUDENT_ID) which calculates the correct count. I then have 2 additional columns in which I am doing a count by TA_LOCATION and the totals for the numbers on each row under TA_LOCATION need to add up to the COUNT of the DISTINCT TA_STUDENT_ID. I need help to get it to do that. Here is my query:
SELECT
count (distinct TA_STUDENT_ID) as 'count',
COUNT (CASE WHEN (TA_LOCATION = 'CCC') THEN 'CCC' END) AS 'CCC',
COUNT(CASE WHEN (TA_LOCATION = 'SCCDC') THEN 'SCCDC' END) AS 'SCCDC',
[TA_AW_ID]
FROM [S85_TA_ACYR]
group by [TA_AW_ID]
order by [TA_AW_ID]
My desired results are that the totals on each row in the TA_LOCATION columns should total and match the numbers on the rows in my COUNT DISTINCT TA_STUDENT_ID column.
Use DISTINCT inside COUNT() with CASE expression :
SELECT COUNT(DISTINCT TA_STUDENT_ID) as 'count',
COUNT(DISTINCT CASE WHEN (TA_LOCATION = 'CCC') THEN TA_STUDENT_ID END) AS 'CCC',
COUNT(DISTINCT CASE WHEN (TA_LOCATION = 'SCCDC') THEN TA_STUDENT_ID END) AS 'SCCDC',
[TA_AW_ID]
FROM [S85_TA_ACYR]
GROUP BY [TA_AW_ID]
ORDER BY [TA_AW_ID];
You can also use a SUM() for the second two fields, like this:
SELECT
Count = COUNT(DISTINCT TA_STUDENT_ID)
,CCC = SUM(CASE WHEN ( TA_LOCATION = 'CCC' ) THEN 1 ELSE 0 END)
,SCCDC = SUM(CASE WHEN ( TA_LOCATION = 'SCCDC' ) THEN 1 ELSE 0 END)
,TA_AW_ID
FROM S85_TA_ACYR
GROUP BY TA_AW_ID
ORDER BY TA_AW_ID

SQL Server Query # of Events Per Day

Perhaps I am making this more complicated that it really is, hopefully someone can point me in the right direction. I get pretty close this this query:
SELECT
Action, TimeOccurred,
COUNT(Action)
FROM
[].[dbo].[]
WHERE
Action LIKE '%Logon Failed%'
AND (DATEDIFF(day, TimeOccurred, GETDATE()) BETWEEN 0 AND 30)
GROUP BY
Action, TimeOccurred
ORDER BY
TimeOccurred
My problem is TimeOccurred is formatted like this: 2017-05-13 00:02:00 so right now instead of giving me all the "logon failed" events per day, I get it per hour/min/second as well.
I would like to essentially cut the hh:mm:ss off so my results are per day. Hopefully that makes sense.
You can convert() to date to truncate the time portion of a datetime data type.
select
Action
, TimeOccurred = convert(date,TimeOccurred )
, Count(Action)
from [].[dbo].[]
where Action like '%Logon Failed%'
and TimeOccured >= dateadd(day,-30,dateadd(day, datediff(day, 0, getdate()), 0))
group by Action
, convert(date,TimeOccurred)
order by TimeOccurred
For your where, you can calculate the date for 30 days ago instead of getting a datediff() and restricting that range to 0-30.
For conditional aggregation you could do something like this:
select
TimeOccurred = convert(date, TimeOccurred)
, logon_kerberos = count (case when Action like ' %logon (kerberos)%' then 1 end)
, logon_local_wts = count (case when Action like ' %logon (local/wts)%' then 1 end)
, logon_ntlm = count (case when Action like ' %logon (ntlm)%' then 1 end)
, logon_total = count (case when Action like ' %logon (%' then 1 end)
, Count(Action)
from [CPTRAX_for_Windows].[dbo].[Logon_Logoff_and_Failed_Logon_Profiles]
where Action like '%Logon (%'
and TimeOccurred >= dateadd(day, -30, dateadd(day, datediff(day, 0, getdate()), 0))
group by convert(date, TimeOccurred)
order by TimeOccurred
You can use a Calendar or dates table for this sort of thing.
For only 152kb in memory, you can have 30 years of dates in a table with this:
/* dates table */
declare #fromdate date = '20000101';
declare #years int = 30;
/* 30 years, 19 used data pages ~152kb in memory, ~264kb on disk */
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
select top (datediff(day, #fromdate,dateadd(year,#years,#fromdate)))
[Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,#fromdate))
into dbo.Dates
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date];
create unique clustered index ix_dbo_Dates_date
on dbo.Dates([Date]);
Without taking the actual step of creating a table, you can use it inside a common table expression with just this:
declare #fromdate date = dateadd(day , datediff(day , 0, getdate() )-30 , 0);
declare #thrudate date = dateadd(day , datediff(day , 0, getdate() ), 0);
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (datediff(day, #fromdate, #thrudate)+1)
[Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,#fromdate))
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date]
)
select [Date]
from dates;
Use either like so:
select
TimeOccurred = d.Date
, logon_kerberos = count (case when Action like ' %logon (kerberos)%' then 1 end)
, logon_local_wts = count (case when Action like ' %logon (local/wts)%' then 1 end)
, logon_ntlm = count (case when Action like ' %logon (ntlm)%' then 1 end)
, logon_total = count (case when Action like ' %logon (%' then 1 end)
, Count(Action)
from Dates d
left join [CPTRAX_for_Windows].[dbo].[Logon_Logoff_and_Failed_Logon_Profiles] l
on d.Date = convert(date,l.TimeOccured)
and l.Action like '%Logon (%'
where d.Date >= dateadd(day, -30, dateadd(day, datediff(day, 0, getdate()), 0))
group by d.Date
order by d.Date
Number and Calendar table reference:
Generate a set or sequence without loops - 2 - Aaron Bertrand
The "Numbers" or "Tally" Table: What it is and how it replaces a loop - Jeff Moden
Creating a Date Table/Dimension in sql Server 2008 - David Stein
Calendar Tables - Why You Need One - David Stein
Creating a date dimension or calendar table in sql Server - Aaron Bertrand

How to add Totals in SQL

I am trying to get the totals of each month as of YTD (Years to date) Can someone please help me figure out how to integrate this in my query? thank you This is what I have so far.
DECLARE #Year int
set #Year = 2013
select a.first_name, a.last_name
, COUNT(CASE WHEN MONTH(b.Funded_date) = 1 THEN 1 ELSE NULL END) January
, COUNT(CASE WHEN MONTH(b.Funded_date) = 2 THEN 1 ELSE NULL END) February
, COUNT(CASE WHEN MONTH(b.Funded_date) = 3 THEN 1 ELSE NULL END) March
, COUNT(CASE WHEN MONTH(b.Funded_date) = 4 THEN 1 ELSE NULL END) April
From tContact a Join tContract b ON a.contact_id = b.contract_id
Group by a.first_name, a.last_name
This is just an example of how you could count up rows that fall under a certain month.
SELECT MONTH(b.Funded_date) AS 'MonthNum',
COUNT(*) AS 'Total'
FROM Table AS b
WHERE YEAR(b.Funded_date) = 2014
GROUP BY MONTH(b.Funded_date)
Hopefully this will help you with your query.
Thanks
What I tried to do here is create an upper bound record for each month in tContract then join that back into the query you already had. It is joined on dates that are between the beginning of the year and the current month.
DECLARE #Year int
set #Year = 2013
select Ms.thismonth, count(B.thing_You_are_Totalling) from (
select thisMonth = dateadd(month,datediff(month,0,Funded_date),0)
from tContract
where moid = 2005405
and year(Funded_date) = #Year
group by dateadd(month,datediff(month,0,Funded_date),0)
) Ms
inner join (select * from tContact a inner join tContract ON a.contact_id = tContract.contract_id) B
on B.Funded_date >=dateadd(year,datediff(year,0,B.Funded_date),0) -- beginning of year
and B.Funded_date <= Ms.thisMonth -- this month
where year(B.Funded_date) = #Year -- restrict to only this year
group by thisMonth, first_name, last_name
I don't have your full table definition so there might be some issues (maybe a SqlFiddle is in order)
Not sure if this is what you are asking for.
select a.first_name, a.last_name
, COUNT(CASE WHEN MONTH(b.Funded_date) = 1 THEN 1 ELSE NULL END) January
, COUNT(CASE WHEN MONTH(b.Funded_date) = 2 THEN 1 ELSE NULL END) February
, COUNT(CASE WHEN MONTH(b.Funded_date) = 3 THEN 1 ELSE NULL END) March
, COUNT(CASE WHEN MONTH(b.Funded_date) = 4 THEN 1 ELSE NULL END) April
, COUNT(*) TotalCount
, SUM(CASE WHEN MONTH(b.Funded_date) = 1 THEN Amount ELSE NULL END) JanuaryAmount
, SUM(CASE WHEN MONTH(b.Funded_date) = 2 THEN Amount ELSE NULL END) FebruaryAmount
, SUM(CASE WHEN MONTH(b.Funded_date) = 3 THEN Amount ELSE NULL END) MarchAmount
, SUM(CASE WHEN MONTH(b.Funded_date) = 4 THEN Amount ELSE NULL END) AprilAmount
From tContact a Join tContract b ON a.contact_id = b.contact_id
WHERE YEAR(b.Funded_date) = #Year
Group by a.first_name, a.last_name
How about this:
declare #year int = 2013
select a.first_name
, a.last_name
, month(b.Funded_date) [Month]
, datename(month, dateadd(month, month(date_of_birth_dt), - 1)) [MonthName]
, count(month(b.Funded_date)) [Total]
from tContact a
where a.[Year] = #year
group by a.first_name, a.last_name, month(b.Funded_date)
It returns the total of each Month for the year 2013. a.[Year] might not the the name of the field that you have so adjust accordingly. Also, [Month] returns numeric value for month.
Use the Count(*) As Total function. I'm sure this will help you
SELECT MONTH(b.Funded_date) AS 'MonthNum',
COUNT(*) AS 'Total'
FROM Table AS b
WHERE YEAR(b.Funded_date) = 2014
GROUP BY MONTH(b.Funded_date)

Detailing query for split by month

I have the following MS SQL query:
SELECT DNIS, COUNT(*) AS Numbers
FROM I3_IC.dbo.CallDetail_Viw WITH (NOLOCK)
WHERE CallDirection = 'Inbound'
AND CallType = 'External'
AND InteractionType = 0
GROUP BY DNIS
ORDER BY DNIS;
Which returns a list like this:
DNIS Count
+12013317062 34
+12018841142 1
+12019771912 1
+12025594026 72
This is over a period of 2 years. I would like a break-down per month
This is the layout of the DB I get this data from (some fields ommited)
CallId
CallType
CallDirection
LineId
RemoteNumberFmt
RemoteNumberCallId
InitiatedDate
InitiatedDateTimeGmt
ConnectedDate
ConnectedDateTimeGmt
TerminatedDate
TerminatedDateTimeGmt
DNIS
CallEventLog
The InitiatedDate and InitiatedDateTimeGmt fields are the ones that hold the date-time server based ad GMT based like this: 2013-02-11 23:01:26.000
Any suggestions appriciated.
So group it by month. Is there something I'm missing in your question?
SELECT DNIS, YEAR(InitiatedDate) as [Year], MONTH(InitiatedDate) as [Month], COUNT(*) AS Numbers
FROM I3_IC.dbo.CallDetail_Viw WITH (NOLOCK)
WHERE CallDirection = 'Inbound'
AND CallType = 'External'
AND InteractionType = 0
GROUP BY DNIS, YEAR(InitiatedDate), MONTH(InitiatedDate)
ORDER BY DNIS, YEAR(InitiatedDate), MONTH(InitiatedDate);
You can use the DATEPART function to extract the month and year from the InitiatedDate field and then include those values in the GROUP BY. You can also use those functions in the ORDER BY as well.
SELECT DNIS, COUNT(*) AS Numbers, DATEPART(mm, InitiatedDate) AS Month, DATEPART(yyyy, InitiatedDate) AS Year
FROM I3_IC.dbo.CallDetail_Viw WITH (NOLOCK)
WHERE CallDirection = 'Inbound'
AND CallType = 'External'
AND InteractionType = 0
GROUP BY DNIS, DATEPART(yyyy, InitiatedDate), DATEPART(mm, InitiatedDate)
ORDER BY DNIS, DATEPART(yyyy, InitiatedDate), DATEPART(mm, InitiatedDate) ;

tsql UNION without nulls

I have the following query
SELECT MONTH, COUNT(DISTINCT VISITS) AS BRAND_VISITS, NULL AS NONB_VISITS
FROM Table1
WHERE KEYWORD_TYPE = BRAND(
AND DATE >= '2013-01-01'
GROUP BY MONTH
UNION ALL
SELECT MONTH, NULL, COUNT(DISTINCT VISITS) AS NONB_VSTS
FROM Table1
WHERE KEYWORD_TYPE = NON-BRAND
AND DATE >= '2013-01-01'
GROUP BY MONTH
I get the following results:
1 352540 NULL
2 309834 NULL
3 228764 NULL
4 236054 NULL
5 218096 NULL
6 172527 NULL
1 NULL 5337
2 NULL 14120
3 NULL 9954
4 NULL 23755
5 NULL 19771
6 NULL 30797
However, what I want is inline results without NULLS
1 352540 5337
2 309834 14120
3 228764 9954
4 236054 23755
5 218096 19771
6 172527 30797
You can do this with using a single statement with CASE or with an JOIN on month instead of a UNION. If you take the join approach you may need to account for null values (no visist for a keyword in a month). You will want to profile them to see which is faster with your data and table structure. It is really all about the indexes and the amount of data you need to aggregate.
Assuming you don't have to worry about nulls based on the counts in your example, here is what you want.
SELECT brand.month, brand.brand_visits,nonbrand.non_brand_visits
FROM (SELECT month, COUNT(visits) AS brand_visits
FROM Table1
WHERE keyword_type = 'BRAND'
AND date >= '2013-01-01'
GROUP BY month) brand
INNER JOIN
(SELECT month, COUNT(visits) AS non_brand_visits
FROM Table1
WHERE keyword_type = 'NON-BRAND'
AND date >= '2013-01-01'
GROUP BY month) nonbrand
ON brand.month=nonbrand.month
Here is the CASE approach. You should profile based on your actual data you are aggregating and your indexes to see which method is faster.
SELECT month,
SUM(CASE WHEN keyword_type = 'BRAND' THEN 1 ELSE 0 END) AS brand_visits,
SUM(CASE WHEN keyword_type = 'NON-BRAND' THEN 1 ELSE 0 END) AS non_brand_visits
FROM Table1
WHERE date >= '2013-01-01'
GROUP BY month
Finally, you did not provide table structure or example data so I made some assumptions above. I strongly believe you did not need the COUNT(DISTINCT in your original statement. I have removed it and verified the two statement above yield the same results. If COUNT(DISTINCT is required then the CASE approach will not work but the join approach will still work fine.
Using your columns:
SELECT month,
count(distinct CASE WHEN keyword_type = 'BRAND' THEN visits END) AS BRAND_VISITS,
count(distinct CASE WHEN keyword_type = 'NON-BRAND' THEN visits END) AS NONB_VSTS
FROM Table1
WHERE date >= '2013-01-01'
and keyword_type in ('BRAND','NON-BRAND')
GROUP BY month
Am tempted to believe that month is simply the month from the date column, I would prefer this solution, it con cover more years than 1 and the same query will still be valid in the year 2014
SELECT cast(dateadd(month, datediff(month, 0, date), 0) as date) month,
count(distinct CASE WHEN keyword_type = 'BRAND' THEN visits END) AS BRAND_VISITS,
count(distinct CASE WHEN keyword_type = 'NON-BRAND' THEN visits END) AS NONB_VSTS
FROM Table1
WHERE date >= '2013-01-01'
and keyword_type in ('BRAND','NON-BRAND')
GROUP BY datediff(month, 0, date)
If you want to stick with your old script, you can fix it this way:
SELECT MONTH, max(BRAND_VISITS) BRAND_VISITS, max(NONB_VISITS) NONB_VISITS
FROM
(
SELECT MONTH, COUNT(DISTINCT VISITS) AS BRAND_VISITS, NULL AS NONB_VISITS
FROM Table1
WHERE KEYWORD_TYPE = 'BRAND'
AND DATE >= '2013-01-01'
GROUP BY MONTH
UNION ALL
SELECT MONTH, NULL, COUNT(DISTINCT VISITS) AS NONB_VSTS
FROM Table1
WHERE KEYWORD_TYPE = 'NON-BRAND'
AND DATE >= '2013-01-01'
GROUP BY MONTH
) a
GROUP BY MONTH

Resources