Hello,I have a small stored procedure that is doing what I believe is a fairly complex task. Maybe I'm overthinking it, but my SQL experience is rusty and limited.I have a view that pulls the data rows I need and I need to sum one of the columns [Number of Employees] WHERE the [PYear] is either the current year or last year.This is simple, you say. Yes, it would be. Except that the rows are single transactions and the [Number of Employees] is the total number of employees for a [Company]. The problem is that if a [Company] has 150 employees and there are 62 transactions, then if I SUM that column, I get 62x150 = 9300, which is obviously wrong.You say this is still not that complex, there are ways around that. Here's another twist.I need the total [Number of Employees] under a [Sales Rep] who is over multiple [Company]. And it has to be grouped by year and filtered down. And I need to do this based on input parameters (@Period_Year and @Period_Month).Hopefully some of you are saying, "That's still easy" and are correct, because that's what I said when I was building my SSRS report, but I was wrong. This SQL provides data to an SSRS DataSet.Here is what I am looking to achieve.Example resultant table data: (Sorry, I can't figure out how to paste a table in neatly)Sales Rep -- Number of Employees Previous Year -- Number of Employees Current Year Allen -- 246 -- NULL Rob -- 2585 -- 2105 Steve -- 1850 -- 1850 Mark -- 6935 -- 7894 Leah -- 44215 -- 46289 Jenny -- 200 -- 852 Jim -- 1451 -- 1398 Pat -- 9035 -- 10452 Well, here is the stored procedure and I'll let you ask questions or give recommendations on how to achieve this goal.What I need this to return is the [Sales Rep], [Number of employees Previous Year], [Number of Employees Current Year] as it is listed above.[code="sql"]ALTER PROCEDURE [dbo].[StoredProcedureName] -- Add the parameters for the stored procedure here @Period_Year nvarchar(4), @Period_Month nvarchar(2)ASBEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- Insert statements for procedure hereWITH DEDUPE AS (SELECT [Sales Rep] ,[Company] ,[Transaction Date] ,[PYear] ,[PMonth] ,[Number Of Employees] ,[Inception Date] ,[Term Date] ,ROW_NUMBER() OVER (PARTITION BY [Company] ORDER BY [Company],[Transaction Date] DESC) AS RowNum FROM [vw_ViewName] WHERE Cast([PYear] AS INT) = Cast(@Period_Year AS INT) AND [Inception Date] < DATEADD(MONTH, DATEDIFF(MONTH, -1, CONCAT(Right(@Period_Month,2), '/1/', @Period_Year))-1, -1) AND ([Term Date] > DATEADD(MONTH, DATEDIFF(MONTH, -1, CONCAT(Right(@Period_Month,2), '/1/', @Period_Year))-1, -1) OR [Term Date] IS NULL) ) SELECT [Sales Rep], SUM([Number Of Employees]) AS NumEmpCurrYear FROM DEDUPE WHERE RowNum = 1 GROUP BY [Sales Rep]END[/code]Please note that I realize the above SP only returns the current year based on the code above.The WHERE clause and SELECT after that would need to change:[code="sql"] WHERE Cast([PYear] AS INT) [b]>[/b]= Cast(@Period_Year AS INT)[b]-1[/b] AND [Inception Date] < DATEADD(MONTH, DATEDIFF(MONTH, -1, CONCAT(Right(@Period_Month,2), '/1/', @Period_Year))-1, -1) AND ([Term Date] > DATEADD(MONTH, DATEDIFF(MONTH, -1, CONCAT(Right(@Period_Month,2), '/1/', @Period_Year))-1, -1) OR [Term Date] IS NULL) ) SELECT [Sales Rep], SUM([Number Of Employees]) AS NumEmpCurrYear [b]-- I would need to add some kind of CASE WHEN here for the SUM and generate two fields, one for current and one for previous year.[/b] FROM DEDUPE WHERE RowNum = 1 GROUP BY [Sales Rep][/code]What this stored procedure does is SUMs the number of employees for each sales rep. The PARTITION BY is used to group the data by [Company] and then SUM the RowNum = 1 (basically TOP 1) of each [Company] for each [Sales Rep]. Hopefully you are able to follow.Here is a sample of a couple rows of data in raw form.SALES REP -- COMPANY -- TRANSACTION DATE -- PYEAR -- PMONTH -- Number Of EmployeesAllen -- Acme -- 2015-12-15 -- 2015 -- 12 -- 246Allen -- Acme -- 2015-11-03 -- 2015 -- 11 -- 246Mark -- Walmart -- 2016-04-01 -- 2016 -- 04 -- 7854Mark -- Walmart -- 2015-09-04 -- 2015 -- 09 -- 6916Mark -- Sql Server Central -- 2016-01-11 -- 2016 -- 01 -- 40Steve -- Home Depot -- 2015-08-04 -- 2015 -- 08 -- 1850Steve -- Home Depot -- 2016-02-25 -- 2016 -- 02 -- 1850--EDIT-- In the sample data, I did not include the Inception Date or Term Date. Let's assume the sample data is only active companies. My query filters out data that doesn't meet the Inception Date AND Term Date criteria. If you need it for testing purposes, feel free to include more sample data with those columns. --END EDIT--So the parent grouping needs to be [Sales Rep], the child grouping has to be [Company], and only one row per [Company] needs to be taken into consideration in order to get the [Number of Employees] for that [Company].But if you look at the WHERE clause, you'll see that [Inception Date] and [Term Date] are considered. This is to determine if the [Company] is active or not. So if I ran this report on 7/2016, I would not want to include data from a [Company] for 2016 if they were terminated prior to 7/2016.I know this is not the best method to do this and I think using temp tables and/or variables would be much more effective, but my experiences with these are minimal. Or at least that's what my memory tells me.I hope this is enough info and that it makes sense.Thank you.Gavin
↧