Is there a way to split sql results by year? - sql

I currently have the following SQL statement:
SELECT
[Manager].[Name],
COUNT([Project].[ProjectId]) AS TotalProjects
FROM
([Project]
INNER JOIN
[Manager] ON [Project].[ManagerId] = [Manager].[ManagerId])
WHERE
[Project].[CurrentStatusId] = 5
GROUP BY
[Manager].[Name]
It currently spits out total projects by each manager. I would like to have it split the projects out by the years they were completed. So basically count the total projects for each manager for each year (2016, 2017, and so on), as well as the total projects all time. I can use the column [Project].[CurrentStatusDt] for the date.

Just add the project year to the SELECT and GROUP BY clauses:
SELECT
[Manager].[Name],
YEAR([Project].[CurrentStatusDt]) PojectYear,
COUNT([Project].[ProjectId]) AS TotalProjects
FROM [Project]
INNER JOIN [Manager] ON [Project].[ManagerId] = [Manager].[ManagerId]
WHERE [Project].[CurrentStatusId] = 5
GROUP BY [Manager].[Name], YEAR([Project].[CurrentStatusDt])
Side note: you don't need parentheses around the joins in SQL Server (this is a MS Access limitation).
EDIT
If you want to spread the years over columns instead of rows, then one solution is to use conditional aggregation
SELECT
[Manager].[Name],
SUM(CASE
WHEN [Project].[CurrentStatusDt] < CAST('2019-01-01' AS DATE)
THEN 1
ELSE 0
END) TotalProjects2018,
SUM(CASE
WHEN [Project].[CurrentStatusDt] >= CAST('2019-01-01' AS DATE)
THEN 1
ELSE 0
END) TotalProjects2019
FROM [Project]
INNER JOIN [Manager] ON [Project].[ManagerId] = [Manager].[ManagerId]
WHERE
[Project].[CurrentStatusId] = 5
AND [Project].[CurrentStatusDt] >= CAST('2018-01-01' AS DATE)
AND [Project].[CurrentStatusDt] < CAST('2020-01-01' AS DATE)
GROUP BY [Manager].[Name]

Related

SQL help to display no. of openings for all branches for each month of a year

Hi I need to generate a SSRS report to show how many centers got opened for each month in a calendar year under each branch. report will have 13 columns, first column being all the branches in each row and remaining 12 columns will have months of an year as header. I'm trying to get a result of each branch having no. of openings per month, so I can feed SSRS to display in tabular format. If a branch doesnt have any openings for any month, I need to display 0.
Branch table
=============
Branchid
Branchname
CenterOpen table
================
CenterOpenID
BranchID
CenterOpenDate
below is the SQL I had written
WITH months(MonthNumber) AS (
SELECT
1
UNION ALL
SELECT
MonthNumber + 1
FROM
months
WHERE
MonthNumber < 12
),
cteBranch(BranchID, BranchName, TargetOpenDate, Month, Count) as (
SELECT
B.BranchID,
B.BranchName,
CS.TargetOpenDate,
MONTH(CS.TargetOpenDate) as Month,
count(Month(CS.TargetOpenDate)) as Count
FROM
Branch B
left join goal.CenterOpenSchedule CS ON CS.BranchID = B.BranchID
GROUP BY
B.BranchID,
B.BranchName,
CS.TargetOpenDate,
MONTH(CS.TargetOpenDate)
)
select
*
from
months
cross join cteBranch
order by
BranchID asc,
MonthNumber asc
If I use cross join, months are repeating for each branch, how to resolve this? your help is highly appreciated.
Not sure which database you are on.
There are different ways to extract month/year from date.
Based on your example SQL, I'm going to use MONTH()
select branchName,
count(case when month(centerOpenDate) = 1 then branchId end) Jan_Count
...
...
count(case when month(centerOpenDate) = 12 then branchId end) Dec_Count
from Branch b
join CenterOpen co
on (b.BranchId = co.BranchId)
where year(centerOpenDate) = <your year filter>
group by branchName
This will take care of your below requirements:
" first column being all the branches in each row and remaining 12 columns will have months of an year as header."
and also -
"If a branch doesnt have any openings for any month, I need to display 0."
Your question is not explicit, but you seem to want a single year -- so you need to filter on the year.
The rest is basically conditional aggregation:
select b.branchName,
sum(case when month(co.centerOpenDate) = 1 then 1 else 0 end) as jan,
sum(case when month(co.centerOpenDate) = 2 then 1 else 0 end) as feb,
. . .
sum(case when month(co.centerOpenDate) = 12 then 1 else 0 end) as dec
from Branch b join
CenterOpen co
on b.BranchId = co.BranchId
where year(co.centerOpenDate) = #year
group by b.branchName

How to filter Users that meet CASE criteria without nesting WHERE in SQL?

Right now I have a query that lets me know which users didn't make a purchase 12 months prior to becoming members. These users have MEM_PRE_12=0 and I want to filter off those users more natively using SQL partitions rather than always putting rudimentary WHERE criteria.
Here is the SQL I use to find the users I want/don't want.
SELECT SUM(CASE WHEN DATE <= DATEADD(month, -12, U.INSERTED_AT) THEN 1 ELSE 0 END) AS MEM_PRE_12, I.CLIENTID, I.INSTALLATIONID
FROM <<<My_Joined_Tables>>>
GROUP BY I.CLIENTID, I.INSTALLATIONID
HAVING MEM_PRE_12 != 0
ORDER BY MEM_PRE_12
After this I'm going to have to go back and say where I.CLIENTID in the above nested query and select the actual information I want from users who made purchases greater than their insertion date.
How can I do this without so much nesting of all these joined tables?
If you want the detailed rows for customers who made a purchase in the last 12 months, you can use window functions:
with q as (
<whatever your query logic is>
)
select q.*
from (select q.*,
SUM(CASE WHEN DATE <= DATEADD(month, -12, U.INSERTED_AT) THEN 1 ELSE 0 END) over (partition by CLIENTID, INSTALLATIONID) as AS MEM_PRE_12
from q
) q
where mem_pre_12 > 0;

Select Records against all months of a given year form one table with records from second table

I have two tables in my database:
MembershipInstallments (ProjectId, AllotmentId, InstallmentId, EntryDate, AmountPaid)
Memberships (ProjectId, AllotmentId, ClientId, ClientName, RegistrationNo)
I want to select month wise payments made by a clients in a year. And also amount paid before the start of that year. My desired result set is
Let's say for the year 2019:
ClientName, RegistrationNumbers, PreviouslyPaidAmount (i.e. all amounts paid in 2018), AmountPaidInJuly 2019, AmountPaidInAugust2019. ..... AmountPaidIn Jun2020
where month is EntryDate from MembershipInstallments table.
I tried it like this, but it takes too long for large data set:
SELECT
ClientName, RegistrationNo,
(SELECT ISNULL(SUM(AmountPaid),0)
FROM MembershipInstallments
WHERE ProjectId = Membership.ProjectId
AND AllotmentId = Membership.AllotmentId
AND EntryDate < #fromDate) ASPreviouslyPaid,
(SELECT ISNULL(SUM(AmountPaid), 0)
FROM MembershipInstallments
WHERE ProjectId = Membership.ProjectId
AND AllotmentId = Memberhsip.AllotmentId
AND (MONTH(EntryDate) = 7) AND (YEAR(EntryDate) = YEAR(#fromDate)) AS JulyPayment
FROM
Memberships
WHERE
ProjectId = #projectId
Any help will be highly appreciated.
Scalar Subqueries tend to be badly optimized. In your case (same join-conditions) you can simply utilize conditional aggregation:
SELECT ms.ClientName,ms.RegistrationNo,
Sum(CASE WHEN mi.EntryDate<#fromDate THEN mi.AmountPaid ELSE 0 end) AS PreviouslyPaid,
Sum(CASE WHEN (Month(mi.EntryDate) = 7) AND (Year(mi.EntryDate) = Year(#fromDate)) THEN mi.AmountPaid ELSE 0)
FROM Memberships AS ms
LEFT JOIN MembershipInstallments AS mi -- don't know if Outer join is really needed
ON mi.ProjectId=ms.ProjectId
AND mi.AllotmentId=ms.AllotmentId
WHERE ms.ProjectId=#projectId
You might be able to do the aggregation before the join, i.e. in a CTE to further improve performance:
WITH cte AS
(
SELECT
ProjectId, AllotmentId,
Sum(CASE WHEN EntryDate<#fromDate THEN AmountPaid ELSE 0 END) AS PreviouslyPaid,
Sum(CASE WHEN (Month(EntryDate) = 7) AND (Year(EntryDate) = Year(#fromDate)) THEN AmountPaid ELSE 0 END) AS JulyPayment
FROM MembershipInstallments
WHERE ProjectId=#projectId
GROUP BY ProjectId, AllotmentId
)
SELECT ms.ClientName, ms.RegistrationNo, cte.PreviouslyPaid, cte.JulyPayment
FROM Memberships AS ms
JOIN cte
ON cte.ProjectId=ms.ProjectId
AND cte.AllotmentId=ms.AllotmentId
WHERE ms.ProjectId=#projectId
In both cases double-check if the result is correct (depends on the actual relation between those tables)

how to return total sold p / year for several years in columnar format?

The SQL below give me the columns for Account, Name and the Total Sale for the year of 2015.But how, if possible, can I add another column for the previous year of 2014 ?
select a.AcctNo, b.Name, Sum(a.TotSold) as [ Total Sold ]
from Orders as A
Join Accounts as b on a.AcctNo = b.AcctNo
where (a.PurchaseDate between '1/1/2015' and '12/31/2015' )
Group by a.AcctNo, b.Name
You can use conditional aggregation:
select o.AcctNo, a.Name,
Sum(case when year(PurchaseDate) = 2015 then TotSold else 0 end) as tot_2015,
Sum(case when year(PurchaseDate) = 2014 then TotSold else 0 end) as tot_2014
from Orders o Join
Accounts a
on a.AcctNo = o.AcctNo
where PurchaseDate >= '2014-01-01'
PurchaseDate < '2016-01-01'
Group by o.AcctNo, a.Name ;
Notes:
Use ISO standard formats for date constants.
When using dates, try not to use between. It doesn't work as expected when there is a time component. The above inequalities work regardless of a time component.
Use table aliases that are abbreviations of the table name. That makes the query easier to follow.

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.