I am not sure what is the proper name to give to this condition in the where clause. I am using Microsoft SQL Server 2008.
Basically, I have an order table with the following columns.
MyOrderTable:
OrderAmount Paid OrderDate
100 Y 2016-08-10 21:15:52.000
120 N 2016-08-10 20:15:12.000
300 Y 2016-08-09 11:10:22.000
500 Y 2016-06-09 10:10:54.000
125 N 2016-06-09 09:15:13.000
325 N 2015-11-09 09:15:13.000
Currently, I have the following SQL query:
SELECT DATEPART(Year, OrderDate) TheYear, DATEPART(Month, OrderDate) TheMonth,
SUM(ISNULL(OrderAmount, 0)) as SumOrderAmount
FROM MyOrderTable
WHERE YEAR(OrderDate) = 2016
GROUP BY DATEPART(Year, OrderDate), DATEPART(Month, OrderDate)
ORDER BY TheYear, TheMonth
The result returned from the above SQL is like the following:
TheYear TheMonth SumOrderAmount
2016 6 625
2016 8 520
How can I query also the SumOrderAmount where the row is Paid='Y'? I want to return the following from the SQL:
TheYear TheMonth SumOrderAmount PaidSumOrderAmount
2016 6 625 500
2016 8 520 400
How can I do that? Any help is greatly appreciated. Thank you.
Use conditional aggregation:
SELECT DATEPART(Year, OrderDate) TheYear, DATEPART(Month, OrderDate) TheMonth,
SUM(ISNULL(OrderAmount, 0)) as SumOrderAmount,
SUM(CASE WHEN Paid = 'Y' THEN OrderAmount ELSE 0 END) as PaidOrderAmount
FROM MyOrderTable
WHERE YEAR(OrderDate) = 2016
GROUP BY DATEPART(Year, OrderDate), DATEPART(Month, OrderDate)
ORDER BY TheYear, TheMonth;
You probably don't need the ISNULL() in SUM(). In SQL, NULL values are ignored in the SUM() aggregation function.
Use a case expression to do a conditional SUM():
SELECT DATEPART(Year, OrderDate) TheYear, DATEPART(Month, OrderDate) TheMonth,
SUM(ISNULL(OrderAmount, 0)) as SumOrderAmount,
SUM(case when Paid='Y' then OrderAmount end)
FROM MyOrderTable
WHERE YEAR(OrderDate) = 2016
GROUP BY DATEPART(Year, OrderDate), DATEPART(Month, OrderDate)
ORDER BY TheYear, TheMonth
Add this clause on select:
SUM(CASE WHEN Paid='Y' THEN OrderAmount ELSE 0 END) AS PaidSumOrderAmount
SELECT DATEPART(Year, OrderDate) TheYear, DATEPART(Month, OrderDate) TheMonth,
SUM(ISNULL(OrderAmount, 0)) as SumOrderAmount,Paid
FROM MyOrderTable
WHERE (YEAR(OrderDate) = 2016) and (Paid = 'Y')
GROUP BY DATEPART(Year, OrderDate), DATEPART(Month, OrderDate)
ORDER BY TheYear, TheMonth
Related
I am using Covid world data, which tracks number of new_cases every day. I have data from 2020-01-01 to present day. This is my current query:
SELECT MIN(date) as week, datepart(iso_week, date) week_num, sum(new_cases) as [Total Cases]
FROM covid_data_cleaned
GROUP BY DATEPART(iso_week, date), DATEPART(year, date)
ORDER BY MIN(date) DESC
Which gives me pretty much what I want except for when the year changes:
week week_num Total Cases
2022-01-10 2 20803473
2022-01-03 1 17217248
**2022-01-01 52 2115780**
**2021-12-27 52 7971560**
2021-12-20 51 5561762
I want to figure out the workaround to combining the '52' values together. Alternatively, my dataset has 112 weeks; can I assign the values 1-112 to the whole dataset rather than 1-52 for each year?
You could aggregate on a correction via a CASE WHEN for the iso year.
SELECT
min(weekstart) as [week]
, [iso_week] as weeknum
, sum(new_cases) as [Total Cases]
FROM
(
SELECT
min([date]) as weekstart
, datepart(iso_week, [date]) as [iso_week]
, case
when month(min([date])) = 1
and datepart(iso_week, [date]) >= 52
then year([date]) - 1
when month(min([date])) = 12
and datepart(iso_week, [date]) = 1
then year([date]) + 1
else year([date])
end as iso_year
, sum(new_cases) as new_cases
FROM covid_data_cleaned
GROUP BY year([date]), datepart(iso_week, [date])
) q
GROUP BY iso_year, [iso_week]
ORDER BY [week] DESC;
Instead of iso week, you can use week.
DECLARE #table table(datev date, new_Cases int)
INSERT INTO #table values
('2022-01-01',123),('2022-01-09',432),('2022-01-03',123),('2021-12-27',234);
SELECT MIN(datev) as week, datepart(week, datev) week_num, sum(new_cases) as [Total Cases]
FROM #table
GROUP BY DATEPART(week, datev), DATEPART(year, datev)
ORDER BY MIN(datev) DESC
week
week_num
Total Cases
2022-01-09
3
432
2022-01-03
2
123
2022-01-01
1
123
2021-12-27
53
234
SOLVED:
Got A Solution, not perfected but can process it further in the frontend to display it! I Basically have 2 selects to create two tables from one and then join them with a inner join where i have in one row all stamp in and stamp outs of the same user within the same day , yay.
SELECT * FROM
(SELECT SUM(CASE WHEN DATEPART(YEAR, t.inStampDate) > 2018 THEN 1 ELSE 0 END) AS 'Stamps',
ISNULL(t.inStampDate, '') as 'inStampDate',
t.employeeID
FROM dbo.timeRecording t
WHERE DATEPART(YEAR, t.inStampDate) > 2018
GROUP BY t.employeeID,
t.inStampDate ) inStamp
INNER JOIN
(SELECT SUM(CASE WHEN DATEPART(YEAR, t.outStampDate) > 2018 THEN 1 ELSE 0 END) AS 'Stamps',
ISNULL(t.outStampDate, '') as 'outStampDate',
t.employeeID
FROM dbo.timeRecording t
WHERE DATEPART(YEAR, t.outStampDate) > 2018
GROUP BY t.employeeID,
t.outStampDate ) outStamp
ON inStamp.inStampDate = outStamp.outStampDate AND inStamp.employeeID = outStamp.employeeID
Previous Situation:
Situation: I have users which can login or stampin and out. These values are being logged. Now I want to show how often a user has stamped in or out in total in a single day.
I have a table in which I have two date values StampInDate and StampOutDate. Also there is an employeeID. I tried to calculate the total amount of stamp in and stamp outs in a single day. I already can show me the total amount of the stamps for each stamp in or stamp out but I cant get that far to compare those values and create a new column "totalStampsThatDay" which will be filled with the count of stamps that day. The error message I get is:
Msg 8120, Level 16, State 1, Line 17
Column 'dbo.timeRecording.employeeID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Code that works:
SELECT t.employeeID,
DATEPART(YEAR, t.inStampDate) AS 'InYear',
DATEPART(MONTH, t.inStampDate) AS 'InMonth',
DATEPART(DAY, t.inStampDate) AS 'InDay',
DATEPART(YEAR, t.outStampDate) AS 'OutYear',
DATEPART(MONTH, t.outStampDate) AS 'OutMonth',
DATEPART(DAY, t.outStampDate) AS 'OutDay',
COUNT(t.inStampDate) AS 'StampIns',
COUNT( t.outStampDate) AS 'StampOuts'
FROM dbo.timeRecording t
GROUP BY DATEPART(DAY, t.inStampDate),
DATEPART(MONTH, t.inStampDate),
DATEPART(YEAR, t.inStampDate),
DATEPART(DAY, t.outStampDate),
DATEPART(MONTH, t.outStampDate),
DATEPART(YEAR, t.outStampDate),
t.employeeID
ORDER BY t.employeeID
Now my try to edit it to achieve what I want but failed:
SELECT tr.StampIns,
tr.StampOuts,
tr.eID,
t.employeeID,
DATEPART(YEAR, t.inStampDate) AS 'InYear',
DATEPART(MONTH, t.inStampDate) AS 'InMonth',
DATEPART(DAY, t.inStampDate) AS 'InDay',
DATEPART(YEAR, t.outStampDate) AS 'OutYear',
DATEPART(MONTH, t.outStampDate) AS 'OutMonth',
DATEPART(DAY, t.outStampDate) AS 'OutDay'
FROM dbo.timeRecording t
JOIN
(SELECT
COUNT(tr.inStampDate) AS 'StampIns',
COUNT(tr.outStampDate) AS 'StampOuts',
tr.employeeID as 'eID'
FROM dbo.timeRecording tr
) tr ON tr.eID = t.employeeID
GROUP BY DATEPART(DAY, t.inStampDate),
DATEPART(MONTH, t.inStampDate),
DATEPART(YEAR, t.inStampDate),
DATEPART(DAY, t.outStampDate),
DATEPART(MONTH, t.outStampDate),
DATEPART(YEAR, t.outStampDate),
t.employeeID,
tr.eID,
tr.StampIns,
tr.StampOuts
ORDER BY t.employeeID
Something like:
employeeID | date | totalStampsThatDay
1 | 21.11.19| 2
2 | 21.11.19| 0
3 | 22.11.19| 1
1 | 22.11.19| 1
... and so on
---- UPDATE ----
Almost got what i wanted. I only need to add a column for the date, e.g. 2019-11-19, but i am unable to do so right now.
SELECT t.employeeID,
COUNT(t.inStampDate) + COUNT( t.outStampDate) as 'TotalStamps',
SUM(CASE WHEN DATEPART(YEAR, t.inStampDate) > 2018 THEN 1 ELSE 0 END) AS 'StampIns',
SUM(CASE WHEN DATEPART(YEAR, t.outStampDate) > 2018 THEN 1 ELSE 0 END) AS 'StampOuts'
FROM dbo.timeRecording t
WHERE DATEPART(YEAR, t.inStampDate) > 2018 OR DATEPART(YEAR, t.outStampDate) > 2018
GROUP BY t.employeeID
My output so far:
employeeID | Total | In | Out
7 | 9 | 6 | 3
8 | 105 | 48 | 57
11 | 6 | 5 | 1
And want:
employeeID | Date | Total | In | Out
7 | 2019-11-19 | 2 | 1 | 1
7 | 2019-11-20 | 3 | 2 | 1
11 | 2019-11-19 | 1 | 1 | 0
11 | 2019-11-16 | 2 | 1 | 1
SELECT t.employeeID,
DATEPART(YEAR, t.inStampDate) AS 'InYear',
DATEPART(MONTH, t.inStampDate) AS 'InMonth',
DATEPART(DAY, t.inStampDate) AS 'InDay',
DATEPART(YEAR, t.outStampDate) AS 'OutYear',
DATEPART(MONTH, t.outStampDate) AS 'OutMonth',
DATEPART(DAY, t.outStampDate) AS 'OutDay',
COUNT(t.inStampDate) + COUNT( t.outStampDate) as 'TotalStamps',
FROM dbo.timeRecording t
GROUP BY DATEPART(DAY, t.inStampDate),
DATEPART(MONTH, t.inStampDate),
DATEPART(YEAR, t.inStampDate),
DATEPART(DAY, t.outStampDate),
DATEPART(MONTH, t.outStampDate),
DATEPART(YEAR, t.outStampDate),
t.employeeID
ORDER BY t.employeeID
What about this?
I am trying to create a report that gives me number to an event that occurred in the week, month and quarter of a specific date.
I have been able to so so for weeks and months but having issue with quarter. I want results for quarter of that specific year- like in the example below for 2016 only.
For example
declare #date date set #date = '2016/02/30'
select case_id, event_date
from #total
WHERE datepart(quarter, event_DATE) = datepart(quarter, #date)
order by 2
when I use this code it gives me result for not only 2016 but also for same quater of 2015,2014 (previous years).
case_id event_date
1234 1986-02-06
5567 2014-01-04
3456 2015-03-11
6378 2016-02-23
4789 2016-02-06
6782 2016-01-04
2346 2016-03-11
9098 2016-02-23
what I want: only for 2016 and not previous years.
case_id event_date
4789 2016-02-06
6782 2016-01-04
2346 2016-03-11
9098 2016-02-23
You could try adding a condition for the year:
[...] AND datepart(year, event_DATE) = datepart(year, #date)
You query would look something like
SELECT case_id, event_date
FROM #total
WHERE datepart(quarter, event_DATE) = datepart(quarter, #date)
AND datepart(year, event_DATE) = datepart(year, #date)
ORDER BY 2
declare #date date set #date = '2016/02/30'
select case_id, event_date
from #total
WHERE datepart(quarter, event_DATE) = datepart(quarter, #date)
AND datepart(YYYY,event_DATE) = '2016'
order by 2
I currently have a query which produces data for each quarter, what I would like is for the total to be a running total. So quarter 2's figures will be added on to quarter 1's and so on until the end of the fiscal year, where the process will then start again.
select datepart(year,date) as Year,
CASE
WHEN MONTH(date) BETWEEN 1 AND 3 THEN convert(char(4), YEAR(date) - 1) + 'Q4'
WHEN MONTH(date) BETWEEN 4 AND 6 THEN convert(char(4), YEAR(date) - 0) + 'Q1'
WHEN MONTH(date) BETWEEN 7 AND 9 THEN convert(char(4), YEAR(date) - 0) + 'Q2'
WHEN MONTH(date) BETWEEN 10 AND 12 THEN convert(char(4), YEAR(date) - 0) + 'Q3'
END AS Quarter,
Data1,
Data2,
FROM TABLE
GROUP BY datepart(year,date),
CASE
WHEN MONTH(date) BETWEEN 1 AND 3 THEN convert(char(4), YEAR(date) - 1) + 'Q4'
WHEN MONTH(date) BETWEEN 4 AND 6 THEN convert(char(4), YEAR(date) - 0) + 'Q1'
WHEN MONTH(date) BETWEEN 7 AND 9 THEN convert(char(4), YEAR(date) - 0) + 'Q2'
WHEN MONTH(date) BETWEEN 10 AND 12 THEN convert(char(4), YEAR(date) - 0) + 'Q3'
END
This is what I currently get
year quarter data1 data2
2016 Q1 10 4
2016 Q2 5 6
2016 Q3 4 2
2017 Q4 1 1
I would like the output to look like this
year quarter data1 data2
2016 Q1 10 4
2016 Q2 15 10
2016 Q3 19 12
2017 Q4 20 13
Thanks for any help
You can wrap your query in a CTE and use CROSS APPLY in order to calculate the cumulative sum:
;WITH CTE AS (
-- your query
)
SELECT t1.year, t1.quarter, t1.data1, t3.cumulative_sum
FROM CTE AS t1
CROSS APPLY (
SELECT SUM(data2) AS cumulative_sum
FROM CTE AS t2
WHERE t2.year <= t1.year AND t2.quarter <= t1.quarter) AS t3
First, your query can be simplified to:
SELECT datepart(year, date) as Year,
datename(year, date) + 'Q' + datename(quarter, dateadd(month, -3, date)) as quarter,
SUM(Data1) as Data1, SUM(Data2) as Data2
FROM TABLE
GROUP BY datepart(year, date) as Year,
datename(year, date) + 'Q' + datename(quarter, dateadd(month, -3, date)) as quarter
ORDER BY quarter;
Note the use of datename(). This returns a string rather than a number, which is easier for string concatenation. In addition, this simplifies the logic just by subtracting 3 months to get the quarter.
In SQL Server 2012+, you can use the built in functionality for cumulative sum. In SQL Server 2008, one method uses apply:
WITH t as (
SELECT datepart(year, date) as Year,
datename(year, date) + 'Q' + datename(quarter, dateadd(month, -3, date)) as quarter,
SUM(Data1) as Data1, SUM(Data2) as Data2
FROM TABLE
GROUP BY datepart(year, date) as Year,
datename(year, date) + 'Q' + datename(quarter, dateadd(month, -3, date)) as quarter
)
SELECT t.*, tt.data2
FROM t OUTER APPLY
(SELECT SUM(data1) as data2
FROM t t2
WHERE t2.quarter <= t.quarter
) tt;
I have a table like this
id Date Amount
1 2016-09-29 09:25:37.000 25.13
2 2016-08-01 17:20:39.000 598.00
3 2016-09-29 09:24:47.000 15.60
4 2016-07-28 17:50:11.000 61.80
5 2016-07-28 17:53:56.000 31.40
6 2016-07-22 10:40:27.000 74.16
I'm trying to get two columns like this,
MonthYear Total
Sep 2016 40.73
Aug 2016 598.00
Jul 2016 167.36
But, I want to get most recent year and month to top.
Try this sql,
SELECT CONVERT(CHAR(4), Date, 100) + CONVERT(CHAR(4), Date, 120)
AS MonthYear, SUM(Amount)
AS Total,
CAST(CONVERT(varchar(4), Date, 120) AS int)
AS Year, DATEPART(m, Date) As Month
FROM your_table
GROUP BY CONVERT(CHAR(4), Date, 100) + CONVERT(CHAR(4), Date,120),CAST(CONVERT(varchar(4), Date, 120) AS int), DATEPART(m, Date)
ORDER BY Year DESC, Month DESC
Just an other perspective.
Query
SELECT t.[MonthYear], SUM(t.[Amount]) AS [Total] FROM(
SELECT RIGHT((CONVERT(VARCHAR(11), [Date], 106)), 8) as [MonthYear], [Amount]
FROM [your_table_name]
)t
GROUP BY t.[MonthYear];
Try below
SELECT Datename(MONTH, [Date]) month_name,
Year([Date]) year,
Sum([Amount]),
Month([date]) month_no
FROM #Table1
GROUP BY Datename(MONTH, [Date]),
Year([Date]),
Month([date])
ORDER BY Month([date]) DESC,
Year([Date]),
Datename(MONTH, [Date])