How to get year numbers in columns - sql

I need to display the number of transactions in individual years for individual employees (ID, 2011, 2012, 2013, 2014) and I should see the number of transactions in every year under years number, but now I receive this form:
How can I change it?
I think I should use WHERE, but I dont know how to do it
My current query is:
SELECT oh.SalesPersonID AS perID,
YEAR(oh.OrderDate) AS [Year], COUNT(*)
FROM Sales.SalesOrderHeader oh
JOIN Person.Person per ON oh.SalesPersonID = per.BusinessEntityID
GROUP BY SalesPersonID, YEAR(OrderDate)
ORDER BY perID, [Year];

Just use conditional aggregation:
SELECT oh.SalesPersonID AS perID,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2011 THEN 1 ELSE 0 END) as cnt_2011,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2012 THEN 1 ELSE 0 END) as cnt_2012,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2013 THEN 1 ELSE 0 END) as cnt_2013,
SUM(CASE WHEN YEAR(oh.OrderDate) = 2014 THEN 1 ELSE 0 END) as cnt_2014
FROM Sales.SalesOrderHeader oh JOIN
Person.Person per
ON oh.SalesPersonID = per.BusinessEntityID
GROUP BY SalesPersonID
ORDER BY perID;

Related

BigQuery: group counters by month after self-join

I have table that looks like this:
I'm trying to build a query, that will show specific partnerId counters groupped by keywordName and month.
To solve first part(without grouping by month), I've built this query:
SELECT keywordName, COUNT(keywordName) as total, IFNULL(b.ebay_count, 0) as ebay, IFNULL(c.amazon_count, 0) as amazon,
FROM LogFilesv2_Dataset.FR_Clickstats_v2 a
LEFT JOIN
(SELECT keywordName as kw , SUM(CASE WHEN partnerId='eBay' THEN 1 ELSE 0 END) as ebay_count
FROM LogFilesv2_Dataset.FR_Clickstats_v2
WHERE partnerId = 'eBay' GROUP BY kw) b
ON keywordName = b.kw
LEFT JOIN
(SELECT keywordName as kw , SUM(CASE WHEN partnerId='AmazonApi' THEN 1 ELSE 0 END) as amazon_count
FROM LogFilesv2_Dataset.FR_Clickstats_v2
WHERE partnerId = 'AmazonApi' GROUP BY kw) c
ON keywordName = c.kw
WHERE keywordName = 'flipper' -- just to filter out single kw.
GROUP BY keywordName, ebay, amazon
It works quite well and returns following output:
Now I'm trying to make additional group by month, but all my attempts returned incorrect results.
Final output supposed to be similar to this:
You can do this with conditional aggregation:
select
date_trunc(dt, month) dt,
keywordName,
count(*) total,
sum(case when partnerId = 'eBay' then 1 else 0 end) ebay,
sum(case when partnerId = 'AmazonApi' then 1 else 0 end) amazon
from LogFilesv2_Dataset.FR_Clickstats_v2
group by date_trun(dt, month), keywordName

Add a column to a multiple SELECT SQL query string

The below code works, but I want to add the column "segvalue1" to my query result:
SELECT (SELECT SUM(DebitAmount-CreditAmount) as BalanceAmtCYTD
FROM GLJrnDtl WITH (NOLOCK) WHERE FiscalPeriod between 1 AND 10
AND Company = 'NVV' AND FiscalYear = 2017),
(SELECT SUM(DebitAmount-CreditAmount) as BalanceAmtCYM
FROM GLJrnDtl WITH (NOLOCK) WHERE FiscalPeriod = 10
AND Company = 'NVV' AND FiscalYear = 2017)
So I modified the code to look like the below but it gives me 2 "Only one expression can be specified in the select list when the subquery is not introduced with EXISTS" errors :
SELECT (SELECT SUM(DebitAmount-CreditAmount) as BalanceAmtCYTD,
segvalue1 FROM GLJrnDtl WITH (NOLOCK) WHERE FiscalPeriod
between 1 AND 10 AND Company = 'NVV' AND FiscalYear = 2017
GROUP BY segvalue1),
(SELECT SUM(DebitAmount-CreditAmount) as BalanceAmtCYM,
segvalue1 FROM GLJrnDtl WITH (NOLOCK) WHERE FiscalPeriod = 10
AND Company = 'NVV' AND FiscalYear = 2017
GROUP BY segvalue1)
Does anyone know how to modify the code to get my desired result? Again, I am just trying to pull in the segvalue1 column. Once I figure this out, I will also pull in a couple more columns. Thanks for your help!
Consider conditional aggregation:
SELECT segvalue1,
SUM(CASE WHEN FiscalPeriod BETWEEN 1 AND 10
THEN DebitAmount-CreditAmount
ELSE NULL
END) as BalanceAmtCYTD,
SUM(CASE WHEN FiscalPeriod = 10
THEN DebitAmount-CreditAmount
ELSE NULL
END) as BalanceAmtCYM
FROM GLJrnDtl WITH (NOLOCK)
WHERE Company = 'NVV' AND FiscalYear = 2017 -- SHARED CONDITION
GROUP BY segvalue1

Difference between COUNT and SUM within an Aggregate CASE statement

Full disclosure, I am learning and I have searched all over the internet and I just can't figure out my question.
I am working on an online class and was given the following example:
select
DATENAME(MONTH, DATEADD(MONTH, MONTH(OrderDate), -1)) AS 'Month',
SUM(CASE WHEN YEAR(OrderDate) = 2005 THEN 1 ELSE 0 END) AS Orders,
SUM(CASE YEAR(OrderDate) WHEN 2005 THEN Totaldue ELSE 0 END) AS 'Total Value'
from
sales.salesorderheader
group by Month(orderdate)
order by Month(orderdate) ASC
That returns the following results:
I understood that (I thought) so I began messing around with the code to further understand Case statements. Looking at the code I thought that the Orders field was essentially finding all the orders in a month, assigning a 1 to each one, and then adding them all up. Because each one was assigned a 1 I figured that I could change the SUM to COUNT and I would get the same results.
However, this code:
select
DATENAME(MONTH, DATEADD(MONTH, MONTH(OrderDate), -1)) AS 'Month',
COUNT(CASE WHEN YEAR(OrderDate) = 2005 THEN 1 ELSE 0 END) AS Orders,
SUM(CASE YEAR(OrderDate) WHEN 2005 THEN Totaldue ELSE 0 END) AS 'Total Value'
from
sales.salesorderheader
group by Month(orderdate)
order by Month(orderdate) ASC
Returns these results:
To try and break this down I created a query that would just look for the orders in January 2005 and count them.
SELECT COUNT(*)
FROM Sales.SalesOrderHeader
WHERE OrderDate >= '1/1/2005' AND OrderDate < '1/1/2005'
This returned 0. The same as the SUM query. I get that COUNT counts rows and SUM sums numbers in a column, but I just don't understand the results I'm getting. Could someone please explain why the count query is returning 2483 for January and not 0?
For COUNT 1 and 0 are the same. What you really need is NULL:
COUNT(ALL expression) evaluates expression for each row in a group and returns the number of nonnull values.
select
DATENAME(MONTH, DATEADD(MONTH, MONTH(OrderDate), -1)) AS 'Month',
COUNT(CASE WHEN YEAR(OrderDate) = 2005 THEN 1 ELSE NULL END) AS Orders,
SUM(CASE YEAR(OrderDate) WHEN 2005 THEN Totaldue ELSE 0 END) AS 'Total Value'
from sales.salesorderheader
group by Month(orderdate)
order by Month(orderdate) ASC;
Or even shorter(default ELSE is NULL so we could omit that part)
COUNT(CASE WHEN YEAR(OrderDate) = 2005 THEN 1 END) AS Orders,
Example:
SUM COUNT COUNT
2005 1 1 1
2006 0 0 NULL
2007 0 0 NULL
2005 1 1 1
===============================================
2 4 2
When you use count(*) you count ALL the rows. If you want to count how many orders you have, you have to use a column: eg: count(OrderDate). Try it
count example:
assume that your column has 3 value and column name is the order
2 ---------- 5 ---------- 4----- Null
now if you run
count (order)
it will return = 3 how many entries you have in the column without null
sum example:
2 ---------- 5 ---------- 4
now if you run
sum (order)
it will return = 2+5+4=11 its add all the entries

sorting month in ascending order

I have looked at related Qs on Stack.
I am trying to sort my query to display month in ascending order. A similar post on Stack said that I must indicate "ASC", but this doesn't work for me. I have written an Order By. I cannot figure out why it is not working.
SELECT DATENAME( MONTH,(Submission.SubmissionDate)) AS [Date]
FROM Submission
GROUP BY DATENAME( MONTH,(Submission.SubmissionDate)) ORDER BY [Date] ASC;
This is the output:
Month
August
February
September
Note: this is just a part of my query, I didnt think it would necessary to show the rest, which relates to other attributes from my table (Not month related)
Edit: This is my Entire Query: (The Initial One)
SELECT DATENAME( MONTH,(Submission.SubmissionDate)) AS [Date],
SUM( CASE WHEN Submission.Status='Under review' THEN 1 ELSE 0 END) [Under_Review],
SUM( CASE WHEN Submission.Status='Accepted' THEN 1 ELSE 0 END) [Accepted],
SUM( CASE WHEN Submission.Status='Rejected' THEN 1 ELSE 0 END) [Rejected],
SUM( CASE WHEN Submission.Status='In print' THEN 1 ELSE 0 END) [In_print],
SUM( CASE WHEN Submission.Status='Published' THEN 1 ELSE 0 END) [Published]
FROM Submission INNER JOIN ((Faculty INNER JOIN School ON Faculty.FacultyID = School.[FacultyID]) INNER JOIN (Researcher INNER JOIN ResearcherSubmission ON Researcher.ResearcherID = ResearcherSubmission.ResearcherID) ON School.SchoolID = Researcher.SchoolID) ON Submission.SubmissionID = ResearcherSubmission.SubmissionID
GROUP BY DATENAME( MONTH,(Submission.SubmissionDate))
ORDER BY DATENAME( MONTH,(Submission.SubmissionDate));
SELECT DATENAME( MONTH, Submission.SubmissionDate) AS [Date]
FROM Submission
ORDER BY datepart(mm,Submission.SubmissionDate)
You don't need a group by (for the query shown). Also, when you order by month name it would return results in the alphabetical order of month name. You should not use previously defined aliases in the where,order by having and group by clauses.
Edit: The problem is with the join conditions. You should correct them as per the comments in line.
SELECT DATENAME( MONTH,(Submission.SubmissionDate)) AS [Date],
SUM( CASE WHEN Submission.Status='Under review' THEN 1 ELSE 0 END) [Under_Review],
SUM( CASE WHEN Submission.Status='Accepted' THEN 1 ELSE 0 END) [Accepted],
SUM( CASE WHEN Submission.Status='Rejected' THEN 1 ELSE 0 END) [Rejected],
SUM( CASE WHEN Submission.Status='In print' THEN 1 ELSE 0 END) [In_print],
SUM( CASE WHEN Submission.Status='Published' THEN 1 ELSE 0 END) [Published]
FROM Faculty
INNER JOIN School ON Faculty.FacultyID = School.[FacultyID]
INNER JOIN Researcher ON School.SchoolID = Researcher.SchoolID
INNER JOIN ResearcherSubmission ON Researcher.ResearcherID = ResearcherSubmission.ResearcherID
INNER JOIN SUBMISSION ON Submission.SubmissionID = ResearcherSubmission.SubmissionID
GROUP BY DATENAME( MONTH,(Submission.SubmissionDate))
ORDER BY DATEPART( MONTH,(Submission.SubmissionDate))
A simple option is to add MONTH(Submission.SubmissionDate) to your group by clause, and order by that as well:
SELECT DATENAME( MONTH,(Submission.SubmissionDate)) AS [Date]
FROM Submission
GROUP BY MONTH(Submission.SubmissionDate), DATENAME( MONTH,(Submission.SubmissionDate))
ORDER BY MONTH(Submission.SubmissionDate)
This will work for your real query as well.
You can use MIN() or MAX():
SELECT DATENAME(MONTH,(Submission.SubmissionDate)) AS [Date]
FROM Submission
GROUP BY DATENAME(MONTH,(Submission.SubmissionDate))
ORDER BY MIN([Date]) ASC;
This chooses an arbitrary date from each group and orders by that.
By the way, you probably should care about the year as well as the month. If so:
SELECT YEAR(s.SubmissionDate), DATENAME(MONTH, s.SubmissionDate) AS [Date]
FROM Submission s
GROUP BY YEAR(s.SubmissionDate), DATENAME(MONTH, s.SubmissionDate)
ORDER BY MIN([Date]) ASC;

Annual Count by Criteria

I am working on a project with our HR department.
I have a table called [EEMaster] that keeps a record of the Active/Termed employees.
It is updated from a flat File using a Slowly Changing Dimension.
At the end of the year I need a count of the number of Active employees and the number of termed employees and then the year.
Here is an example of the data I need returned annually.
| 2010 | 2011 | 2012 | 2013 |
HistoricalHC | 447 | 419 | 420 | 418 |
NumbTermEmp | 57 | 67 | 51 | 42 |
I currently have the data connected to an excel spreadsheet providing a rolling count by Division. I use the following columns from the [EEMaster] for it.
ChangeStatus (1/0 from the SCD)
EmpStatusName ("Active" for current employees and "Withdrawn" for Termed Employees)
HireYear (set to All in the pivot table)
Term Year (set to 2013 in the pivot table)
PONumb (The employee numbers, I use for the count)
I have created a table to input the data into, I will manually load the previous years (counts)into the table since the current development is a rolling number. What I want to do is to develop an SSIS package that will capture the count on Jan 1 of 2014 and insert the # of "Active Employees", "Termed Employees" and the Year that just finished into a table.
UPDATE:
I have created two queries. One that provides the number of Active Employees
SELECT COUNT([PersNo]) AS HistoricalHC
FROM [dbo].[EEMaster]
WHERE [ChangeStatus] = 'Current' AND [EmpStatusName] = 'Active'
it returns
|HistoricHC|
|418 |
And another that provides the number of terms by Term Year
SELECT COUNT([PersNo]) AS NumbOfTermEE
FROM [dbo].[EEMaster]
WHERE [ChangeStatus] = 'Current' AND [EmpStatusName] = 'Withdrawn'
AND [TermYear] = '2013'
it returns
|NumbOfTermEE|
|42 |
I need the [TermYear] to be dynamic. Since this will run on Jan 1st of every year. It would need to pull the number of terms for the previous year (continually).
Then I need both of these numbers to be added into the new row with the year the data was calculated.
|Year|HistoricalHC|NumbOfTermEmp|
|2010|447 |57 |
|2011|419 |67 |
|2012|420 |51 |
|2013|418 |42 |
You are looking for a syntax of a case expression that does an aggregate to add a few for different things.
Sum(Case when (expression) then 1 end)
You also want to group by year it seems in the columns so you can easily pivot on that. You mention dynamic but I don't really know if you need to get much dynamic for just the year logic. I am not really getting if you want a SQL statement to go in a data flow to generate an output of an Excel sheet or not. Basically if you want just a grid with one row being one set of conditions and another being another. I would do a 'union' of two or more selects as long as it is not too large it should not be that hard. Here is a simple self extracting example with dummy data to see what I mean more.
It will run as is in SQL Management Studio 2005 and up.
declare #Person Table ( personID int identity, person varchar(8));
insert into #Person values ('Brett'),('Sean'),('Chad'),('Michael'),('Ray'),('Erik'),('Queyn');
declare #Orders table ( OrderID int identity, PersonID int, OrderCnt int, dt Date);
insert into #Orders values (1, 10, '1-7-11'),(1, 12, '2-12-12'),(2, 20, '7-1-13'),(2, 12, '1-5-10'),(3, 20, '6-4-11')
,(3, 12, '2-3-10'),(3, 6, '6-10-10'),(4, 20, '7-10-11'),(5, 20, '1-8-10'),(5, 9, '2-10-11'),
(6, 20, '3-1-11'),(6, 34, '4-6-12'),(7, 20, '5-1-11'),(7, 12, '6-8-12'),(7, 56, '7-25-13')
-- As is just joining sets
select *
from #Person p
join #Orders o on p.personID = o.PersonID
order by dt
-- Years on the rows
select
year(o.dt) as Year
, sum(o.OrderCnt) as Orders
, count(p.personID) as People
, count(distinct p.personID) as DistinctPeople
from #Person p
join #Orders o on p.personID = o.PersonID
group by year(o.dt)
-- Custom grouping on rows and doing the years with pivots for the columns
Select
'BulkOrders' as Description
, sum(case when year(o.dt) = '2010' then OrderCnt end) as [2010Orders]
, sum(case when year(o.dt) = '2011' then OrderCnt end) as [2011Orders]
, sum(case when year(o.dt) = '2012' then OrderCnt end) as [2012Orders]
, sum(case when year(o.dt) = '2013' then OrderCnt end) as [2013Orders]
, sum(OrderCnt) as Totals
from #Person p
join #Orders o on p.personID = o.PersonID
union
select
'OrdersByPerson'
, Count(case when year(o.dt) = '2010' then p.personID end)
, Count(case when year(o.dt) = '2011' then p.personID end)
, Count(case when year(o.dt) = '2012' then p.personID end)
, Count(case when year(o.dt) = '2013' then p.personID end)
, Count(p.personID)
from #Person p
join #Orders o on p.personID = o.PersonID
union
select
'OrdersByPersonDistinct'
, Count(distinct case when year(o.dt) = '2010' then p.personID end)
, Count(distinct case when year(o.dt) = '2011' then p.personID end)
, Count(distinct case when year(o.dt) = '2012' then p.personID end)
, Count(distinct case when year(o.dt) = '2013' then p.personID end)
, Count(distinct p.personID)
from #Person p
join #Orders o on p.personID = o.PersonID
Here is the solution I cam up with.
I will create an SSIS package that will run the following Stored Procedure.
INSERT INTO [dbo].[TORateFY] (Year,HistoricalHC,NumbTermedEmp)
SELECT DISTINCT YEAR(GETDATE()) AS [Year],
SUM(CASE WHEN EmpStatusName = 'Active' THEN 1 ELSE 0 END) AS HistoricalHC,
SUM(CASE WHEN EmpStatusName = 'Withdrawn' AND TermYear = YEAR(GETDATE()) THEN 1 ELSE 0 END) AS NumbOfTermEE
FROM dbo.EEMaster
This will be scheduled to run Annually on the 31st of Dec.
Update to my previous Answer:
I worked with a guy on another forum and he provided an excellent script that will give the correct count for both the active and termed employees on a monthly basis instead of waiting until the end of the year to get an overall count. This puts the reporting more inline with what was originally done manually.
MERGE dbo.TORateFY AS tgt
USING (
SELECT DATENAME(YEAR, GETDATE()) AS [Year],
SUM(CASE WHEN EmpStatusName = 'Active' THEN 1 ELSE 0 END) AS HistoricalHC,
SUM(CASE WHEN EmpStatusName = 'Withdrawn' AND TermYear = DATENAME(YEAR,
GETDATE()) THEN 1 ELSE 0 END) AS NumbOfTermEE
FROM dbo.EEMaster
WHERE ChangeStatus = 'Current'
AND EmpStatusName IN ('Active', 'Withdrawn')
OR TermYear <= DATENAME(YEAR, GETDATE())
) AS src ON src.[Year] = tgt.[Year]
WHEN MATCHED
THEN UPDATE
SET tgt.HistoricalHC = src.HistoricalHC,
tgt.NumbTermedEmp = src.NumbOfTermEE
WHEN NOT MATCHED BY TARGET
THEN INSERT (
[Year],
HistoricalHC,
NumbTermedEmp
)
VALUES (
src.[Year],
src.HistoricalHC,
src.NumbOfTermEE
);
I wanted to share the in case anyone else ran into a similar situation.
Thank you everyone for your input and guidance.