i want to calculate sum of leaverequested column month wise - mysql

empid leavefrom leaveto leaverequested
1 3/3/2014 4/3/2014 2
1 7/3/2014 8/3/2014 2
1 31/3/2014 1/4/2014 2
1 10/4/2014 11/4/2014 2
I want to calculate the sum of the leaverequested column.
Ouput:
march - 5 days
april - 3 days
This is my SQL query so far:
select Emp_id
,datename(month,leave_from) as [First]
,datename(month,leave_to) as Last
,count(DATEDIFF(Day, leave_from, leave_to)+1) as [Total Leave]
,sum(DATEDIFF(Day, leave_from, leave_to)+1) as [Total Days]
from emp_leave
group by Emp_id
,datename(month,leave_from)
,datename(month,leave_to);
Can any one help me to get this output please?

One way to go about it
WITH n AS
(
SELECT 0 n
UNION ALL
SELECT n + 1 FROM n WHERE n < 32 -- adjust as needed to max months that a leave can possibly span
), base AS
(
SELECT empid,
DATEADD(mm, n.n, DATEADD(mm, DATEDIFF(mm, 0, leavefrom), 0)) basemonth,
CASE WHEN leavefrom > DATEADD(mm, n.n, DATEADD(mm, DATEDIFF(mm, 0, leavefrom), 0))
THEN leavefrom
ELSE DATEADD(mm, n.n, DATEADD(mm, DATEDIFF(mm, 0, leavefrom), 0))
END sdate,
CASE WHEN leaveto < DATEADD(mm, n.n, DATEADD(mm, DATEDIFF(mm, 0, leavefrom) + 1, -1))
THEN leaveto
ELSE DATEADD(mm, n.n, DATEADD(mm, DATEDIFF(mm, 0, leavefrom) + 1, -1))
END edate
FROM emp_leave JOIN n
ON n.n <= DATEDIFF(month, leavefrom, leaveto)
)
SELECT empid,
YEAR(basemonth) year,
DATENAME(mm, basemonth) month,
SUM(DATEDIFF(dd, sdate, edate) + 1) total
FROM base
GROUP BY empid, basemonth
ORDER BY empid, base month
Output:
| EMPID | YEAR | MONTH | TOTAL |
|-------|------|-------|-------|
| 1 | 2014 | March | 5 |
| 1 | 2014 | April | 3 |
Here is SQLFiddle demo

Related

Generate dynamic custom intervals

I am working on a project that requires reports that can dynamically group the source data on non-standard user defined intervals such as Production Shifts within a specified start and end range. Example user may want to see production information group by shift for the last two days.
I created a table called ‘IntervalConfiguration’ that stores the configuration information required to create the grouping intervals with data as follow:
IntervalType SubIntervalType IntervalDuration IntervalDurationUnits IntervalStartReferenceTime IntervalRepeatDuration IntervalRepeatDurationUnits
------------------------- ------------------- -------------------- --------------------- -------------------------- ---------------------- ---------------------------
Production Day ProductionDay 1 Days 2013-01-07 07:00:00.000 1 Days
Production Month ProductionMonth 1 Months 2013-01-01 07:00:00.000 1 Months
Production Week ProductionWeek 1 Weeks 2013-01-07 08:45:00.000 1 Weeks
Production Year ProductionYear 1 Years 2013-01-01 08:45:00.000 1 Years
Site A - Production Shift Day 12 Hours 2013-01-06 07:00:00.000 24 Hours
Site A - Production Shift Night 12 Hours 2013-01-06 19:00:00.000 24 Hours
Site B - Production Shift Day 12 Hours 2013-01-06 06:45:00.000 24 Hours
Site B - Production Shift Night 12 Hours 2013-01-06 18:45:00.000 24 Hours
If a user selects ‘Site A - Production Shift’ as the grouping interval on the report and a start date of '01/01/2018' and end date of '01/05/2018' then the report has to create grouping intervals for day shifts where day shifts start at 7AM and ends at 7PM and night shift where night shift start at 7PM and ends at 7AM the next day.
Also, only grouping intervals completely contained within the start and end date should be returned. Below is an example of expected grouping intervals for the scenario described.
SubIntervalType IntervalStart IntervalEnd
---------------- ----------------------- -----------------------
Day 2018-01-01 07:00:00.000 2018-01-01 19:00:00.000
Night 2018-01-01 19:00:00.000 2018-01-02 07:00:00.000
Day 2018-01-02 07:00:00.000 2018-01-02 19:00:00.000
Night 2018-01-02 19:00:00.000 2018-01-03 07:00:00.000
Day 2018-01-03 07:00:00.000 2018-01-03 19:00:00.000
Night 2018-01-03 19:00:00.000 2018-01-04 07:00:00.000
Day 2018-01-04 07:00:00.000 2018-01-04 19:00:00.000
If user selects Production Month as the grouping interval with a start date of '01/01/2018' and end date of '01/01/2019' then the report should generate the following grouping intervals.
SubIntervalType IntervalStart IntervalEnd
----------------- ----------------------- -----------------------
ProductionMonth 2018-01-01 07:00:00.000 2018-02-01 07:00:00.000
ProductionMonth 2018-02-01 07:00:00.000 2018-03-01 07:00:00.000
ProductionMonth 2018-03-01 07:00:00.000 2018-04-01 07:00:00.000
ProductionMonth 2018-04-01 07:00:00.000 2018-05-01 07:00:00.000
ProductionMonth 2018-05-01 07:00:00.000 2018-06-01 07:00:00.000
ProductionMonth 2018-06-01 07:00:00.000 2018-07-01 07:00:00.000
ProductionMonth 2018-07-01 07:00:00.000 2018-08-01 07:00:00.000
ProductionMonth 2018-08-01 07:00:00.000 2018-09-01 07:00:00.000
ProductionMonth 2018-09-01 07:00:00.000 2018-10-01 07:00:00.000
ProductionMonth 2018-10-01 07:00:00.000 2018-11-01 07:00:00.000
ProductionMonth 2018-11-01 07:00:00.000 2018-12-01 07:00:00.000
I have started building the following table valued function to dynamically create the desired grouping intervals.
CREATE FUNCTION [dbo].[GetIntervals]
(
#dateRangeStart datetime,
#dateRangeEnd datetime,
#groupByInterval NVARCHAR(200)
)
RETURNS #Intervals TABLE (
IntervalType NVARCHAR(100)
,SubIntervalType NVARCHAR(100)
,IntervalStart DATETIME
,IntervalEnd DATETIME
,IntervalDurationSeconds FLOAT
)
AS
BEGIN
DECLARE #activeIntervalDateTime DATETIME = DATEADD(millisecond, 3, #dateRangeStart);
DECLARE #intervalStartTime DATETIME = DATEADD(s, 1, #dateRangeStart);
DECLARE #intervalEndTime DATETIME = DATEADD(s, 1, #dateRangeStart);
DECLARE #intervalDurationSeconds FLOAT;
DECLARE #intervalName NVARCHAR(100);
DECLARE #subIntervalType NVARCHAR(100);
WHILE #intervalStartTime <= #dateRangeEnd
BEGIN
SELECT TOP 1
#intervalName = IntervalType ,#subIntervalType = SubIntervalType , #intervalStartTime = IntervalStart, #intervalEndTime = IntervalEnd
FROM (SELECT IntervalType, SubIntervalType, IntervalDuration, IntervalDurationUnits,
IntervalRepeatDuration, IntervalRepeatDurationUnits,
CASE IntervalRepeatDurationUnits
WHEN 'Hours' THEN (DateAdd(HH, (DateDiff(HH, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration, IntervalStartReferenceTime))
WHEN 'Days' THEN (DateAdd(D, (DateDiff(D, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration, IntervalStartReferenceTime))
WHEN 'Months'THEN (DateAdd(MM, (DateDiff(MM, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration, IntervalStartReferenceTime))
END AS IntervalStart,
CASE IntervalRepeatDurationUnits
WHEN 'Hours' THEN (DateAdd(HH, IntervalDuration, DateAdd(HH, (DateDiff(HH, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration, IntervalStartReferenceTime)))
WHEN 'Days' THEN
CASE IntervalDurationUnits
WHEN 'Hours' THEN (DateAdd(HH, IntervalDuration, DateAdd(D, (DateDiff(D, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration, IntervalStartReferenceTime)))
WHEN 'Days' THEN (DateAdd(D, IntervalDuration, DateAdd(D, (DateDiff(D, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration, IntervalStartReferenceTime)))
END
WHEN 'Months'THEN
CASE IntervalDurationUnits
WHEN 'Hours' THEN (DateAdd(HH, IntervalDuration, DateAdd(MM, (DateDiff(MM, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration, IntervalStartReferenceTime)))
WHEN 'Days' THEN (DateAdd(D, IntervalDuration, DateAdd(MM, (DateDiff(MM, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration, IntervalStartReferenceTime)))
WHEN 'Months' THEN (DateAdd(MM, IntervalDuration, DateAdd(MM, (DateDiff(MM, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration, IntervalStartReferenceTime)))
END
END AS IntervalEnd
,IntervalStartReferenceTime
FROM (
SELECT IntervalType, SubIntervalType, IntervalDuration, IntervalDurationUnits, IntervalRepeatDuration, IntervalRepeatDurationUnits, IntervalStartReferenceTime,
CASE IntervalRepeatDurationUnits
WHEN 'Hours' THEN DATEADD(MILLISECOND, -1*(DATEPART(MILLISECOND, IntervalStartReferenceTime) + 3), DATEADD(SECOND, -1*DATEPART(SECOND, IntervalStartReferenceTime), DATEADD(MINUTE, -1*DATEPART(MINUTE, IntervalStartReferenceTime), #activeIntervalDateTime)))
WHEN 'Days' THEN DATEADD(MILLISECOND, -1*(DATEPART(MILLISECOND, IntervalStartReferenceTime) + 3), DATEADD(SECOND, -1*DATEPART(SECOND, IntervalStartReferenceTime), DATEADD(MINUTE, -1*DATEPART(MINUTE, IntervalStartReferenceTime), DATEADD(HOUR, -1*DATEPART(HOUR, IntervalStartReferenceTime), #activeIntervalDateTime))))
WHEN 'Months' THEN DATEADD(MILLISECOND, -1*(DATEPART(MILLISECOND, IntervalStartReferenceTime) + 3), DATEADD(SECOND, -1*DATEPART(SECOND, IntervalStartReferenceTime), DATEADD(MINUTE, -1*DATEPART(MINUTE, IntervalStartReferenceTime), DATEADD(HOUR, -1*DATEPART(HOUR, IntervalStartReferenceTime), DATEADD(DAY, -1*(DATEPART(DAY, IntervalStartReferenceTime) - 1), #activeIntervalDateTime)))))
END AS ActiveTimeNormalized
FROM dbo.IntervalConfiguration
) norm
WHERE IntervalType = #groupByInterval) interval
WHERE (#activeIntervalDateTime > IntervalStart) and (#activeIntervalDateTime <= IntervalEnd)
ORDER BY IntervalStartReferenceTime DESC
SET #intervalDurationSeconds = DATEDIFF(SECOND, #intervalStartTime, #intervalEndTime);
IF #intervalStartTime >= #dateRangeStart AND #intervalEndTime <= #dateRangeEnd
BEGIN
INSERT INTO #Intervals(
IntervalType
,SubIntervalType
,IntervalStart
,IntervalEnd
,IntervalDurationSeconds
)
VALUES(
#intervalName
,#subIntervalType
,#intervalStartTime
,#intervalEndTime
,#intervalDurationSeconds
)
END
SET #activeIntervalDateTime = DATEADD(MILLISECOND, 3, #intervalEndTime);
END
RETURN;
END
This function however is getting increasingly complex and hard to debug also I would like to eliminate the need to use While loops within the function. My question is this, is there a simpler way to achieve my requirements and is it possible to eliminate the need for a while loop?
You can definitely simplify the query and eliminate the while loop through the use of a tally table as demonstrated below:
CREATE FUNCTION [dbo].[GetIntervals]
(
#startRange datetime,
#endRange datetime,
#groupByPeriod NVARCHAR(200)
)
RETURNS TABLE
AS
RETURN
(
WITH Tally (N) AS
(
SELECT 0 UNION ALL
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) a(n) -- 10 rows
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(n) -- 100 rows
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(n) -- 1,000 rows
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d(n) -- 10,000 rows
--CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) e(n) -- 100,000 rows
--CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) f(n) -- 1,000,000 rows
),
Intervals
AS
(
SELECT I.IntervalType
,I.SubIntervalType
,I.IntervalDuration
,I.IntervalDurationUnits
,I.IntervalStartReferenceTime
,I.IntervalRepeatDuration
,I.IntervalRepeatDurationUnits
,(
CASE
WHEN I.IntervalRepeatDurationUnits = 'Years' AND N < 500 THEN DATEADD(YEAR, ((DATEDIFF(YEAR, I.IntervalStartReferenceTime, #startRange) / I.IntervalRepeatDuration) + N) * I.IntervalRepeatDuration ,I.IntervalStartReferenceTime)
WHEN I.IntervalRepeatDurationUnits = 'Months' AND N < 6000 THEN DATEADD(MONTH, ((DATEDIFF(MONTH, I.IntervalStartReferenceTime, #startRange) / I.IntervalRepeatDuration) + N) * I.IntervalRepeatDuration ,I.IntervalStartReferenceTime)
WHEN I.IntervalRepeatDurationUnits = 'Weeks' AND N < 24000 THEN DATEADD(WEEK, ((DATEDIFF(WEEK, I.IntervalStartReferenceTime, #startRange) / I.IntervalRepeatDuration) + N) * I.IntervalRepeatDuration ,I.IntervalStartReferenceTime)
WHEN I.IntervalRepeatDurationUnits = 'Days' THEN DATEADD(DAY, ((DATEDIFF(DAY, I.IntervalStartReferenceTime, #startRange) / I.IntervalRepeatDuration) + N) * I.IntervalRepeatDuration ,I.IntervalStartReferenceTime)
WHEN I.IntervalRepeatDurationUnits = 'Hours' THEN DATEADD(HOUR, ((DATEDIFF(HOUR, I.IntervalStartReferenceTime, #startRange) / I.IntervalRepeatDuration) + N) * I.IntervalRepeatDuration ,I.IntervalStartReferenceTime)
END
) AS IntervalStart
,Tally.N
FROM IntervalConfiguration I
CROSS JOIN Tally
WHERE (I.IntervalType = #groupByPeriod)
AND
(
N BETWEEN 0 AND (
CASE I.IntervalRepeatDurationUnits
WHEN 'Years' THEN DATEDIFF(YEAR, #startRange, #endRange) / I.IntervalRepeatDuration
WHEN 'Months' THEN DATEDIFF(MONTH, #startRange, #endRange) / I.IntervalRepeatDuration
WHEN 'Weeks' THEN DATEDIFF(WEEK, #startRange, #endRange) / I.IntervalRepeatDuration
WHEN 'Days' THEN DATEDIFF(DAY, #startRange, #endRange) / I.IntervalRepeatDuration
WHEN 'Hours' THEN DATEDIFF(HOUR, #startRange, #endRange) / I.IntervalRepeatDuration
END)
)
)
SELECT TOP 100 PERCENT
I.IntervalType
,I.SubIntervalType
,I.IntervalDuration
,I.IntervalDurationUnits
,I.IntervalStartReferenceTime
,I.IntervalRepeatDuration
,I.IntervalRepeatDurationUnits
,I.IntervalStart
,(
CASE I.IntervalDurationUnits
WHEN 'Years' THEN DATEADD(YEAR, I.IntervalDuration, I.IntervalStart)
WHEN 'Months' THEN DATEADD(MONTH, I.IntervalDuration, I.IntervalStart)
WHEN 'Weeks' THEN DATEADD(WEEK, I.IntervalDuration, I.IntervalStart)
WHEN 'Days' THEN DATEADD(DAY, I.IntervalDuration, I.IntervalStart)
WHEN 'Hours' THEN DATEADD(HOUR, I.IntervalDuration, I.IntervalStart)
END
) AS IntervalEnd
,N
FROM Intervals I
WHERE I.IntervalStart >= #startRange
AND
(
CASE I.IntervalDurationUnits
WHEN 'Years' THEN DATEADD(YEAR, I.IntervalDuration, I.IntervalStart)
WHEN 'Months' THEN DATEADD(MONTH, I.IntervalDuration, I.IntervalStart)
WHEN 'Weeks' THEN DATEADD(WEEK, I.IntervalDuration, I.IntervalStart)
WHEN 'Days' THEN DATEADD(DAY, I.IntervalDuration, I.IntervalStart)
WHEN 'Hours' THEN DATEADD(HOUR, I.IntervalDuration, I.IntervalStart)
END
) <= #endRange
ORDER BY I.IntervalStart
)

Getting the month to show date name rather than number when pulling each month in the year

I am pulling data that lists each month of the year but the month column states the first day of each year, how can I make this show the full month name?
Here is some of what I have. I read similar questions and tried to add in what it stated everywhere but I couldn't get it work, help?
SELECT a.MonthDate
,Sum(a.ScrapPcs) / (Sum(a.GrossPcs)*1.00) As ScrapPct
,0.05 As ScrapTarget
,sum (a.GrossPcs) As 'Total Parts Cast'
,sum (a.ScrapPcs) as 'Total Parts Scrap'
,CASE
WHEN Sum(a.ScrapPcs) / (Sum(a.GrossPcs)*1.00) <= 0.05 THEN 1
WHEN Sum(a.ScrapPcs) / (Sum(a.GrossPcs)*1.00) >= 0.9*.05 THEN -1
ELSE 0
END
AS Status
FROM
(
SELECT DATEADD(month, DATEDIFF(month, 0, b.CreationProdDate), 0) As MonthDate
,Count(b.BOOKING_ID) As ScrapPcs
, 0 As GrossPcs
FROM dbo.CPC_BOOKING b
WHERE b.CreationProdDate Between DATEADD(yy, DATEDIFF(yy, 0, GetDate()), 0) AND DateAdd("d", -1, GetDate())
and CPC_BookingTyp_ID in (2,8)
and ManufacturingPlant in (90002604,90017699, 90017705)
GROUP BY DATEADD(month, DATEDIFF(month, 0, b.CreationProdDate), 0)
UNION ALL
SELECT DATEADD(month, DATEDIFF(month, 0, n.ProductionDate), 0) As MonthDate
,0 As ScrapPcs
,Sum(n.Quantity) As GrossPcs
FROM [NORIS].[dbo].[MDL_Data_Ultimate] n
WHERE n.ProductionDate Between DATEADD(yy, DATEDIFF(yy, 0, GetDate()), 0) AND DateAdd("d", -1, GetDate())
and n.ManufacturingPlantGroup = 1
GROUP BY DATEADD(month, DATEDIFF(month, 0, n.ProductionDate), 0)
) a
group by a.MonthDate
Thanks in advance, anything helps
For MySQL:
https://www.w3resource.com/mysql/date-and-time-functions/mysql-monthname-function.php
Use the MONTHNAME function as per the example on that webpage.
SELECT MONTHNAME(a.MonthDate)
For MS SQL Server:
If you want the month name use this in the derived table:
SELECT datename(month,DATEADD(month, DATEDIFF(month, 0, b.CreationProdDate), 0)) As MonthDate
That is, you want to apply the datename(month, date)function to the first column of both unioned queries.

how to concatenate Date & Year into one column sql

i have Date in one column & year in column and i need to concatenate and get the answer as Jan-2017 and that should be in actual Month oder
SELECT CONCAT(column1, ',', column2) AS Date,
FROM table;
This is simple. I assume your both column data types are DateTime or Date. Try the following:
SELECT CONCAT(SUBSTRING(DATENAME(month, YourMonthColumn), 0,4), '-', Year(YourYearColumn))
FROM YourTableName
Sql Server 2008 compatible: (no concat() and no format())
Using a convert() style of 106 (or 113), and just taking the mon yyyy part, and replacing the ' ' with '-',
and using dates truncated to the month, so we can group and order by it using dateadd(month, datediff(month, 0, [Date] ),0):
select MonthYear = replace(stuff(convert(varchar(12)
,dateadd(month, datediff(month, 0, [Date]), 0)
,106),1,3,''),' ','-')
, Days = count(*)
from dates
group by dateadd(month, datediff(month, 0, [Date]), 0)
order by dateadd(month, datediff(month, 0, [Date]), 0)
rextester demo: http://rextester.com/DFF74396
returns:
+-----------+------+
| MonthYear | Days |
+-----------+------+
| Dec-2016 | 31 |
| Jan-2017 | 31 |
| Feb-2017 | 28 |
| Mar-2017 | 10 |
+-----------+------+
Alternate using datename(month,date) for the month and concatenating the year:
select MonthYear = left(datename(month,dateadd(month, datediff(month, 0, [Date]), 0)),3)
+ '-'
+ convert(char(4),year(dateadd(month, datediff(month, 0, [Date]), 0)))
, Days = count(*)
from dates
group by dateadd(month, datediff(month, 0, [Date]), 0)
order by dateadd(month, datediff(month, 0, [Date]), 0)

Sales and transaction totals by part, grouped by last 24 months

SELECT det.partNum,
SUM(det.quantity) AS Demand1,
COUNT(det.partNum) AS Call1
FROM details det
JOIN invoice inv ON det.invoice_id = inv.id
WHERE inv.invoice_date
BETWEEN '2015-11-01 00:00:00'
AND '2015-11-31 23:59:59'
GROUP BY partNum
The above sql returns all part numbers, the total number sold (Demand), and the total number of transactions the parts were involved in (Call) for the current month.
What our vendor wants is this information for every part, but also grouped for each of the past 24 months. The csv they are requesting would look like the following (if only viewing the last 3 months):
Part# | Demand1 | Demand2 | Demand3 | Call1 | Call2 | Call3
123 | 0 | 2 | 0 | 0 | 1 | 0
345 | 6 | 3 | 4 | 1 | 2 | 3
Part# 123: 0 transactions this month (Call1) 0 quantity sold (Demand1)
1 transaction last month (Call2) 2 quantity sold (Demand2).
0 transactions two months ago (Call3) 0 quantity sold (Demand3).
Part# 345: 1 transaction this month (Call1) for qty sold of 6 (Demand1)
2 transactions last month (Call2) for qty sold of 3 (Demand2)
3 transactions two months ago (Call3) for qty sold of 4 (Demand3)
Realize that they want this extended out for the past 24 months. Demand1/Call1 are always the current month.
I used the WHERE/BETWEEN statement to show where the date is coming from and to demonstrate how I can get an accurate report of the parts for the current month.
What I can't figure out how to do is to fill Demand and Call for 24 months. And this is the format that the vendor expects the data to be in. This wasn't my choice. Any help in getting this working as expected would be greatly appreciated.
Thanks
EDIT
I removed the sql-server tag. Sorry about that. This is only MySQL.
Also, I'm adding my reply from below...
Looking into DATEDIFF, TIMESTAMPDIFF, and even PERIOD_DIFF. But none actually seem to return what I need. What needs to happen is the first demand column should search for the current month, day 1 (inclusive) through the next month, day 1 (exclusive). The next demand column should search the current month - one month, day 1 (inclusive) through next month - one month, day 1 (exclusive). And each subsequent column should search the same parameters, subtracting an additional month each column. I don't think that can be accomplished with precision simply using DATEDIFF.
I hope that makes sense.
And again, thanks for any help.
If I understood your problem correctly, you can do it like this:
SELECT
det.partNum,
SUM(case when inv.invoice_date >= dateadd(month, -3, #currMonth) and inv.invoice_date < dateadd(month, -2, #currMonth) then det.quantity else 0) AS Demand1,
SUM(case when inv.invoice_date >= dateadd(month, -2, #currMonth) and inv.invoice_date < dateadd(month, -1, #currMonth) then det.quantity else 0) AS Demand2,
...
FROM details det
JOIN invoice inv ON det.invoice_id = inv.id
WHERE
inv.invoice_date >= '2015-11-01 00:00:00' AND inv.invoice_date < '2015-12-01'
GROUP BY partNum
This uses a variable that has the start date of current month to make the SQL more simple. I also changed the where clause, you should really use >= + < with dates instead of between.
This might get you started with Pivot query.
;WITH cte AS
(
SELECT det.partNum,
SUM(det.quantity) AS DemandSum,
COUNT(det.partNum) AS CallCount,
DATEDIFF(MONTH,inv.invoice_date, GETDATE()) + 1 MonthDiff
FROM details det
JOIN invoice inv ON det.invoice_id = inv.id
GROUP BY det.partNum, DATEDIFF(MONTH,inv.invoice_date, GETDATE()) + 1
)
SELECT t.partNum,
[Demand1],[Demand2],[Demand3],[Demand4],[Demand5],[Demand6],[Demand7],[Demand8],[Demand9],[Demand10],[Demand11],[Demand12],
[Demand13],[Demand14],[Demand15],[Demand16],[Demand17],[Demand18],[Demand19],[Demand20],[Demand21],[Demand22],[Demand23],[Demand24],
[Call1],[Call2],[Call3],[Call4],[Call5],[Call6],[Call7],[Call8],[Call9],[Call10],[Call11],[Call12],
[Call13],[Call14],[Call15],[Call16],[Call17],[Call18],[Call19],[Call20],[Call21],[Call22],[Call23],[Call24]
FROM (SELECT DISTINCT partNum FROM cte) t
LEFT JOIN (
SELECT * FROM (
SELECT partNum, DemandSum, CONCAT('Demand',MonthDiff) ColName FROM cte
) c PIVOT (SUM(DemandSum) FOR ColName IN ([Demand1],[Demand2],[Demand3],[Demand4],[Demand5],[Demand6],[Demand7],[Demand8],[Demand9],[Demand10],[Demand11],[Demand12],
[Demand13],[Demand14],[Demand15],[Demand16],[Demand17],[Demand18],[Demand19],[Demand20],[Demand21],[Demand22],[Demand23],[Demand24])
) p
) ds ON ds.partNum = t.partNum
LEFT JOIN (
SELECT * FROM (
SELECT partNum, CallCount, CONCAT('Call',MonthDiff) ColName FROM cte
) c PIVOT (COUNT(CallCount) FOR ColName IN ([Call1],[Call2],[Call3],[Call4],[Call5],[Call6],[Call7],[Call8],[Call9],[Call10],[Call11],[Call12],
[Call13],[Call14],[Call15],[Call16],[Call17],[Call18],[Call19],[Call20],[Call21],[Call22],[Call23],[Call24])
) p
) cc ON cc.partNum = t.partNum
if that's too confusing, you can use the CASE method. I'd do it a little different than the other answer though..
SELECT
det.partNum,
SUM(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 0 then det.quantity else 0 end) AS Demand1,
SUM(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 1 then det.quantity else 0 end) AS Demand2,
SUM(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 2 then det.quantity else 0 end) AS Demand3,
COUNT(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 0 then det.partNum end) AS Call1,
COUNT(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 1 then det.partNum end) AS Call2,
COUNT(case WHEN DATEDIFF(MONTH, inv.invoice_date, GETDATE()) = 2 then det.partNum end) AS Call3
FROM
details det
JOIN invoice inv ON det.invoice_id = inv.id
GROUP BY
det.partNum
you can get the full script for all 24 months here.. SQL Fiddle

How to two select statements with sum functions in them

I'm trying to join these two tables and I get an error when I use any join. Union will work but returns all the values in two rows as opposed to 3 which I need. This is what I have so far and what it returns is below it. Any help would be great :)
select C.CustId ,SUM(Ia.Amount) as total
from Invoice I
inner join InvoiceAmtSummary Ia on I.GUIDInvoice=Ia.GUIDInvoice
inner join Customer C on C.GUIDCustomer=I.GUIDCustomer
WHERE DATEPART(mm, I.InvoiceDate) = DATEPART(mm, DATEADD(mm, -1, getdate()))
and DATEPART(yyyy, I.InvoiceDate) = DATEPART(yyyy, DATEADD(yyyy, -0, getdate()))
group by C.CustId
union
select C.CustId ,SUM(Ia.Amount) as total2
from Invoice I
inner join InvoiceAmtSummary Ia on I.GUIDInvoice=Ia.GUIDInvoice
inner join Customer C on C.GUIDCustomer=I.GUIDCustomer
WHERE DATEPART(mm, I.InvoiceDate) = DATEPART(mm, DATEADD(mm, -2, getdate()))
and DATEPART(yyyy, I.InvoiceDate) = DATEPART(yyyy, DATEADD(yyyy, -0, getdate()))
group by C.CustId
The returned result is below with the required result below that
Custid total
a 2
b 9
b 12
c 16
d 3
d 12
Custid total total2
a 2
b 9 12
c 16
d 3 12
select c.custid, c.total, c2.total2
from (select C.CustId ,SUM(Ia.Amount) as total
from Invoice I
inner join InvoiceAmtSummary Ia on I.GUIDInvoice=Ia.GUIDInvoice
inner join Customer C on C.GUIDCustomer=I.GUIDCustomer
WHERE DATEPART(mm, I.InvoiceDate) = DATEPART(mm, DATEADD(mm, -1, getdate()))
and DATEPART(yyyy, I.InvoiceDate) = DATEPART(yyyy, DATEADD(yyyy, -0, getdate()))
group by C.CustId) c
inner join
(select C.CustId ,SUM(Ia.Amount) as total2
from Invoice I
inner join InvoiceAmtSummary Ia on I.GUIDInvoice=Ia.GUIDInvoice
inner join Customer C on C.GUIDCustomer=I.GUIDCustomer
WHERE DATEPART(mm, I.InvoiceDate) = DATEPART(mm, DATEADD(mm, -2, getdate()))
and DATEPART(yyyy, I.InvoiceDate) = DATEPART(yyyy, DATEADD(yyyy, -0, getdate()))
group by C.CustId) c2 on c.custid = c2.custid
I think you are trying to have 2 columns of SUM of different Months. Here is what you can do:
Select C.CustId ,
Sum(Case DATEPART(mm, I.InvoiceDate)
When DATEPART(mm, DATEADD(mm, -1, getdate())) Then Ia.Amount
Else 0 End) As 'Total1',
Sum(Case DATEPART(mm, I.InvoiceDate)
When DATEPART(mm, DATEADD(mm, -2, getdate())) Then Ia.Amount
Else 0 End) As 'Total2'
from Invoice I
inner join InvoiceAmtSummary Ia on I.GUIDInvoice=Ia.GUIDInvoice
inner join Customer C on C.GUIDCustomer=I.GUIDCustomer
WHERE
DATEPART(yyyy, I.InvoiceDate) = DATEPART(yyyy, DATEADD(yyyy, -0, getdate()))
group by C.CustId
I am using Case to avoid the recursive join.
Since you are using MySQL, I would approach by implementing in-line sqlvariables (via my first "from" alias. The #FirstOfThisMonth is computed by subtracting whatever the current day of month is from the current date (less 1).
Ex: Today is April 3rd (3rd day of month). So, -3 = March 31... PLUS 1 brings back to April 1 of current month. Once that date is determined, I can now subtract an entire month for first of PREVIOUS month (March 1st), and subtract 2 months for Feb 1st.
Now that this complexity is done ONCE, we can use these variables instead of constant datepart extraction for month and year. Especially if you consider trying to do two months ago from Feb 10th. (First of current is Feb 1, one month back is Jan 1, two months back is Dec 1 of prior year).
NOW, I simply SUM() based on a case when condition.
if the Invoice Date is >= #TwoMonthsAgo AND LESS THAN #LastMonth, that goes into the two-months-ago total.
the next is Invoice Date >= #LastMonth AND LESS THAN #FirstOfThisMonth for last month's total.
Now, you have a rolling two-month window... If you wanted to go longer, just add another monthly variable reference and SUM() its criteria.
Finally the WHERE clause can only include invoices that are greater or equal to the #TwoMonthsAgo so it doesn't have to go through the entire database
select
C.CustId,
SUM( CASE when I.InvoiceDate >= #TwoMonthsAgo AND I.InvoiceDate < #LastMonth
then Ia.Amount else 0 end ) as TotalTwoMonthsAgo,
SUM( CASE when I.InvoiceDate >= #LastMonth AND I.InvoiceDate < #FirstOfThisMonth
then Ia.Amount else 0 end ) as TotalLastMonth
from
( select #FirstOfThisMonth := date_add( now(), INTERVAL -dayofmonth(now())+1 day ),
#LastMonth := date_add( #myDate, INTERVAL -1 month ),
#TwoMonthsAgo := date_add( #myDate, INTERVAL -2 month )) sqlvars,
Invoice I
inner join InvoiceAmtSummary Ia
on I.GUIDInvoice = Ia.GUIDInvoice
inner join Customer C
on C.GUIDCustomer = I.GUIDCustomer
WHERE
I.InvoiceDate >= #TwoMonthsAgo
AND I.InvoiceDate < #FirstOfThisMonth
group by
C.CustID