Daily, Weekly and Monthly report from MS SQL - sql-server-2008

I want to get Daily, Weekly and Monthly report from a sql-server table.
Table structure as as follow:
------------------------------------------
| ItemID | CommentDate |
-----------------------------------------
|989898797 | 2019-04-01 02:51:11.153 |
|----------------------------------------|
|989898797 | 2019-04-01 02:51:11.153 |
|----------------------------------------|
|989898797 | 2019-04-03 02:51:11.153 |
|----------------------------------------|
|989898797 | 2019-04-09 02:51:11.153 |
|----------------------------------------|
|989898797 | 2019-04-11 02:51:11.153 |
|----------------------------------------|
So far I have tried the following,
select (select count(itemid) from ebayfeedback where ((year(commentdate) = year(getdate()))
and datepart(m,commentdate)=datepart(m,dateadd(month,-1,getdate())))) as lastmonth,
(select count(itemid) from ebayfeedback where (year(commentdate) = year(getdate()))
and datepart(m,commentdate)=datepart(m,dateadd(month,0,getdate()))) as thismonth,
(select count(itemid) from ebayfeedback where (year(commentdate) = year(getdate()))
and datepart(wk,commentdate)=datepart(wk,dateadd(week,1,getdate()))) as lastweek,
(select count(itemid) from ebayfeedback where (year(commentdate) = year(getdate()))
and datepart(wk,commentdate)=datepart(wk,getdate()) group by datepart(wk,commentdate) ) as thisweek,
(select count(itemid) from ebayfeedback where convert(varchar,commentdate,101)=
convert(varchar,dateadd(day,-1,getdate()),101)) as yesterday,
(select count(itemid) from ebayfeedback where convert(varchar,commentdate,101)=
convert(varchar,getdate(),101) ) as today
from ebayfeedback
The Result I receive result in multiple rows from the above query is like below.
---------------------------------------------------------
| lastmonth | thismonth | lastweek | thisweek | today |
---------------------------------------------------------
|5 | 5 | 2 | 2 | 1 |
|-------------------------------------------------------|
|5 | 5 | 2 | 2 | 1 |
|-------------------------------------------------------|
|5 | 5 | 2 | 2 | 1 |
|-------------------------------------------------------|
|5 | 5 | 2 | 2 | 1 |
|-------------------------------------------------------|
|5 | 5 | 2 | 2 | 1 |
|-------------------------------------------------------|
I want single row (1 result) for each period only. Please advise me as how to achieve this. Also is there any best approach other than the one I used.
Desired Result should be one row like below.
| lastmonth | thismonth | lastweek | thisweek | today |
---------------------------------------------------------
|5 | 5 | 2 | 2 | 1 |
|-------------------------------------------------------|
Note: The data I given in the as example in above both tables not the actual I have.

One way to solve this is using conditional aggregation query to create a report based on it.
First, create and populate sample table (Please save is this step in your future questions):
DECLARE #T AS TABLE
(
ItemID int,
CommentDate datetime
);
INSERT INTO #T (ItemId, CommentDate) VALUES
(989898797, '2019-04-01T02:51:11.153'),
(989898797, '2019-04-01T02:51:11.153'),
(989898797, '2019-04-03T02:51:11.153'),
(989898797, '2019-04-09T02:51:11.153'),
(989898797, '2019-04-11T02:51:11.153');
Declaring local variable to make the query more readable and to prevent some code repetitions:
DECLARE #Today date = GETDATE(), -- today's date
#ThisWeek date = DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), GETDATE()), -- first date of the week
#ThisMonth date = DATEADD(DAY, 1 - DATEPART(DAY, GETDATE()), GETDATE()); -- first date of the month
DECLARE #LastMonth date = DATEADD(MONTH, -1, #ThisMonth), -- first date of last month
#LastWeek date = DATEADD(WEEK, -1, #ThisWeek) -- first date of last week
The query:
SELECT COUNT(CASE WHEN CommentDate >= #LastMonth AND CommentDate < #ThisMonth THEN ItemId END) As LastMonth,
COUNT(CASE WHEN CommentDate >= #ThisMonth AND CommentDate < DATEADD(MONTH, 1, #ThisMonth) THEN ItemId END) As thismonth,
COUNT(CASE WHEN CommentDate >= #LastWeek AND CommentDate < #ThisWeek THEN ItemId END) As lastweek,
COUNT(CASE WHEN CommentDate >= #ThisWeek AND CommentDate < DATEADD(WEEK, 1, #ThisWeek) THEN ItemId END) As thisweek,
COUNT(CASE WHEN CommentDate >= #Today AND CommentDate < DATEADD(DAY, 1, #Today) THEN ItemId END) As today
FROM #T
Results:
LastMonth thismonth lastweek thisweek today
0 5 2 0 0

Related

GROUP BY custom date intervals per year

Situation: I need a custom interval between dates. The problem I face when I try to GROUP BY the year and the result I get amounts to by the given year. I need a custom interval per year from December 20th with time: 00:00:00 of previous year to December 19th with time: 23:59:59 of said year. Here is some of my data:
Table - History:
id | date | income | spent
--------------------------------------------
1 | 2019-12-21 17:15:00 | 600,00 | NULL
2 | 2019-12-23 12:55:00 | 183,00 | NULL
3 | 2019-12-30 20:05:00 | NULL | 25,00
4 | 2020-01-01 15:35:00 | NULL | 13,00
5 | 2020-01-01 20:25:00 | NULL | 500,50
6 | 2020-12-10 10:25:00 | NULL | 5,50
7 | 2021-05-22 12:45:00 | 1098,00 | NULL
8 | 2021-05-23 10:18:00 | NULL | 186,00
9 | 2021-11-25 12:32:00 | NULL | 10,00
10 | 2021-12-23 10:35:00 | NULL | 10,00
The expected result:
Year | Summary Income | Summary Spent | Difference
--------------------------------------------------
2020 | 783,00 | 544,00 | 239,50
2021 | 1098,00 | 196,00 | 902,00
2022 | 0,00 | 10,00 | -10,00
I have managed to get a result with the help of a loop within a procedure:
...
SET #Aa = (SELECT MIN(date) FROM History);
CREATE TEMPORARY TABLE Yr (Year VARCHAR(4), Income FLOAT(8,2), Spent FLOAT(8,2), differ FLOAT(8,2));
Yearly: LOOP
SET #Aa = #Aa + 1;
SET #From = CONCAT((#Aa - 1), '-12-20 00:00:00');
SET #To = CONCAT(#Aa, '-12-19 23:59:59');
SET #Count = (SELECT SUM(income) FROM History WHERE date >= #From AND date <= #To);
SET #diff = (SELECT SUM(spent) FROM History WHERE date >= #From AND date <= #To);
INSERT INTO Yr (Year, Income, Spent, differ) VALUES (#Aa, #Count, #diff, (#Count - #diff));
IF (#Aa = (SELECT MAX(YEAR(date)) FROM History)) THEN LEAVE Yearly; END IF;
END LOOP;
SELECT * FROM Yr;
...
Question: I wonder if it's possible to get a custom interval for an annual summary with an condensed SQL query without using a loop?
You can simply add 11 days to the date before applying the year function to get this grouping, e.g.
SELECT YEAR(DATE_ADD(date, INTERVAL 11 DAY)) AS Year,
SUM(income) AS income,
SUM(spent) AS Spent,
IFNULL(SUM(income),0) - IFNULL(SUM(spent),0) AS difference
FROM History
GROUP BY YEAR(DATE_ADD(date, INTERVAL 11 DAY));
Example on db-fiddle

get specific data in different time period in mysql

I have a table like this
--------------------------------
|name | time | city |value |
--------------------------------
|a | 2018| rasht | 1.5 |
--------------------------------
|a | 2017| rasht | 2 |
--------------------------------
|a | 2018| tehran| 4 |
--------------------------------
|a | 2017| rasht | 3 |
--------------------------------
|a | 2018| rasht | 5 |
--------------------------------
|a | 2017| rasht | 2 |
--------------------------------
|b | 2018| tehran| 7 |
--------------------------------
i like to get data from this table like this:
name | city | total 2018 | total 2017
a |rasht | 6.5 |7
a |theran| 4 |0
b |theran| 7 |0
I am using query like this:
select A.name,city,A.sum(value) ,B.sum(value) from
(select * from tbl where year=2018 group by name,city)A,
(select * from tbl where year=2017 group by name,city)B
where A.name=B.name and A.city=B.city
but it didn't work and for records like b that dont have value in 2017 it returns nothing
As u can see my example here is very simple i made exact db in fiddle if u can see it in this address Fiddle
I also use this code:
select subzone, mvFeederName, SUM(CASE WHEN faultStartDate >= 13970901 and faultEndDate <= 13971101 and (subzone=10 ) THEN energyLost ELSE 0 END) AS `unplannedCurrentEnergyLost`, SUM(CASE WHEN faultStartDate >= 13960901 and faultEndDate <= 13961101 and (subzone=10 ) THEN energyLost ELSE 0 END) AS `unplannedLastYearEnergyLost`, count(CASE WHEN faultStartDate >= 13970901 and faultEndDate <= 13971101 and (subzone=10 ) THEN mvFeederName ELSE 0 END) AS `unplannedCurrentCount`, count(CASE WHEN faultStartDate >= 13960901 and faultEndDate <= 13961101 and (subzone=10 ) THEN mvFeederName ELSE 0 END) AS `unplannedLastYearCount` from faults_mv group by subzone,mvFeederName
it return zero for energyLost sumation col in two time period and count of mvFeederName in two thime period is the same that is not correct.
Use conditional aggregation -
select name, city,
sum(case when time=2018 then value end) 'total 2018',
sum(case when time=2017 then value end) 'total 2017'
from tablename
group by name, city
You can use conditional aggregation to get the result you want:
SELECT name, city,
SUM(CASE WHEN time = 2018 THEN value ELSE 0 END) AS `total 2018`,
SUM(CASE WHEN time = 2017 THEN value ELSE 0 END) AS `total 2017`
FROM tbl
GROUP BY name, city
Output:
name city total 2018 total 2017
a rasht 6.5 7
a tehran 4 0
b tehran 7 0
Demo on dbfiddle

How to get the data per month in MySQL

I'm trying to get the data per every month.
I'm a newbie at MySQL.
I just google and learn from the internet.
So, My Query may be not suitable.
If not suitable, please fix my query.
HERE IS MY QUERY
SELECT
SUM( cr_dt > EXTRACT( YEAR_MONTH FROM CURDATE() )
AND
cr_dt < EXTRACT( YEAR_MONTH FROM CURDATE() + INTERVAL 1 MONTH )
) as thisMonth,
SUM( cr_dt > EXTRACT( YEAR_MONTH FROM CURDATE() - INTERVAL 1 MONTH
AND
cr_dt < EXTRACT( YAER_MONTH FROM CURDATE()
) as last1Month
FROM MYTABLE
I just found the EXTRACT() and INTERVAL, but I don't know it may suitable.
If you have a better way to solve, share please.
WHAT I EXPECT
| thisMonth | last1Month |
+-----------+------------+
| 123 | 1294 |
WHAT I SEE NOW
| thisMonth | last1Month |
+-----------+------------+
| 0 | 0 |
SAMPLE DATAS
| idx | cr_dt |
+-----+---------------------+
| 1 | 2018-02-01 17:00:00 |
| 2 | 2018-02-19 16:00:00 |
| 3 | 2018-02-28 15:00:00 |
| 4 | 2018-03-04 14:00:00 |
| 5 | 2018-04-01 13:00:00 |
| 6 | 2018-04-09 12:00:00 |
| 7 | 2018-04-12 11:00:00 |
| 8 | 2018-04-17 10:00:00 |
You need to use conditional aggregation here, something like this:
SELECT
COUNT(CASE WHEN cr_dt >= DATE_FORMAT(CURRENT_DATE, '%Y/%m/01')
THEN 1 END) AS thisMonth,
COUNT(CASE WHEN cr_dt >= DATE_FORMAT(CURRENT_DATE - INTERVAL 1 MONTH, '%Y/%m/01') AND
cr_dt < DATE_FORMAT(CURRENT_DATE, '%Y/%m/01') THEN 1 END) AS last1Month
FROM MYTABLE
WHERE cr_dt >= DATE_FORMAT(CURRENT_DATE - INTERVAL 1 MONTH, '%Y/%m/01');
More typically you might see this sort of query using a GROUP BY clause, to compute aggregates over individual groups. In your case, however, it appears you want to aggregate over the entire table.

How to get records for last 3 months while grouping by each month

Please how do I sum records in my MySQL table for the last 3 months but group them by month.
I want something like this:
select SUM(amount) from table where.....
group by month
I am doing the below but it is not returning any results
SELECT MONTHNAME(a.created_at) MONTH, YEAR(a.created_at) YEAR, SUM(a.credit) as credit, SUM(a.debit)
FROM telco_transactions AS a
WHERE a.telco_id = '1' and DATE(a.created_at) = DATE_ADD(NOW(), INTERVAL -3 MONTH)
GROUP BY MONTHNAME(a.created_at), YEAR(a.created_at);
select T.date_time, SUM(T.amount) from (
-> select * from TEST_TABLE where date_time >= DATE_ADD(CURDATE(), INTERVAL -3 MONTH) and date_time <= CURDATE())
-> as T GROUP BY MONTH(T.date_time);
The table test_table looks like
+------------+--------+
| date_time | amount |
+------------+--------+
| 2017-12-24 | 30 |
| 2017-09-24 | 30 |
| 2017-12-04 | 30 |
| 2017-11-24 | 30 |
| 2017-11-09 | 30 |
| 2017-10-24 | 30 |
+------------+--------+
and the output of the query looks like
+------------+---------------+
| date_time | SUM(T.amount) |
+------------+---------------+
| 2017-09-24 | 30 |
| 2017-10-24 | 30 |
| 2017-11-24 | 60 |
| 2017-12-24 | 60 |
+------------+---------------+
I would try this:
SELECT SUM(records)
FROM TABLE_NAME
WHERE Date_Column >= DATEADD(MONTH, -3, GETDATE())
GROUP BY DATEPART(MONTH, Date_Column)
I found a answer
SELECT MONTHNAME(a.created_at) as tmonth, YEAR(a.created_at) as tYear,
SUM(a.credit) as credit, SUM(a.debit)
FROM telco_transactions AS a
WHERE a.telco_id = '1' and DATE(a.created_at) BETWEEN DATE(NOW())-INTERVAL 3 MONTH AND DATE(NOW())
GROUP BY MONTHNAME(a.created_at), YEAR(a.created_at);

Retreiving data using a sql query for a specific scenario

I am having a resultset/table which is as below
user_id |date_time |name |
---------|------------------|------|
1 |05/04/2017 08:00 |Jack |
2 |05/04/2017 09:00 |Adams |
1 |05/04/2017 13:06 |Jack |
1 |05/04/2017 13:45 |Jack |
1 |06/04/2017 09:15 |Jack |
1 |07/04/2017 10:00 |Jack |
1 |10/04/2017 12:00 |Jack |
2 |10/04/2017 12:30 |Adams |
1 |10/04/2017 15:44 |Jack |
I want to sort the date_time in ascending order for each user for each day.
I am expecting the result to be as below: (I am having problem with the second row and the last but one). All rows for Jack on April 5 should be together, followed by Adams; whether the date_time of Adams is in between the date_time of Jack for that day
user_id |date_time |name |
---------|------------------|------|
1 |05/04/2017 08:00 |Jack |
1 |05/04/2017 13:06 |Jack |
1 |05/04/2017 13:45 |Jack |
2 |05/04/2017 09:00 |Adams |
1 |06/04/2017 09:15 |Jack |
1 |07/04/2017 10:00 |Jack |
1 |10/04/2017 12:00 |Jack |
1 |10/04/2017 15:44 |Jack |
2 |10/04/2017 12:30 |Adams |
Adding the query I had used to arrive at this resultset:
SELECT DISTINCT user_table.user_id
,diary_table.date_time
,user_table.NAME
FROM user_table
INNER JOIN diary_table ON user_table.user_id = diary_table.diary_user_id
AND (
date_time >= '06-Apr-2017 00:00:00'
AND date_time <= '15-Apr-2017 23:59:59'
)
AND diar_user_id IN (
SELECT DISTINCT diar_user_id
FROM diary_table
INNER JOIN event_table ON event_table.event_id = diary_table.diar_event_id
WHERE event_table.event_name = 'Lunch'
AND (
date_time >= '06-Apr-2017 00:00:00'
AND date_time <= '15-Apr-2017 23:59:59'
)
)
ORDER BY date_time ASC
,NAME
,ASC
Got this solved by using a day column. Here goes the query:
SELECT DISTINCT DISTINCT DATEADD(DAY, DATEDIFF(DAY, 0, date_time), 0) AS theDay
,user_table.user_id
,diary_table.date_time
,user_table.NAME
FROM user_table
INNER JOIN diary_table ON user_table.user_id = diary_table.diary_user_id
AND (
date_time >= '06-Apr-2017 00:00:00'
AND date_time <= '15-Apr-2017 23:59:59'
)
AND diar_user_id IN (
SELECT DISTINCT diar_user_id
FROM diary_table
INNER JOIN event_table ON event_table.event_id = diary_table.diar_event_id
WHERE event_table.event_name = 'Lunch'
AND (
date_time >= '06-Apr-2017 00:00:00'
AND date_time <= '15-Apr-2017 23:59:59'
)
)
ORDER BY theDay
,NAME ASC
,date_time ASC