SQL - Group Table by entries X amount of time from each other - mysql

I need to group together the entries in which the timestamp difference between one and the other is X amount of seconds or less than then average the value for each of them for each of the devices. In the following example I have a Table with this data and I need to group by device with entries between 60 seconds from each other.
Device Timestamp Value
0 30:8c:fb:a4:b9:8b 10/26/2015 22:50:15 34
1 30:8c:fb:a4:b9:8b 10/26/2015 22:50:46 34
2 c0:ee:fb:35:ec:cd 10/26/2015 22:50:50 33
3 c0:ee:fb:35:ec:cd 10/26/2015 22:50:51 32
4 30:8c:fb:a4:b9:8b 10/26/2015 22:51:15 34
5 30:8c:fb:a4:b9:8b 10/26/2015 22:51:47 32
6 c0:ee:fb:35:ec:cd 10/26/2015 22:52:38 38
7 30:8c:fb:a4:b9:8b 10/26/2015 22:54:46 34
This should be the resulting Table
Device First_seen Last_seen Average_value
0 30:8c:fb:a4:b9:8b 10/26/2015 22:50:15 10/26/2015 22:51:47 33,5
1 c0:ee:fb:35:ec:cd 10/26/2015 22:50:50 10/26/2015 22:50:51 32,5
2 c0:ee:fb:35:ec:cd 10/26/2015 22:52:38 10/26/2015 22:52:38 38
3 30:8c:fb:a4:b9:8b 10/26/2015 22:54:46 10/26/2015 22:54:46 34
Thank you very much for your help.

There is an old trick for this!
Mostly based on power of Window functions
Perfectly works for BigQuery!
So, first you "mark" all entries which exceed 60 seconds after previous entry!
Those which exceed getting value 1 and rest getting value 0!
Secondly you define groups by summing all previous marks (of course steps above are done while partitioning by device)
And finally, you just do simple grouping by above defined groups
Three simple steps implemented in one query with few simple sub-selects!
Hope this helps
SELECT device, MIN(ts) AS first_seen, MAX(ts) AS last_seen, AVG(value) AS average_value
FROM (
SELECT device, ts, value, SUM(grp_start) OVER (PARTITION BY device ORDER BY ts) AS grp
FROM (
SELECT device, ts, value,
IF(TIMESTAMP_TO_SEC(TIMESTAMP(ts))-TIMESTAMP_TO_SEC(TIMESTAMP(ts0))>60,1,0) AS grp_start
FROM (
SELECT device, ts, value, LAG(ts, 1) OVER(PARTITION BY device ORDER BY ts) AS ts0
FROM yourTable
)
)
)
GROUP BY device, grp

Here's one way...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(device CHAR(1) NOT NULL
,timestamp DATETIME NOT NULL
,value INT NOT NULL
,PRIMARY KEY(device,timestamp)
);
INSERT INTO my_table VALUES
('a','2015/10/26 22:50:15',34),
('a','2015/10/26 22:50:46',34),
('b','2015/10/26 22:50:50',33),
('b','2015/10/26 22:50:51',32),
('a','2015/10/26 22:51:15',34),
('a','2015/10/26 22:51:47',32),
('b','2015/10/26 22:52:38',38),
('a','2015/10/26 22:54:46',34);
SELECT m.*
, AVG(n.value) avg
FROM
( SELECT a.device
, a.timestamp start
, MIN(c.timestamp) end
FROM
( SELECT x.*
, CASE WHEN x.device = #prev THEN #i:=#i+1 ELSE #i:=1 END i
, #prev:=device
FROM my_table x
, (SELECT #i:=1,#prev:=null) vars
ORDER
BY device
, timestamp
) a
LEFT
JOIN
( SELECT x.*
, CASE WHEN x.device = #prev THEN #i:=#i+1 ELSE #i:=1 END i
, #prev:=device
FROM my_table x
, (SELECT #i:=1,#prev:=null) vars
ORDER
BY device
, timestamp
) b
ON b.device = a.device
AND b.timestamp > a.timestamp - INTERVAL 60 SECOND
AND b.i = a.i - 1
LEFT
JOIN
( SELECT x.*
, CASE WHEN x.device = #prev THEN #i:=#i+1 ELSE #i:=1 END i
, #prev:=device
FROM my_table x
, (SELECT #i:=1,#prev:=null) vars
ORDER
BY device
, timestamp
) c
ON c.device = a.device
AND c.i >= a.i
LEFT
JOIN
( SELECT x.*
, CASE WHEN x.device = #prev THEN #i:=#i+1 ELSE #i:=1 END i
, #prev:=device
FROM my_table x
, (SELECT #i:=1,#prev:=null) vars
ORDER
BY device
, timestamp
) d
ON d.device = c.device
AND d.i = c.i + 1
AND d.timestamp < c.timestamp + INTERVAL 60 SECOND
WHERE b.i IS NULL
AND c.i IS NOT NULL
AND d.i IS NULL
GROUP
BY a.device
, a.i
) m
JOIN my_table n
ON n.device = m.device
AND n.timestamp BETWEEN start AND end
GROUP
BY m.device
, m.start;
+--------+---------------------+---------------------+---------+
| device | start | end | avg |
+--------+---------------------+---------------------+---------+
| a | 2015-10-26 22:50:15 | 2015-10-26 22:51:47 | 33.5000 |
| a | 2015-10-26 22:54:46 | 2015-10-26 22:54:46 | 34.0000 |
| b | 2015-10-26 22:50:50 | 2015-10-26 22:50:51 | 32.5000 |
| b | 2015-10-26 22:52:38 | 2015-10-26 22:52:38 | 38.0000 |
+--------+---------------------+---------------------+---------+

Related

How to return the number of sets for each date

I am running a query that returns:
Date Set Data
2021-07-02 1 A
2021-07-02 2 B
2021-07-02 3 C
2021-08-15 1 D
2021-10-27 1 E
2021-10-27 2 F
I need to also return the number of Sets for each date:
Date Set Data NoSets
2021-07-02 1 A 3
2021-07-02 2 B 3
2021-07-02 3 C 3
2021-08-15 1 D 1
2021-10-27 1 E 2
2021-10-27 2 F 2
SELECT csm_pat_exe_date.pedate_id, csm_patient_exercise.pat_exe_id,
csm_exercise_details.ede_id, csm_exercise.exe_id,
ses_pat_id, ses_pat_note, ses_pat_body_weight, ses_pat_blood_pressure, ses_pat_blood_glucose_level,
exe_name, ede_order, ede_type,
ede_unit, weekofyear(csm_pat_exe_date.pedate_date) AS weekNumber, csm_pat_exe_date.pedate_date, peds_id, peds_set, peds_result, pedate_note, t2.noSets
FROM csm_session_patient, csm_session, csm_exercise, csm_patient_exercise, csm_exercise_details,
csm_pat_exe_date_set, csm_pat_exe_date
INNER JOIN (
SELECT pedate_date, COUNT(*) as noSets
FROM csm_patient_exercise, csm_pat_exe_date
WHERE csm_patient_exercise.pat_id = '1'
AND csm_patient_exercise.pat_exe_id = csm_pat_exe_date.pat_exe_id
GROUP BY pedate_date
) t2 ON csm_pat_exe_date.pedate_date = t2.pedate_date
WHERE csm_session_patient.pat_id= '1'
AND csm_session_patient.ses_id = csm_session.ses_id
AND csm_session.ses_date = csm_pat_exe_date.pedate_date
AND exe_archived IS NULL
AND csm_exercise.exe_id = csm_patient_exercise.exe_id
AND csm_patient_exercise.pat_exe_id = '1'
AND csm_patient_exercise.exe_id = csm_patient_exercise.pat_exe_id
AND csm_patient_exercise.pat_exe_id = csm_pat_exe_date.pat_exe_id
AND csm_pat_exe_date.pedate_date >= '2021-06-01'
AND csm_pat_exe_date.pedate_date <= '2021-09-24'
AND csm_pat_exe_date.pedate_id = csm_pat_exe_date_set.pedate_id
AND csm_pat_exe_date_set.ede_id = csm_exercise_details.ede_id
ORDER BY csm_pat_exe_date.pedate_date, peds_set, ede_order;
You may add the count window function to your select clause eg
Mysql 8+
SELECT
`Date`,
`Set`,
`Data`,
`NoSets`,
COUNT(*) OVER (PARTITION BY Date) as NoSets
FROM
...include the rest of your query here
Older Mysql Versions
You may use variables or aggregates to achieve your count
Schema (MySQL v5.5)
CREATE TABLE my_table (
`Date` DATETIME,
`Set` INTEGER,
`Data` VARCHAR(1)
);
INSERT INTO my_table
(`Date`, `Set`, `Data`)
VALUES
('2021-07-02', '1', 'A'),
('2021-07-02', '2', 'B'),
('2021-07-02', '3', 'C'),
('2021-08-15', '1', 'D'),
('2021-10-27', '1', 'E'),
('2021-10-27', '2', 'F');
Query #1
SELECT
`Date`,
`Set`,
`Data`,
`NoSets`
FROM (
SELECT
t.*,
#maxcnt:=IF(#prevdate2=`DATE`,IF(#maxcnt>cnt,#maxcnt,cnt),cnt) as NoSets,
#prevdate2:=`Date`
FROM (
SELECT
#cnt:=IF(#prevdate1=`DATE`,#cnt+1,1) as cnt,
#prevdate1:=`Date`,
m.*
FROM
my_table m
CROSS JOIN (SELECT #cnt:=0,#prevdate1:=NULL) vars
ORDER BY `Date`
) t
CROSS JOIN (SELECT #maxcnt:=0,#prevdate2:=NULL) vars
ORDER BY `Date`,cnt DESC
) t2;
Date
Set
Data
NoSets
2021-07-02 00:00:00
3
C
3
2021-07-02 00:00:00
2
B
3
2021-07-02 00:00:00
1
A
3
2021-08-15 00:00:00
1
D
1
2021-10-27 00:00:00
2
F
2
2021-10-27 00:00:00
1
E
2
Query #2
SELECT
t1.`Date`,
t1.`Set`,
t1.`Data`,
t2.`NoSets`
FROM
my_table t1
INNER JOIN (
SELECT `Date`, COUNT(*) as NoSets
FROM my_table
GROUP BY `Date`
) t2 ON t1.`Date`=t2.`Date`;
Date
Set
Data
NoSets
2021-07-02 00:00:00
1
A
3
2021-07-02 00:00:00
2
B
3
2021-07-02 00:00:00
3
C
3
2021-08-15 00:00:00
1
D
1
2021-10-27 00:00:00
1
E
2
2021-10-27 00:00:00
2
F
2
or
SELECT
t1.`Date`,
t1.`Set`,
t1.`Data`,
(
SELECT COUNT(*) FROM my_table t2 WHERE t2.Date=t1.Date
) as `NoSets`
FROM
my_table t1
View on DB Fiddle
Let me know if this works for you.

Calculate difference between min and max for each column only if higher then 0

I need to calculate the difference between odds based on the value in the 'updated' column at the moment I take odds where the updated value is a min and minus it from odds where the updated value is max. It works perfect but I've just realized that in some columns happens to be 0 sometimes and I was wondering if it's possible to select the minimum still based on the updated column and only values where higher than 0.
That's how the table looks like
fixture_id
H_odds
D_odds
A_odds
ev_tstamp
updated
120000
1.40
1.50
1.30
132000
12
120000
1.10
1.10
1.10
132000
11
120000
1.20
0
1.60
132000
10
And that's what I would like to get back
fixture_id
H_odds
D_odds
A_odds
ev_tstamp
updated
dif_h
dif_d
dif_a
120000
1.40
1.50
1.30
132000
12
0.2
0.4
-0.3
That's what I'm getting back at the moment
fixture_id
H_odds
D_odds
A_odds
ev_tstamp
updated
dif_h
dif_d
dif_a
120000
1.40
1.50
1.30
132000
12
0.2
1.5
-0.3
The code I'm using
select
t_max.*,
(t_max.H_odds - t_min.H_odds) as dif_h,
(t_max.D_odds - t_min.D_odds) as dif_d,
(t_max.A_odds - t_min.A_odds) as dif_a
from
(
select
fixture_id,
min(updated) min_updated,
max(updated) max_updated
from
test
group by
fixture_id
) as t1
join test as t_min on (t_min.fixture_id = t1.fixture_id and t_min.updated = t1.min_updated)
join test as t_max on (t_max.fixture_id = t1.fixture_id and t_max.updated = t1.max_updated)
Consider the following:
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(fixture_id INT NOT NULL
,updated INT NOT NULL
,outcome ENUM('Home win','Draw','Away win') NOT NULL
,odds DECIMAL(5,2) NOT NULL
,PRIMARY KEY(fixture_id,outcome,updated)
);
INSERT INTO my_table VALUES
(120,12,'Home win',1.40),
(120,11,'Home win',1.10),
(120,10,'Home win',1.20),
(120,12,'Draw',1.50),
(120,11,'Draw',1.10),
(120,12,'Away win',1.30),
(120,11,'Away win',1.10),
(120,10,'Away win',1.60);
Latest odds:
SELECT x.*
FROM my_table x
JOIN
( SELECT fixture_id
, outcome
, MAX(updated) min_updated
FROM my_table x
GROUP
BY fixture_id
, outcome
) y
ON y.fixture_id = x.fixture_id
AND y.outcome = x.outcome
AND y.min_updated = x.updated;
Earliest odds:
Earliest odds:
SELECT x.*
FROM my_table x
JOIN
( SELECT fixture_id
, outcome
, MIN(updated) min_updated
FROM my_table x
GROUP
BY fixture_id
, outcome
) y
ON y.fixture_id = x.fixture_id
AND y.outcome = x.outcome
AND y.min_updated = x.updated;
Delta:
SELECT a.*
, a.odds - b.odds delta
FROM
( SELECT x.*
FROM my_table x
JOIN
( SELECT fixture_id
, outcome
, MAX(updated) min_updated
FROM my_table x
GROUP
BY fixture_id
, outcome
) y
ON y.fixture_id = x.fixture_id
AND y.outcome = x.outcome
AND y.min_updated = x.updated
) a
JOIN
( SELECT x.*
FROM my_table x
JOIN
( SELECT fixture_id
, outcome
, MIN(updated) min_updated
FROM my_table x
GROUP
BY fixture_id
, outcome
) y
ON y.fixture_id = x.fixture_id
AND y.outcome = x.outcome
AND y.min_updated = x.updated
) b
ON b.fixture_id = a.fixture_id
AND b.outcome = a.outcome;
Result:
+------------+---------+----------+------+-------+
| fixture_id | updated | outcome | odds | delta |
+------------+---------+----------+------+-------+
| 120 | 12 | Home win | 1.40 | 0.20 |
| 120 | 12 | Draw | 1.50 | 0.40 |
| 120 | 12 | Away win | 1.30 | -0.30 |
+------------+---------+----------+------+-------+
This solution only works on MySQL 8+.
I would suggest window functions. The following treats each odds column separately . . . and it does not make any assumptions about the odds increasing or decreasing with each update:
select fixture_id, ev_tstamp, max(updated),
max(case when update = max_h_update then h_odds end) as max_h,
max(case when update = max_d_update then h_odds end) as max_d,
max(case when update = max_a_update then h_odds end) as max_a,
(max(case when update = max_h_update then h_odds end) -
max(case when update = min_h_update then h_odds end)
) as h_diff,
(max(case when update = max_d_update then d_odds end) -
max(case when update = min_d_update then d_odds end)
) as d_diff,
(max(case when update = max_a_update then a_odds end) -
max(case when update = min_a_update then a_odds end)
) as a_diff
from (select t.*,
max(case when h_odds <> 0 then update end) over (partition by fixture_id) as max_h_update,
min(case when h_odds <> 0 then update end) over (partition by fixture_id) as min_h_update,
max(case when d_odds <> 0 then update end) over (partition by fixture_id) as max_h_update,
min(case when d_odds <> 0 then update end) over (partition by fixture_id) as min_h_update,
max(case when a_odds <> 0 then update end) over (partition by fixture_id) as max_a_update,
min(case when a_odds <> 0 then update end) over (partition by fixture_id) as min_a_update
from test t
) t
group by fixture_id, ev_tstamp;
I just modify the code little bit to calculate the difference only for specific group of odds (avg) so it look like bellow. It worked just once though, it took over 15 seconds to process and the other times I tried it didn't work due to time out error. Just to clarify in my structure the market column is the 'outcome' column from your example.
explain SELECT a.*
, a.odds - b.odds delta
FROM
( SELECT x.*
FROM average_odds x
JOIN
( SELECT fix_id
, market
, MAX(updated) min_updated
FROM average_odds x where odds_type=avg
GROUP BY fix_id
, market
) y
ON y.fix_id = x.fix_id
AND y.market = x.market
AND y.min_updated = x.updated
) a
JOIN
( SELECT x.*
FROM average_odds x
JOIN
( SELECT fix_id
, market
, MIN(updated) min_updated
FROM average_odds x where odds_type=avg
GROUP BY fix_id
, market
) y
ON y.fix_id = x.fix_id
AND y.market = x.market
AND y.min_updated = x.updated
) b
ON b.fix_id = a.fix_id
AND b.market = a.market
ORDER BY `delta` ASC
That's the explain table
ID
S TYPE
table..
parti
type
pos_keys
KEY
key len
ref
rows
filtered
extra
1
PRIMARY
derived3>
null
all
null
null
null
null
17466
100.00
Using temporary; Using filesort
1
PRIMARY
x
null
ref
fix,fixi,market,updat
fix
4
y.fix_id
596
0.11
Using where
1
PRIMARY
x
null
ref
fix,fixi,market,updat
fix
4
y.fix_id
596
2.27
Using where
1
PRIMARY
derived5>
null
ref
auto_key0>
auto_key0>
31
y.fix_id,y.market,bobi.x.updated
10
100.00
using index
5
DERIVED
x
null
ref
boki
boki
4
const
17466
100.00
Using index condition; Using temporary; Using file...
3
DERIVED
x
null
ref
boki
boki
4
const
17466
100.00
Using index condition; Using temporary; Using file...

sql server 2008 running totals between 2 dates

I need to get running totals between 2 dates in my sql server table and update the records simultaneoulsy. My data is as below and ordered by date,voucher_no
DATE VOUCHER_NO OPEN_BAL DEBITS CREDITS CLOS_BAL
-------------------------------------------------------------------
10/10/2017 1 100 10 110
12/10/2017 2 110 5 105
13/10/2017 3 105 20 125
Now if i insert a record with voucher_no 4 on 12/10/2017 the output should be like
DATE VOUCHER_NO OPEN_BAL DEBITS CREDITS CLOS_BAL
------------------------------------------------------------------
10/10/2017 1 100 10 110
12/10/2017 2 110 5 105
12/10/2017 4 105 4 109
13/10/2017 3 109 20 129
I have seen several examples which find running totals upto a certain date but not between 2 dates or from a particular date to end of file
You should consider changing your database structure. I think it will be better to keep DATE, VOUCHER_NO, DEBITS, CREDITS in one table. And create view to calculate balances. In that case you will not have to update table after each insert. In this case your table will look like
create table myTable (
DATE date
, VOUCHER_NO int
, DEBITS int
, CREDITS int
)
insert into myTable values
('20171010', 1, 10, null),( '20171012', 2, null, 5)
, ('20171013', 3, 20, null), ('20171012', 4, 4, null)
And view will be
;with cte as (
select
DATE, VOUCHER_NO, DEBITS, CREDITS, bal = isnull(DEBITS, CREDITS) * case when DEBITS is null then -1 else 1 end
, rn = row_number() over (order by DATE, VOUCHER_NO)
from
myTable
)
select
a.DATE, a.VOUCHER_NO, a.DEBITS, a.CREDITS
, OPEN_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end) - a.bal
, CLOS_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end)
from
cte a
join cte b on a.rn >= b.rn
group by a.DATE, a.VOUCHER_NO, a.rn, a.bal, a.DEBITS, a.CREDITS
Here's another solution if you can not change your db structure. In this case you must run update statement each time after inserts. In both cases I assume that initial balance is 100 while recalculation
create table myTable (
DATE date
, VOUCHER_NO int
, OPEN_BAL int
, DEBITS int
, CREDITS int
, CLOS_BAL int
)
insert into myTable values
('20171010', 1, 100, 10, null, 110)
,( '20171012', 2, 110, null, 5, 105)
, ('20171013', 3, 105, 20, null, 125)
, ('20171012', 4, null, 4, null, null)
;with cte as (
select
DATE, VOUCHER_NO, DEBITS, CREDITS, bal = isnull(DEBITS, CREDITS) * case when DEBITS is null then -1 else 1 end
, rn = row_number() over (order by DATE, VOUCHER_NO)
from
myTable
)
, cte2 as (
select
a.DATE, a.VOUCHER_NO
, OPEN_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end) - a.bal
, CLOS_BAL = sum(b.bal + case when b.rn = 1 then 100 else 0 end)
from
cte a
join cte b on a.rn >= b.rn
group by a.DATE, a.VOUCHER_NO, a.rn, a.bal
)
update a
set a.OPEN_BAL = b.OPEN_BAL, a.CLOS_BAL = b.CLOS_BAL
from
myTable a
join cte2 b on a.DATE = b.DATE and a.VOUCHER_NO = b.VOUCHER_NO

MySQL Rolling Subtraction of a given qantity

I have a table like this:
CREATE TABLE `PQ_batch` (
`id` int(6) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Batch Id number',
`date` datetime DEFAULT NULL,
`qty` int(11) DEFAULT NULL COMMENT 'Number of units in a batch',
PRIMARY KEY (`bid`)
) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8;
Id | date | qty
--------------------------------
1 2017-01-06 5
2 2017-01-02 5
3 2017-01-03 100
Given a qty value of: #qtyToTake:=100
*Select the rows that will be needed to fulfill the #qtyToTake and ONLY these rows, the quantity that is to be taken from each row, and the new quantity that remains for that row. The oldest batches should be used up first. *
It should look something like this:
Id | date | qty | newQty | qtyTakenPerRecord
-------------------------------------------------------
1 2017-01-02 5 0 5
2 2017-01-03 100 5 95
3 2017-01-01 5 5 0
newQty = (qty - #qtyToTake) where #qtyToTake = (#qtyToTake - the previous row's qty until #qtyToTake reaches 0)
#qtyToTake should be dynamically assigned to be the difference of the previous row's qty and its current value until it reaches 0.
Here's what I came up with:
SELECT p.bid, p.Orig as origQty, p.NewQty, (p.Orig - p.NewQty) AS NumToTake
FROM(
SELECT b.bid, (#runtot := b.bqty - #runtot) AS remain, ( #runtot := (b.bqty - #runtot) ) leftToGet, b.bqty AS Orig,
(SELECT
(sum(bqty) - #runtot) AS tot FROM PQ_batch
WHERE bid <= b.bid ) AS RunningTotal,
(SELECT
CASE
WHEN (sum(bqty) - #runtot) > 1 THEN (sum(bqty) - #runtot)
ELSE 0
END
FROM PQ_batch
WHERE bid <= b.bid ) AS NewQty
FROM PQ_batch b,(SELECT #runtot:= 100) c
ORDER BY bdate
) AS p
Using #McNets example here's what I came up with:
SELECT bid, bdate,bpid,bcost, bqty, newQty, qtyTakenPerRecord
FROM (
SELECT y.*,
IF(#qtyToTake > 0, 1, 0) AS used,
IF(#qtyToTake > bqty, 0, bqty - #qtyToTake) AS newQty,
IF(#qtyToTake > bqty, bqty, bqty - (bqty - #qtyToTake)) AS qtyTakenPerRecord,
#qtyToTake := #qtyToTake - bqty AS qtyToTake
FROM
(SELECT #qtyToTake := 100) x,
(SELECT * from PQ_batch WHERE bpid =1002 AND bqty > 0 ORDER BY bdate) y
) z
WHERE used = 1
ORDER BY bdate

Count Age With Distinctly in MySQL

I have a table like this
PersonID Gender Age CreatedDate
================================
1 M 32 10/09/2011
2 F 33 10/09/2011
2 F 33 10/11/2011
1 M 32 10/11/2011
3 F 33 10/11/2011
I want to find Gender Count By Age with group by created date,The age range will be 30-34 and getting person will be distinctly.
Desired output should like this:
Gender AgeRange CreatedDate CountResult
================================
M 30_34 10/09/2011 1
F 30_34 10/09/2011 1
F 30_34 10/11/2011 1
So I tried this but couldtn help:
SELECT t.Gender,'30_34' AS AgeRange,t.CreatedDate,
SUM(CASE WHEN t.Age BETWEEN 30 AND 34 THEN 1 ELSE 0 END) AS CountResult,
FROM (
SELECT DISTINCT PersonID,Gender,Age,CreatedDate
FROM MyTable
GROUP PersonID,Gender,Age,CreatedDate
HAVING COUNT(PersonID)=1
) t
What can I do for solution?
Thanks
If you are want the earliest created date per personid this might do
drop table if exists mytable;
create table mytable(PersonID int, Gender varchar(1),Age int, CreatedDate date);
insert into mytable values
(1 , 'M', 32 , '2011-09-10'),
(2 , 'F', 33 , '2011-09-10'),
(2 , 'F', 33 , '2011-11-10'),
(1 , 'M', 32 , '2011-11-10'),
(3 , 'F', 33 , '2011-11-10');
select mt.gender,
mt.createddate,
sum(case when mt.age between 32 and 34 then 1 else 0 end) as Age32to34
from mytable mt
where createddate = (select min(mt1.createddate) from mytable mt1 where mt1.personid = mt.personid)
group by gender,mt.createddate
How about:
SELECT
Gender
, '30_34' AS AgeRange
, CreatedDate
, COUNT(*) AS CountResult
FROM MyTable A
JOIN (
SELECT PersonID, MIN(CreatedDate) MinCreatedDate
FROM MyTable GROUP BY PersonID
) B ON B.PersonID = A.PersonID AND B.MinCreatedDate = A.CreatedDate
WHERE Age BETWEEN 30 AND 34
GROUP BY Gender, CreatedDate
ORDER BY CreatedDate, Gender DESC
You would appear to want:
SELECT t.Gender, '30_34' AS AgeRange, t.CreatedDate,
COUNT(DISTINCT t.PersonId) AS CountResult
FROM MyTable
WHERE t.Age BETWEEN 30 AND 34
GROUP BY t.Gender, t.CreatedDate;