How I can create this SELECT query in MYSQL? - mysql

I am having two MYSQL tables. These are named as :
attendance_summary, attendance_summary_cecb. Both tables have same fields but may have different data.
These are the result the month of August, 2016 from this two tables.
mysql> SELECT emp_id, date, days, ot_days, ot_hours FROM attendance_summary;
+--------+------------+------+---------+----------+
| emp_id | date | days | ot_days | ot_hours |
+--------+------------+------+---------+----------+
| 4 | 2016-08-01 | 10 | 0 | 20.0 |
| 4 | 2016-08-16 | 13 | 0 | 14.5 |
| 12 | 2016-08-01 | 12 | 0 | 10.0 |
| 12 | 2016-08-16 | 11 | 2 | 16.5 |
| 14 | 2016-08-01 | 12 | 2 | 15.0 |
| 14 | 2016-08-16 | 10 | 0 | 16.0 |
| 15 | 2016-08-01 | 11 | 0 | 16.0 |
| 15 | 2016-08-16 | 9 | 3 | 21.0 |
+--------+------------+------+---------+----------+
8 rows in set (0.00 sec)
mysql> SELECT emp_id, date, days, ot_days, ot_hours FROM attendance_summary_cecb;
+--------+------------+------+---------+----------+
| emp_id | date | days | ot_days | ot_hours |
+--------+------------+------+---------+----------+
| 4 | 2016-08-01 | 15 | 0 | 20.0 |
| 4 | 2016-08-16 | 10 | 0 | 12.0 |
| 12 | 2016-08-01 | 12 | 1 | 10.0 |
| 12 | 2016-08-16 | 11 | 2 | 16.5 |
| 14 | 2016-08-01 | 12 | 2 | 15.0 |
| 14 | 2016-08-16 | 10 | 0 | 16.0 |
| 15 | 2016-08-01 | 10 | 0 | 16.0 |
| 15 | 2016-08-16 | 9 | 0 | 21.0 |
+--------+------------+------+---------+----------+
8 rows in set (0.00 sec)
Using this two tables, In a single query, I need to get
> From `attendance_summary`
> - Total Days
> - Total OT Days
> - Total OT Hours
>
> From `attendance_summary_cecb`
> - Total Days
> - Total OT Days
> - Total OT Hours
This is how I tried it:
SELECT e.emp_id
, e.full_name
, MAX(days1) as days1
, MAX(ot_days1) as ot_days1
, MAX(ot_hours1) as ot_hours1
, MAX(days2) as days2
, MAX(ot_days2) as ot_days2
, MAX(ot_hours2) as ot_hours2
, SUM(days1+days2) AS olekma_days
, SUM(ot_days1+ot_days2) AS olekma_ot_days
, SUM(ot_hours1+ot_hours2) AS olekma_ot_hours
, SUM(days3+days4) AS cecb_days
, SUM(ot_days3+ot_days4) AS cecb_ot_days
, SUM(ot_hours3+ot_hours4) AS cecb_ot_hours
FROM
(
SELECT emp_id
, CASE DAY(date) WHEN 1 THEN days ELSE 0 END as days1
, CASE DAY(date) WHEN 1 THEN ot_days ELSE 0 END as ot_days1
, CASE DAY(date) WHEN 1 THEN ot_hours ELSE 0 END as ot_hours1
, CASE DAY(date) WHEN 16 THEN days ELSE 0 END as days2
, CASE DAY(date) WHEN 16 THEN ot_days ELSE 0 END as ot_days2
, CASE DAY(date) WHEN 16 THEN ot_hours ELSE 0 END as ot_hours2
FROM attendance_summary
WHERE MONTH(date) = 08 AND YEAR(date) = 2016
UNION
SELECT emp_id
, CASE DAY(date) WHEN 1 THEN days ELSE 0 END as days3
, CASE DAY(date) WHEN 1 THEN ot_days ELSE 0 END as ot_days3
, CASE DAY(date) WHEN 1 THEN ot_hours ELSE 0 END as ot_hours3
, CASE DAY(date) WHEN 16 THEN days ELSE 0 END as days4
, CASE DAY(date) WHEN 16 THEN ot_days ELSE 0 END as ot_days4
, CASE DAY(date) WHEN 16 THEN ot_hours ELSE 0 END as ot_hours4
FROM attendance_summary_cecb
WHERE MONTH(date) = 08 AND YEAR(date) = 2016
) as s
LEFT JOIN employees e USING (emp_id)
INNER JOIN categories c ON c.id = e.category_id AND c.salary_type = 'D'
WHERE e.category_id = 6
GROUP BY e.emp_id\G
UPDATE:
This is the table structure for these two tables:
CREATE TABLE `attendance_summary` (
`as_id` INT(11) NOT NULL AUTO_INCREMENT,
`emp_id` INT(11) NOT NULL,
`date` DATE NOT NULL DEFAULT '1901-01-01',
`days` INT(11) NOT NULL,
`ot_days` INT(11) NULL,
`ot_hours` DECIMAL(16,1) NULL,
PRIMARY KEY (`as_id`),
UNIQUE KEY (emp_id, `date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `attendance_summary_cecb` (
`as_id` INT(11) NOT NULL AUTO_INCREMENT,
`emp_id` INT(11) NOT NULL,
`date` DATE NOT NULL DEFAULT '1901-01-01',
`days` INT(11) NOT NULL,
`ot_days` INT(11) NULL,
`ot_hours` DECIMAL(16,1) NULL,
PRIMARY KEY (`as_id`),
UNIQUE KEY (emp_id, `date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
But it doesn't work for me. Hope somebody may help me out.

The answer to your question is rather simple. Btw I had to create 2 missing tables from the bottom to confirm your error.
When you do a
select col1, col2 from t1
union
select col9 as fred, col11 as john from t2
or any variation on that theme with scads of tables, the only column names that come back are from the first member of the union.
In other words, fred and john don't come out.
So your days3 and days4 are not available coming out of the derived table s.
You need to rethink it then, but that answers the question :p
From the MySQL Manual Page entitled UNION Syntax:
The column names from the first SELECT statement are used as the
column names for the results returned. Selected columns listed in
corresponding positions of each SELECT statement should have the same
data type. (For example, the first column selected by the first
statement should have the same type as the first column selected by
the other statements.)

Related

mysql - calculate difference between two dates

I have a table which looks like below.
CREATE TABLE `table_growth` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`timestamp` datetime DEFAULT CURRENT_TIMESTAMP,
`table_name` varchar(50) DEFAULT NULL,
`rows` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=184 DEFAULT CHARSET=utf8
Example of rows in the table:
+-----+---------------------+--------------------------+-------+
| id | timestamp | table_name | rows |
+-----+---------------------+--------------------------+-------+
| 110 | 2019-03-01 06:00:00 | attachments | 640 |
| 111 | 2019-03-01 06:00:00 | contacts | 0 |
| 112 | 2019-03-01 06:00:00 | copy_menuitem_options | 3038 |
| 113 | 2019-03-01 06:00:00 | copy_menuitem_suboptions | 9779 |
| 114 | 2019-03-01 06:00:00 | copy_menuitems | 12118 |
| 115 | 2019-03-02 06:00:00 | attachments | 638 |
| 116 | 2019-03-02 06:00:00 | contacts | 0 |
| 117 | 2019-03-02 06:00:00 | copy_menuitem_options | 3039 |
| 118 | 2019-03-02 06:00:00 | copy_menuitem_suboptions | 9789 |
| 119 | 2019-03-02 06:00:00 | copy_menuitems | 12128 |
+-----+---------------------+--------------------------+-------+
I want to calculate the diff(rows) between 2 days. like date(timestamp)='2019-03-02' - date(timestamp)='2019-03-01'
Expected results
table_name | Rows Diff
------------------------------
attachments | 2
contacts | 0
copy_menuitem_options | 1
copy_menuitem_suboptions| 10
copy_menuitems | 10
I tried these queries, but somewhere its failing.
SELECT x.table_name
, (y.rows-x.rows)as diff
FROM dbadmin.table_growth x
JOIN dbadmin.table_growth y
ON y.id = x.id
AND DATE(y.timestamp) = '2019-03-02'
WHERE DATE(x.timestamp) = '2019-03-01';
select x.table_name, (y.rows - x.rows) as doff
from table_growth x join
table_growth y on y.id=x.id and DATE(y.timestamp) = '2019-03-02'
WHERE DATE(x.timestamp) = '2019-03-01';
Your second query is on the right track, but the join condition is partially off. You should be asserting that the table names, not ids, match:
SELECT
x.table_name,
(x.rows - y.rows) AS diff
FROM table_growth x
INNER JOIN table_growth y
ON x.table_name = y.table_name and
DATE(y.timestamp) = '2019-03-02'
WHERE
DATE(x.timestamp) = '2019-03-01';
Note: Your current output is slightly ambiguous, because it is not clear which rows value comes first in the difference, or if perhaps you want to report an absolute value.
this will work;
select distinct a.table_name,(a.rows-b.rows) diff from table_growth a,table_growth b
where a.table_name=b.table_name;
If you have only one row per date, then this might be the fastest approach:
SELECT g.table_name,
SUM(CASE WHEN DATE(g.timestamp) = '2019-03-02'
THEN g.rows
WHEN DATE(g.timestamp) = '2019-03-01'
THEN -g.rows
ELSE 0
END) as diff
FROM dbadmin.table_growth g
WHERE g.timestamp >= '2019-03-01' AND
g.timestamp < '2019-03-03'
GROUP BY g.table_name;
In particular, this can make use of an index on table_growth(timestamp, table_name, rows).

Mysql Query with multiple subqueries with group by distinct condition

Hi I am a PHP Developer weak in MySQL Medium complex queries make my head fired.
The below is the table vulnerability.
+-----------------------------------------------------------------------------------------------+
| id | webisite_id | low_count| high_count | medium_count | date_time | vul_date |
+-----------------------------------------------------------------------------------------------+
| 20 | 6 | 1 | 1 | 1 | 2018-07-04 09:14:04 | 2018-02-01 |
| 19 | 6 | 30 | 30 | 30 | 2018-07-04 09:13:38 | 2018-01-30 |
| 18 | 6 | 1 | 1 | 1 | 2018-07-04 09:13:16 | 2018-01-01 |
+-----------------------------------------------------------------------------------------------+
This table represent count of low, medium, high - vulnerability count for each website in database. We can enter as many entries for each websites. But the only relevant entry for a website is the latest entry in each month (based on vul_date).
Here I need help I want query which fetch sum of counts low, high, medium of each websites of each month of last 1 year, for example if -> website with id 1 has 1, 2, 3 low, high, medium number of vulnerabilities, on month June and
-> that of with id 2 has 7, 8, 9 respectively the result should be for June 8, 10, 12. And like last 1 year's each month result should be get. If no entry it should be 0.
Note that the entries should be the maximum value of vul_date and if a site has multiple entries on the same vul_date get the latest date_time entry.
I tried to write question as much as simple. hope the question is understood.
Please help me on this
Thanks in advance.
I think below query will work for you.
SELECT
SUM(low_count),
SUM(medium_count),
SUM(high_count),
MONTH(vul_date)
FROM
(SELECT
low_count, medium_count, high_count, vul_date, date_time
FROM
test
WHERE
(website_id , vul_date) IN (SELECT website_id, MAX(vul_date)
FROM test GROUP BY website_id , MONTH(vul_date))) t
WHERE
date_time IN (SELECT MAX(date_time) FROM test GROUP BY website_id , vul_date)
GROUP BY MONTH(vul_date);
What it does is, first finds the latest entry month wise for each website id which is your max vul_date.
SELECT website_id, MAX(vul_date)
FROM test GROUP BY website_id , MONTH(vul_date)
If there are more than one entry for a vul_date, it uses date_time to select maximum value from them. Finally it sums all website date after grouping it month wise.
You can change the above query to get 0 value for those months where there is no entry for any websites.
DROP TABLE IF EXISTS T;
CREATE TABLE T(id INT, website_id INT, low_count INT, high_count INT, medium_count INT, date_time DATETIME, vul_date DATE);
INSERT INTO T VALUES
( 20 , 6 , 1 , 1 , 1, '2018-07-04 09:14:04' , '2018-02-01'),
( 19 , 6 , 30, 30, 30, '2018-07-04 09:13:38' , '2018-01-30'),
( 18 , 6 , 2 , 2 ,2 , '2018-07-04 09:13:16' , '2018-01-01'),
( 17 , 6 , 2 , 2 ,2 , '2018-07-04 09:12:01' , '2018-01-01'),
( 90 , 1,1,2,3,'2017-07-05 01:00:00',' 2017-07-06'),
( 90 , 2,8,9,10,'2017-07-05 01:00:00',' 2017-07-06');
select coalesce(c.yyyymm,d.yyyymm) yyyymm,
coalesce(c.lo,0) lo,
coalesce(c.hi,0) hi,
coalesce(c.med,0) med
from
(
SELECT concat(year(a.vul_date),'-',month(a.vul_date)) yyyymm,
SUM(LOW_COUNT) lo,SUM(HIGH_COUNT) hi,sum(medium_count) med
from
(
select website_id,date_time,vul_date
from t
where date_time = (select max(date_time) from t t1 where t1.website_id = t.website_id and t1.vul_date = t.vul_date)
) a
join
(select website_id, date_time,vul_date,
LOW_COUNT,HIGH_COUNT,medium_count
from t) b
on b.website_id = a.website_id and b.date_time = a.date_time
group by concat(year(a.vul_date),'-',month(a.vul_date))
) c
right join
(select distinct concat(year(dte),'-',month(dte)) yyyymm from dates d
where dte between date_sub(now(), interval 1 year) and now()
) d on d.yyyymm = c.yyyymm
;
Sub query a get the vul_date with the most recent data_time which is then self joined, aggregated and then infilled with missing dates using a right join to a dates/calender table. If you don't have a dates/calender it would be useful for this kind of exercise nut there are alternatives which you can find in SO.
Result
+---------+------+------+------+
| yyyymm | lo | hi | med |
+---------+------+------+------+
| 2017-7 | 9 | 11 | 13 |
| 2017-8 | 0 | 0 | 0 |
| 2017-9 | 0 | 0 | 0 |
| 2017-10 | 0 | 0 | 0 |
| 2017-11 | 0 | 0 | 0 |
| 2017-12 | 0 | 0 | 0 |
| 2018-1 | 32 | 32 | 32 |
| 2018-2 | 1 | 1 | 1 |
| 2018-3 | 0 | 0 | 0 |
| 2018-4 | 0 | 0 | 0 |
| 2018-5 | 0 | 0 | 0 |
| 2018-6 | 0 | 0 | 0 |
| 2018-7 | 0 | 0 | 0 |
+---------+------+------+------+
13 rows in set (0.04 sec)

Get all streaks of consecutive dates from a user score table

Table score_streak is used to store a user's daily scores and is defined as follows.
CREATE TABLE IF NOT EXISTS score_streak(
create_date DATE NOT NULL,
score INT(11),
PRIMARY KEY (create_date)
);
insert into score_streak (create_date, score) values
(DATE('2017-04-01'), 11) ,
(DATE('2017-04-02'), 8) ,
(DATE('2017-04-03'), 9) ,
(DATE('2017-04-06'), 14) ,
(DATE('2017-04-07'), 15) ,
(DATE('2017-04-08'), 13) ,
(DATE('2017-04-12'), 20) ,
(DATE('2017-04-13'), 21) ,
(DATE('2017-04-14'), 22) ,
(DATE('2017-04-15'), 18) ;
select * from score_streak;
create_date | score
2017-04-01 | 11
2017-04-02 | 8
2017-04-03 | 9
2017-04-06 | 14
2017-04-07 | 15
2017-04-08 | 13
2017-04-12 | 20
2017-04-13 | 21
2017-04-14 | 22
2017-04-15 | 18
I would like to query the table to get all streaks in which the user's score is greater than or equal to 10 and the dates must be consecutive. And each streak has a start date and an end date.
For example, the expected result of the sample data above is provided below (note that there are 3 streaks):
start_date | end_date |streak_count
2017-04-01 | 2017-04-01 | 1
2017-04-06 | 2017-04-08 | 3
2017-04-12 | 2017-04-15 | 4
Thanks.
You can do
SELECT MIN(create_date) start_date,
MAX(create_date) end_date,
COUNT(*) streak_count
FROM (
SELECT q.*,
#g := #g + COALESCE(DATEDIFF(create_date, #p) <> 1, 0) gn,
#p := create_date
FROM (
SELECT *
FROM score_streak
WHERE score > 9
ORDER BY create_date
) q CROSS JOIN (
SELECT #g := 0, #p := NULL
) i
) r
GROUP BY gn
Output:
+------------+------------+--------------+
| start_date | end_date | streak_count |
+------------+------------+--------------+
| 2017-04-01 | 2017-04-01 | 1 |
| 2017-04-06 | 2017-04-08 | 3 |
| 2017-04-12 | 2017-04-15 | 4 |
+------------+------------+--------------+
SQLFiddle

mysql select last 7 day query and if are more query in a day sum that and show only the sum

I want to show using select mysql the data_order is timestamp
firstly only the last 7 rows(which to contain the column price) from only each day of the last week including today like day-by-day. Suppose I have in every day (last 7 days) a single order is simple, but I don't know how to make the mysql statement when I have more orders in the same day
+-------------------------------------------------------------+
| table name `comanda` |
+-------------------------------------------------------------+
| id_comanda | keyUnique_comanda | pret_comanda| data_comanda |
+------------+-------------------+-------------+--------------+
| 1 | a1234 | 150 | today |
+------------+-------------------+-------------+--------------+
| 2 | b4321 | 300 | yesturday |
+------------+-------------------+-------------+--------------+
| 3 | b4321 | 200 | yesturday |
+------------+-------------------+-------------+--------------+
| 4 | c4321 | 100 | yesturday |
+------------+-------------------+-------------+--------------+
| 5 | d234 | 50 | 3 day ago |
+------------+-------------------+-------------+--------------+
| 6 | e453 | 200 | 9 day ago |
+------------+-------------------+-------------+--------------+
I tried something... but is not show me well
SELECT DAY(data_comanda) AS period, SUM(pret_comanda) AS total
FROM comanda
WHERE data_comanda >= CURDATE() + INTERVAL 1 WEEK
GROUP BY period
-- --------------------------------------------------------
--
-- Table structure for table `comanda`
--
CREATE TABLE `comanda` (
`id_comanda` int(11) NOT NULL,
`pret_comanda` varchar(255) NOT NULL,
`pret_comanda_total` int(11) NOT NULL,
`comanda` text NOT NULL,
`nume_comanda` varchar(255) NOT NULL,
`prenume_comanda` varchar(255) NOT NULL,
`email_comanda` varchar(255) NOT NULL,
`telefon_comanda` varchar(19) NOT NULL,
`judet_comanda` varchar(255) NOT NULL,
`adresa_comanda` varchar(2555) NOT NULL,
`clientIP` varchar(255) NOT NULL,
`localitate_comanda` varchar(255) NOT NULL,
`detalii_comanda` varchar(3000) CHARACTER SET utf8 NOT NULL,
`data_comanda` timestamp NOT NULL,
`data_comanda_finalizare` datetime DEFAULT NULL,
`produse_diferite_comanda` varchar(10) NOT NULL,
`keyUnique_comanda` varchar(25) NOT NULL,
`status_comanda` varchar(255) NOT NULL DEFAULT 'asteptare',
`admin_validare_comanda` varchar(255) NOT NULL DEFAULT 'neModificat'
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Instead of
WHERE data_comanda >= CURDATE() + INTERVAL 1 WEEK
you should use
WHERE data_comanda >= CURDATE() - INTERVAL 1 WEEK
But this will include today and the last 7 days (overall 8 days). If you only want 7 days overall you should use
WHERE data_comanda >= CURDATE() - INTERVAL 6 DAY
The query would now return
+--------+-------+
| period | total |
+--------+-------+
| 1 | 600 |
| 2 | 150 |
| 27 | 50 |
+--------+-------+
http://rextester.com/QSDUY96504
This might be confusing because DAY(data_comanda) returns the day of the month. So you might want to use DATE instead of DAY and get the result like:
+------------+-------+
| period | total |
+------------+-------+
| 27.02.2017 | 50 |
| 01.03.2017 | 600 |
| 02.03.2017 | 150 |
+------------+-------+
http://rextester.com/XOECI72414
To include the missing days you can create an inline table with numbers from 0 to 6
SELECT *
FROM (
SELECT 0 as diff UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6
) diffs
And now LEFT JOIN your table
SELECT CURDATE() - INTERVAL diffs.diff DAY AS period,
COALESCE(SUM(pret_comanda), 0) AS total
FROM (
SELECT 0 as diff UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6
) diffs
LEFT JOIN comanda c ON DATE(c.data_comanda) = CURDATE() - INTERVAL diffs.diff DAY
GROUP BY period;
Note that SUM(pret_comanda) will return NULL for missing days. To convert it to 0 you can use COALESCE(SUM(pret_comanda), 0)
Now the result would look like
+------------+-------+
| period | total |
+------------+-------+
| 24.02.2017 | 0 |
| 25.02.2017 | 0 |
| 26.02.2017 | 0 |
| 27.02.2017 | 50 |
| 28.02.2017 | 0 |
| 01.03.2017 | 600 |
| 02.03.2017 | 150 |
+------------+-------+
http://rextester.com/WJD33053

MySql query group by day and by time

I'm trying create an SQL query to resolve my problem.
My Table:
+----+---------------------+-------+
| id | date | value |
+----+---------------------+-------+
| 1 | 2014-10-10 05:10:10 | 10 |
+----+---------------------+-------+
| 2 | 2014-10-10 09:10:10 | 20 |
+----+---------------------+-------+
| 3 | 2014-10-10 15:10:10 | 30 |
+----+---------------------+-------+
| 4 | 2014-10-10 23:10:10 | 40 |
+----+---------------------+-------+
| 5 | 2014-10-11 08:10:10 | 15 |
+----+---------------------+-------+
| 6 | 2014-10-11 09:10:10 | 25 |
+----+---------------------+-------+
| 7 | 2014-10-11 10:10:10 | 30 |
+----+---------------------+-------+
| 8 | 2014-10-11 23:10:10 | 40 |
+----+---------------------+-------+
I want to sum value in groups by days and this days in three sub groups like a 'morning'(06:00 - 12:00), 'afternoon'(12:00 - 18:00) and 'night'(00:00 - 06:00 and 18:00 - 24:00).
something like this:
+------------+-------+---------+-----------+-------+
| date | value | morning | afternoon | night |
+------------+-------+---------+-----------+-------+
| 2014-10-10 | 100 | 20 | 30 | 50 |
+------------+-------+---------+-----------+-------+
| 2014-10-11 | 110 | 70 | 0 | 40 |
+------------+-------+---------+-----------+-------+
You could use a couple of sums over case expressions:
SELECT DAY(`date`) AS `date`
SUM(CASE WHEN HOUR(`date`) BETWEEN 6 AND 12 THEN value ELSE 0 END) AS `morning`,
SUM(CASE WHEN HOUR(`date`) BETWEEN 12 AND 18 THEN value ELSE 0 END) AS `afternoon`,
SUM(CASE WHEN HOUR(`date`) < 6 OR HOUR(`date`) > 18 THEN value ELSE 0 END) AS `evening`
FROM my_table
GROUP BY DAY(`date`)
There are multiple ways to go about this, but for myself I'd do it by first extracting the pseudo information in a CROSS APPLY, and then grouping on this information.
I believe this offers significant readibility benefits, and allows you to re-use any calculations in other clauses. For example, you have centralised the grouping mechanism, meaning that you only need to change it in the one place rather than in the select and the group by. Similarly, you could add "extraData.Morning = 1" to a WHERE clause rather than re-writing the calculation for mornings.
For example:
CREATE TABLE #TestData (ID INT, Data DATETIME, Value INT)
INSERT INTO #TestData (ID, Data, Value) VALUES
(1 ,'2014-10-10 05:10:10' ,10)
,(2 ,'2014-10-10 09:10:10' ,20)
,(3 ,'2014-10-10 15:10:10' ,30)
,(4 ,'2014-10-10 23:10:10' ,40)
,(5 ,'2014-10-11 08:10:10' ,15)
,(6 ,'2014-10-11 09:10:10' ,25)
,(7 ,'2014-10-11 10:10:10' ,30)
,(8 ,'2014-10-11 23:10:10' ,40)
SELECT
extraData.DayComponent
,SUM(td.Value)
,SUM(CASE WHEN extraData.Morning = 1 THEN td.Value ELSE 0 END) AS Morning
,SUM(CASE WHEN extraData.Afternoon = 1 THEN td.Value ELSE 0 END) AS Afternoon
,SUM(CASE WHEN extraData.Night = 1 THEN td.Value ELSE 0 END) AS Night
FROM #TestData td
CROSS APPLY (
SELECT
DATEADD(dd, 0, DATEDIFF(dd, 0, td.Data)) AS DayComponent
,CASE WHEN DATEPART(HOUR, td.Data) BETWEEN 6 AND 12 THEN 1 ELSE 0 END AS Morning
,CASE WHEN DATEPART(HOUR, td.Data) BETWEEN 12 AND 18 THEN 1 ELSE 0 END AS Afternoon
,CASE WHEN DATEPART(HOUR, td.Data) BETWEEN 0 AND 6
OR DATEPART(HOUR, td.Data) BETWEEN 18 AND 24 THEN 1 ELSE 0 END AS Night
) extraData
GROUP BY
extraData.DayComponent
DROP TABLE #TestData