How can I group and sum data by day using T-SQL? - sql

I have a table like this
datex | countx |
---------------------
2022-12-04 | 1 |
2022-12-03 | 2 |
2022-12-02 | 1 |
2022-12-01 | 3 |
2022-11-30 | 1 |
2022-11-29 | 1 |
2022-11-28 | 1 |
2022-11-27 | 2 |
I want to get this output
datex | count_sum |
-------------------------
2022-12 | 4 |
2022-12-01 | 3 |
2022-11 | 5 |
So far I tried some group by clause but I didn't succeed.
Here is test code
declare #test table
(
datex date,
countx int
)
insert into #test
values ('2022-12-04', 1),
('2022-12-03', 2),
('2022-12-02', 1),
('2022-12-01', 3),
('2022-11-30', 1),
('2022-11-29', 1),
('2022-11-28', 1),
('2022-11-27', 2)

You may use a case expression to check if the date is the first day of the month then aggregate as the following:
with check_date as
(
select case
when Day([date])=1
Then Cast([date] as varchar(10))
else Format([date], 'yyyy-MM')
end As dt,
[count]
from table_name
)
select dt, sum([count]) as count_sum
from check_date
group by dt
order by dt desc
See demo

As I understood you want to "extract" year and month from your datex column and count it. I think you can use below SQL:
with cte as(
select
concat(year(datex), '-', month(datex)) as datex,
countx
from test
where not datex in ( '2022-12-01' )
)
select
datex,
count(1)
from cte
group by datex;
Result:
date | count_sum |
-------------------------
2022-12 | 3 |
2022-11 | 4 |
Here is Fiddle.

Related

How to write a SQL query that generate values based on data in the table

I have a table that looks like the table below and I need to make a query that shows the previous price of the Stock
Stock_ID | Stock_Code | Price | From_date | To_date
-----------+------------+-------+------------+-----------
1 | XYZ | 71 | 2013-01-05 | 2013-01-06
1 | XYZ | 72 | 2013-01-07 | 2013-01-08
1 | XYZ | 74 | 2013-01-09 | 2013-01-10
2 | QWE | 24 | 2013-01-05 | 2013-01-06
2 | QWE | 22 | 2013-01-07 | 2013-01-08
2 | QWE | 30 | 2013-02-09 | 2013-01-10
The query should resulted in something like this:
Stock_ID | Stock_Code | Price | From_date | To_date | Previous_Price
-----------+------------+-----+--------------+---------------------------
1 | XYZ | 71 | 2013-01-05 | 2013-01-06| null
1 | XYZ | 72 | 2013-01-07 | 2013-01-08| 71
1 | XYZ | 74 | 2013-01-09 | 2013-01-10| 72
2 | QWE | 24 | 2013-01-05 | 2013-01-06| null
2 | QWE | 22 | 2013-01-07 | 2013-01-08| 24
2 | QWE | 30 | 2013-02-09 | 2013-01-10| 22
what I tried:
SELECT *,
(SELECT Price
WHERE To_date in (SELECT DATEADD(day, -1, From_date) from StockTable))
FROM StockTable
However, the order is incorrect and the null is showed in the bottom.
I suspect this is because it's a totally separate query and the second query does not directly uses the date from the SELECT * table.
I included Order By as well as suggested by one of the comments, but it still doesn't work.
Is it possible to do so without creating a new table and use join? What can I do to obtain the result?
Perhaps the window function lag() over() would be a good fit here
Select *
,Prev_Price = lag(Price) over (partition by Stock_ID order by From_date)
from YourTable
Results
A first principles approach is to simply use an inline query to select the previous record. It not a generally efficient solution but if the dates are contiguous and there are not many records for each Stock_Code then the performance might be acceptable:
SELECT s.Stock_ID, s.Stock_Code, s.Price, s.From_date, s.To_date
, (SELECT Price
FROM StockTable lst
WHERE lst.Stock_ID = s.Stock_ID
AND lst.Stock_Code = s.Stock_Code
AND lst.To_date = (
SELECT MAX(To_date)
FROM StockTable mx
WHERE mx.Stock_ID = s.Stock_ID
AND mx.Stock_Code = s.Stock_Code
AND mx.To_date < s.To_Date
)
) as Previous_Price
FROM StockTable s
You could however simplify this with a simple LAG window query:
SELECT Stock_ID, Stock_Code, Price, From_date, To_date
, LAG (Price, 1, 0)
OVER (PARTITION BY Stock_ID, Stock_Code
ORDER BY To_Date)
as Previous_Price
FROM StockTable s
Try this fiddle for proof: http://sqlfiddle.com/#!18/a4372/2
I'm not sure that is the best solution, but:
create table #temp(
Stock_ID INT,
Stock_Code NChar(5),
Price INT,
From_Date DATE,
To_Date DATE
)
INSERT INTO #temp VALUES
(1, 'XYZ', 71, '2013-01-05', '2013-01-06'),
(1, 'XYZ', 72, '2013-01-07', '2013-01-08'),
(1, 'XYZ', 74, '2013-01-09', '2013-01-10'),
(2, 'QWE', 24, '2013-01-05', '2013-01-06'),
(2, 'QWE', 22, '2013-01-07', '2013-01-08'),
(2, 'QWE', 30, '2013-01-09', '2013-01-10')
SELECT
t1.Stock_ID,
t1.Stock_Code,
t1.Price,
t1.From_Date,
t1.To_Date,
(SELECT
t3.Price [Previouse_Price]
FROM
#temp t3
INNER JOIN
(SELECT
MAX(t2.From_Date) [Previouse_Date]
FROM
#temp t2
WHERE
t1.Stock_ID = t2.Stock_ID
AND
t1.Stock_Code = t2.Stock_Code
AND
t1.From_Date > t2.From_Date
) A ON A.Previouse_Date = t3.From_Date
WHERE
t1.Stock_ID = t3.Stock_ID
AND
t1.Stock_Code = t3.Stock_Code)
FROM #temp t1

Split a date range in SQL Server

I'm struggling with a solution for a problem but I couldn't find anything similar here.
I have a table "A" like:
+---------+------------+------------+-----------+
| user_id | from | to | attribute |
+---------+------------+------------+-----------+
| 1 | 2020-01-01 | 2020-12-31 | abc |
+---------+------------+------------+-----------+
and I get a table "B" like:
+---------+------------+------------+-----------+
| user_id | from | to | attribute |
+---------+------------+------------+-----------+
| 1 | 2020-03-01 | 2020-04-15 | def |
+---------+------------+------------+-----------+
And what I need is:
+---------+------------+------------+-----------+
| user_id | from | to | attribute |
+---------+------------+------------+-----------+
| 1 | 2020-01-01 | 2020-02-29 | abc |
| 1 | 2020-03-01 | 2020-04-15 | def |
| 1 | 2020-04-16 | 2020-12-31 | abc |
+---------+------------+------------+-----------+
I tried just using insert and update but I couldn't figure out how to simultaneously do both. Is there a much simpler way? I read about CTE, could this be an approach?
I'd be very thankful for your help!
Edit: more examples
TABLE A
| user_id | from | to | attribute |
+=========+============+============+===========+
| 1 | 2020-01-01 | 2020-12-31 | atr1 |
| 1 | 2021-01-01 | 2021-12-31 | atr2 |
| 2 | 2020-01-01 | 2021-06-15 | atr1 |
| 3 | 2020-01-01 | 2021-06-15 | atr3 |
TABLE B
| user_id | from | to | attribute |
+=========+============+============+===========+
| 1 | 2020-09-01 | 2021-02-15 | atr3 |
| 2 | 2020-04-15 | 2020-05-31 | atr2 |
| 3 | 2021-04-01 | 2022-01-01 | atr1 |
OUTPUT:
| user_id | from | to | attribute |
+=========+============+============+===========+
| 1 | 2020-01-01 | 2020-08-31 | atr1 |
| 1 | 2020-09-01 | 2021-02-15 | atr3 |
| 1 | 2021-02-16 | 2021-12-31 | atr2 |
| 2 | 2020-01-01 | 2020-04-14 | atr1 |
| 2 | 2020-04-15 | 2020-05-31 | atr2 |
| 2 | 2020-06-01 | 2021-06-15 | atr1 |
| 3 | 2020-01-01 | 2021-03-31 | atr3 |
| 3 | 2021-04-01 | 2022-01-01 | atr1 |
Initially I just asked to split the date range and make a new row because the new attribute of table B is between the one in table A. But it's only a part of the problem. Maybe it's more clear with the new dataset(?)
Sample data,
create table #TableA( userid int, fromdt date
,todt date, attribute varchar(10))
insert into #TableA (userid , fromdt , todt , attribute)
values
( 1 ,'2020-01-01','2020-12-31' , 'atr1' ),
( 1 ,'2021-01-01','2021-12-31' , 'atr2' ),
( 2 ,'2020-01-01','2021-06-15' , 'atr1' ),
( 3 ,'2020-01-01','2021-06-15' , 'atr3' )
create table #TableB( userid int,fromdt date
,todt date, attribute varchar(10))
insert into #TableB (userid,fromdt, todt, attribute)
values
( 1 ,'2020-09-01','2021-02-15' , 'atr3' ),
( 2 ,'2020-04-15','2020-05-31' , 'atr2' ),
( 3 ,'2021-04-01','2022-01-01' , 'atr1' )
;
The Script,
;WITH CTE
AS (
SELECT *
FROM #TableA
UNION ALL
SELECT *
FROM #TableB
)
,CTE2
AS (
SELECT userid
,min(fromdt) minfromdt
,max(todt) maxtodt
FROM CTE
GROUP BY userid
)
,CTE3
AS (
SELECT c.userid
,c.fromdt
,c.todt
,c.attribute
,LEAD(c.fromdt, 1) OVER (
PARTITION BY c.userid ORDER BY c.fromdt
) LeadFromdt
FROM CTE c
)
,CTE4
AS (
SELECT c3.userid
,c3.fromdt
,CASE
WHEN c3.todt > c3.LeadFromdt
THEN dateadd(day, - 1, c3.leadfromdt)
--when c3.todt<c3.LeadFromdt then dateadd(day,-1,c3.leadfromdt)
ELSE c3.todt
END AS Todt
,
--c3.todt as todt1,
c3.attribute
FROM CTE3 c3
)
,CTE5
AS (
SELECT userid
,fromdt
,todt
,attribute
FROM CTE4
UNION ALL
SELECT c2.userid
,dateadd(day, 1, c4.Todt) AS Fromdt
,maxtodt AS Todt
,c4.attribute
FROM CTE2 c2
CROSS APPLY (
SELECT TOP 1 c4.todt
,c4.attribute
FROM cte4 c4
WHERE c2.userid = c4.userid
ORDER BY c4.Todt DESC
) c4
WHERE c2.maxtodt > c4.Todt
)
SELECT *
FROM CTE5
ORDER BY userid
,fromdt
drop table #TableA, #TableB
Your output is wrong.
Also append other sample data in same example
where my script is not working.
The easiest way is to work with a calendar table. You can create one and reuse it later.
When you have one (here I called it "AllDates"), you can do something like this:
WITH cte
as
(
select ad.theDate,u.userid,isnull(b.attrib,a.attrib) as attrib,
ROW_NUMBER() over (PARTITION BY u.userid, isnull(b.attrib,a.attrib)ORDER BY ad.theDate)
- ROW_NUMBER() over (PARTITION BY u.userid ORDER BY ad.theDate) as grp
from AllDates ad
cross join (select userid from tableA union select userid from tableB) u
left join tableB b on ad.theDate between b.frm and b.toD and u.userid = b.userid
left join tableA a on ad.theDate between a.frm and a.toD and u.userid = a.userid
where b.frm is not null
or a.frm is not null
)
SELECT userid,attrib,min(theDate) as frmD, max(theDate) as toD
FROM cte
GROUP BY userid,attrib,grp
ORDER BY 1,3;
If I understand the request correctly the data from table A should be merged into table B to fill the gaps based on four scenarios, here is how I achieved it:
/*
Scenario 1 - Use dates from B as base to be filled in from A
- Start and end dates from B
*/
SELECT
B.UserId,
B.StartDate,
B.EndDate,
B.Attr
FROM #tmpB AS B
UNION
/*
Scenario 2 - Start date between start and end date of another record
- End date from B plus one day as start date
- End date from A as end date
*/
SELECT
B.UserId,
DATEADD(DD, 1, B.EndDate) AS StartDate,
A.EndDate,
A.Attr
FROM #tmpB AS B
JOIN #tmpA AS A ON
B.UserId = A.UserId
AND B.StartDate < A.StartDate
AND B.EndDate > A.StartDate
UNION
/*
Scenario 3 - End date between start and end date of another record or both dates between start and end date of another record
- Start date from A as start date
- Start date from B minus one as end date
*/
SELECT
B.UserId,
A.StartDate,
DATEADD(DD, -1, B.StartDate) AS EndDate,
A.Attr
FROM #tmpB AS B
JOIN #tmpA AS A ON
B.UserId = A.UserId
AND (B.StartDate < A.EndDate AND B.EndDate > A.EndDate
OR B.StartDate BETWEEN A.StartDate AND A.EndDate AND B.EndDate BETWEEN A.StartDate AND A.EndDate)
UNION
/*
Scenario 4 - Both dates between start and end date of another record
- End date from B minus one as start date
- End date from A as end date
*/
SELECT
B.UserId,
DATEADD(DD, -1, B.EndDate) AS StartDate,
A.EndDate,
A.Attr
FROM #tmpB AS B
JOIN #tmpA AS A ON
B.UserId = A.UserId
AND B.StartDate BETWEEN A.StartDate AND A.EndDate
AND B.EndDate BETWEEN A.StartDate AND A.EndDate

SQL difference between Multiple Rows having the same ID

SQL Sever 2012
Raw Data
ID VAL Time
+---+----+---------------------+
| 2 | 1 | 2015-05-09 12:54:39 |
| 3 | 10 | 2015-05-09 12:54:39 |
| 2 | 1 | 2015-05-09 12:56:39 |
| 3 | 10 | 2015-05-09 12:56:39 |
| 2 | 5 | 2015-05-09 13:48:30 |
| 3 | 16 | 2015-05-09 13:48:30 |
| 2 | 7 | 2015-05-09 15:01:09 |
| 3 | 20 | 2015-05-09 15:01:09 |
+---+----+---------------------+
I have a table where VAL is increasing forever in time. I want to manipulate the data to show how much VAL is increasing for each ID over time. So Val at Time2 - Val at Time1
Ideal Result:
ID VALI Time
+---+----+---------------------+
| 2 | 0 | 2015-05-09 12:56:39 |
| 3 | 0 | 2015-05-09 12:56:39 |
| 2 | 4 | 2015-05-09 13:48:30 |
| 3 | 6 | 2015-05-09 13:48:30 |
| 2 | 2 | 2015-05-09 15:01:09 |
| 3 | 4 | 2015-05-09 15:01:09 |
+---+----+---------------------+
Code so far:
select
t1.Time,t1.[ID],t2.[VAL]-t1.[VAL] AS [ValI]
from #tempTable t1
inner join #tempTable t2 ON t1.[ID]=t2.[ID]
AND t1.[Time]<t2.[Time]
I need to calculate the difference between the current timestamp and ONLY the Time right before current timestamp not all timestamps before the current timestamp. As of now I get a lot of repeating values when VAL did not change.
You can use this.
DECLARE #MyTable TABLE (ID INT, VAL INT, [Time] DATETIME)
INSERT INTO #MyTable VALUES
(2, 1 ,'2015-05-09 12:54:39'),
(3, 10 ,'2015-05-09 12:54:39'),
(2, 1 ,'2015-05-09 12:56:39'),
(3, 10 ,'2015-05-09 12:56:39'),
(2, 5 ,'2015-05-09 13:48:30'),
(3, 16 ,'2015-05-09 13:48:30'),
(2, 7 ,'2015-05-09 15:01:09'),
(3, 20 ,'2015-05-09 15:01:09')
;WITH CTE AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY [Time]) RN FROM #MyTable
)
SELECT T1.ID, T2.VAL - T1.VAL AS VALI, T2.Time FROM CTE T1
INNER JOIN CTE T2 ON T1.ID = T2.ID AND T1.RN = T2.RN - 1
ORDER BY T1.[Time], T1.ID
Result:
ID VALI Time
----------- ----------- -----------------------
2 0 2015-05-09 12:56:39.000
3 0 2015-05-09 12:56:39.000
2 4 2015-05-09 13:48:30.000
3 6 2015-05-09 13:48:30.000
2 2 2015-05-09 15:01:09.000
3 4 2015-05-09 15:01:09.000
Here this should work:
select id, time, val-prevval val1 from (
select * , lag(val, 1, 0) over(partition by id order by val, time) prevVal from #Temp)A
order by time
You could first put a Rank on your #tempTable ordered by Time descending, and partitioned by ID.
Then your join becomes this:
select
t1.Time,
t1.[ID],
t1.[VAL] - t2.[VAL] AS [ValI]
from #tempTable t1
inner join #tempTable t2 ON t1.[ID] = t2.[ID]
AND t2.Rank = (t1.Rank + 1)
LAG() became available in SQL 2012. This allows you to take the current row's val and subtract the val from the previous row, grouped by the id and sorted by Time. That will return NULL for the first two rows, since they don't have a previous record to compare to. You can exclude them by placing the query in a sub-select then applying a WHERE valDiff IS NULL, or you can default the valDiff using the third argument of LAG() > LAG(Val,1,0) to default the first two rows to 0.
SQL Fiddle
MS SQL Server 2017 Schema Setup:
CREATE TABLE t1 ( ID int, VAL int, [Time] datetime) ;
INSERT INTO t1 ( ID, Val, [Time] )
VALUES
( 2, 1 , '2015-05-09 12:54:39')
, ( 3, 10, '2015-05-09 12:54:39')
, ( 2, 1 , '2015-05-09 12:56:39')
, ( 3, 10, '2015-05-09 12:56:39')
, ( 2, 5 , '2015-05-09 13:48:30')
, ( 3, 16, '2015-05-09 13:48:30')
, ( 2, 7 , '2015-05-09 15:01:09')
, ( 3, 20, '2015-05-09 15:01:09')
;
Query 1:
SELECT s1.ID
, s1.ValDiff
, FORMAT(s1.[Time], 'yyyy-MM-dd hh:mm:ss') AS fTime
FROM (
SELECT ID
, Val - LAG(Val,1) OVER ( PARTITION BY ID ORDER BY [Time],ID ) AS ValDiff
, [Time]
FROM t1
) s1
WHERE s1.valDiff IS NOT NULL
ORDER BY s1.[Time],s1.ID
Results:
| ID | ValI | fTime |
|----|---------|---------------------|
| 2 | 0 | 2015-05-09 12:56:39 |
| 3 | 0 | 2015-05-09 12:56:39 |
| 2 | 4 | 2015-05-09 01:48:30 |
| 3 | 6 | 2015-05-09 01:48:30 |
| 2 | 2 | 2015-05-09 03:01:09 |
| 3 | 4 | 2015-05-09 03:01:09 |
If you have LAG
DEMO
SELECT
id
, val - LAG(val, 1) OVER (PARTITION BY id ORDER BY time ASC) AS VALI
, time
FROM #TempTable
ORDER BY time ASC, ID ASC

SQL group by on nested select statement

My data looks like this and here's google spread sheet
I want all the rows selected, along with an added extra row which is life of item (per item_code) in terms of weeks i.e. DATEDIFF(day, min(txn_date), txn_date)/7
I tried something like this:
SELECT txn_date, txn_qty, item_code,
( SELECT DATEDIFF(day, min(txn_date), txn_date)/7
FROM my_table
WHERE item_code like 'X6%'
GROUP BY item_code
) weeks_life
FROM my_table
WHERE item_code like 'X6%'
as for output, it should look like this:
I would use DATEDIFF and a MAX OVER clause for this.
declare #TEMP table (transaction_id int, txn_date date, txn_qty int, code char(5))
INSERT INTO #TEMP VALUES ( 1,'2016-09-20',1,'X6113')
INSERT INTO #TEMP VALUES ( 2,'2016-09-22',4,'X6113')
INSERT INTO #TEMP VALUES ( 3,'2016-11-08',7,'X6117')
INSERT INTO #TEMP VALUES ( 4,'2016-12-10',3,'X6117')
INSERT INTO #TEMP VALUES ( 5,'2016-12-22',1,'X6112')
INSERT INTO #TEMP VALUES ( 6,'2017-01-19',2,'X6118')
INSERT INTO #TEMP VALUES ( 7,'2017-02-11',4,'X6119')
INSERT INTO #TEMP VALUES ( 8,'2016-06-30',1,'X6117')
INSERT INTO #TEMP VALUES ( 9,'2016-08-03',5,'X6110')
INSERT INTO #TEMP VALUES (10,'2016-09-11',7,'X6118')
INSERT INTO #TEMP VALUES (11,'2016-10-29',1,'X6110')
INSERT INTO #TEMP VALUES (12,'2016-11-12',335,'X6113')
INSERT INTO #TEMP VALUES (13,'2017-01-06',1,'X6110')
INSERT INTO #TEMP VALUES (14,'2017-02-06',12,'X6113')
select transaction_id
,txn_date
,DATEDIFF(WEEK,MIN(txn_date) OVER(PARTITION BY code order by code),txn_date) as life_weeks
,txn_qty
,code
from #TEMP
References from MSDN
MAX (Transact-SQL)
OVER Clause (Transact-SQL)
DATEDIFF (Transact-SQL)
You can use window functions. I think this is what you want:
SELECT txn_date, txn_qty, item_code,
DATEDIFF(day,
MIN(txn_date) OVER (PARTITION BY item_code),
txn_date
)/7 as weeks_life
FROM my_table
WHERE item_code like 'X6%';
If you want to use an inline subquery like that, you could do this:
select
txn_date
, txn_qty
, item_code
, ceiling((
datediff(day, (
select min(txn_date)
from t i
where i.item_code = t.item_code
), txn_date)
) / 7.0) as weeks_life
from t
where item_code like 'X6%'
order by
item_code
, txn_date
cross apply() version:
select
txn_date
, txn_qty
, item_code
, ceiling((datediff(day, x.min_txn_date, txn_date)) / 7.0) as weeks_life
from t
cross apply (
select min_txn_date = min(txn_date)
from t i
where i.item_code = t.item_code
) as x
where item_code like 'X6%'
order by
item_code
, txn_date
inner join version:
select
t.txn_date
, t.txn_qty
, t.item_code
, ceiling((datediff(day, x.min_txn_date, t.txn_date)) / 7.0) as weeks_life
from t
inner join (
select min_txn_date = min(txn_date), item_code
from t i
group by item_code
) as x
on x.item_code = t.item_code
where t.item_code like 'X6%'
order by
t.item_code
, t.txn_date
rextester demo: http://rextester.com/BYTL99094
returns:
+------------+---------+-----------+------------+
| txn_date | txn_qty | item_code | weeks_life |
+------------+---------+-----------+------------+
| 2016-08-03 | 5 | X6110 | 0 |
| 2016-10-29 | 1 | X6110 | 13 |
| 2017-01-06 | 1 | X6110 | 23 |
| 2016-12-22 | 1 | X6112 | 0 |
| 2016-09-20 | 1 | X6113 | 0 |
| 2016-09-22 | 4 | X6113 | 1 |
| 2016-11-12 | 335 | X6113 | 8 |
| 2017-02-06 | 12 | X6113 | 20 |
| 2016-06-30 | 1 | X6117 | 0 |
| 2016-11-08 | 7 | X6117 | 19 |
| 2016-12-10 | 3 | X6117 | 24 |
| 2016-09-11 | 7 | X6118 | 0 |
| 2017-01-19 | 2 | X6118 | 19 |
| 2017-02-11 | 4 | X6119 | 0 |
+------------+---------+-----------+------------+

sum 2 fields by row and query max value by day per month

I have used SQL for simple queries, but now need to perform something a bit more complex. I am not sure how to nest the queries.
I have one table with the following columns:
Date, Daily Power, Daily Power 1, Daily power2
I need to find that max daily values and then filter by months. Also I need Daily Power 1 and Daily Power 2 summed into a new column.
Any help would be appreciated.
Part of the problem with your table is that the data is not normalized since you have 3 columns each containing a separate value for DailyPower.
One way that you can easily get the result that you need is to unpivot the data using a UNION ALL query.
This query will take the data from the multiple columns and turn it into multiple rows for use:
select date, 'DailyPower' as col, DailyPower as value
from yourtable
union all
select date, 'DailyPower1' as col, DailyPower1 as value
from yourtable
union all
select date, 'DailyPower2' as col, DailyPower2 as value
from yourtable
See SQL Fiddle with Demo. This query takes the data and converts it into the result:
| DATE | COL | VALUE |
------------------------------------
| 2012-01-01 | DailyPower | 456 |
| 2012-01-02 | DailyPower | 789 |
| 2012-02-01 | DailyPower | 23 |
| 2012-01-01 | DailyPower1 | 789 |
| 2012-01-02 | DailyPower1 | 235 |
| 2012-02-01 | DailyPower1 | 89 |
| 2012-01-01 | DailyPower2 | 65 |
| 2012-01-02 | DailyPower2 | 45 |
| 2012-02-01 | DailyPower2 | 10 |
Once the data is in the rows, then it is easier to get the max() value by date.
Your query would be similar to the following:
select date,
max(value) MaxDailyPower,
sum(case when col in ('DailyPower1', 'DailyPower2') then value end) TotalDailyPower
from
(
select date, 'DailyPower' as col, DailyPower as value
from yourtable
union all
select date, 'DailyPower1' as col, DailyPower1 as value
from yourtable
union all
select date, 'DailyPower2' as col, DailyPower2 as value
from yourtable
) src
where date >= '2012-01-01'
and date <= '2012-12-31'
group by date
See SQL Fiddle with Demo. This gives the result:
| DATE | MAXDAILYPOWER | TOTALDAILYPOWER |
------------------------------------------------
| 2012-01-01 | 789 | 854 |
| 2012-01-02 | 789 | 280 |
| 2012-02-01 | 89 | 99 |
Edit #1, if you want to GROUP BY month, then you could use:
select month(date) Month,
max(value) MaxDailyPower,
sum(case when col in ('DailyPower1', 'DailyPower2') then value end) TotalDailyPower
from
(
select date, 'DailyPower' as col, DailyPower as value
from yourtable
union all
select date, 'DailyPower1' as col, DailyPower1 as value
from yourtable
union all
select date, 'DailyPower2' as col, DailyPower2 as value
from yourtable
) src
group by month(date)
See SQL Fiddle with Demo
Is this what you want?
select date,
(case when DailyPower > DailyPower1 and DailyPower > DailyPower2 then DailyPower
when DailyPower1 > DailyPower2 then DailyPower1
else DailyPower2
) as MaxDailyPower,
coalesce(DailyPower1, 0) + Colaesce(DailyPower2) as DailyPowerSUm
from t
where date between '2012-01-01' and '2012-03-31' -- for the filter
This assumes that there is one row per date i nyour data.