How to sum rows before a condition is met in SQL - sql

I have a table which has multiple records for the same id. Looks like this, and the rows are sorted by sequence number.
+----+--------+----------+----------+
| id | result | duration | sequence |
+----+--------+----------+----------+
| 1 | 12 | 7254 | 1 |
+----+--------+----------+----------+
| 1 | 12 | 2333 | 2 |
+----+--------+----------+----------+
| 1 | 11 | 1000 | 3 |
+----+--------+----------+----------+
| 1 | 6 | 5 | 4 |
+----+--------+----------+----------+
| 1 | 3 | 20 | 5 |
+----+--------+----------+----------+
| 2 | 1 | 230 | 1 |
+----+--------+----------+----------+
| 2 | 9 | 10 | 2 |
+----+--------+----------+----------+
| 2 | 6 | 0 | 3 |
+----+--------+----------+----------+
| 2 | 1 | 5 | 4 |
+----+--------+----------+----------+
| 2 | 12 | 3 | 5 |
+----+--------+----------+----------+
E.g. for id=1, i would like to sum the duration for all the rows before and include result=6, which is 7254+2333+1000+5. Same for id =2, it would be 230+10+0. Anything after the row where result=6 will be left out.
My expected output:
+----+----------+
| id | duration |
+----+----------+
| 1 | 10592 |
+----+----------+
| 2 | 240 |
+----+----------+
The sequence has to be in ascending order.
I'm not sure how I can do this in sql.
Thank you in advance!

I think you want:
select t2.id, sum(t2.duration)
from t
where t.sequence <= (select t2.sequence
from t t2
where t2.id = t.id and t2.result = 6
);
In PrestoDB, I would recommend window functions:
select id, sum(duration)
from (select t.*,
min(case when result = 6 then sequence end) over (partition by id) as sequence_6
from t
) t
where sequence <= sequence_6;

You can use a simple aggregate query with a condition that uses a subquery to recover the sequence corresponding to the record whose sequence is 6 :
SELECT t.id, SUM(t.duration) total_duration
FROM mytable t
WHERE t.sequence <= (
SELECT sequence
FROM mytable
WHERE id = t.id AND result = 6
)
GROUP BY t.id
This demo on DB Fiddle with your test data returns :
| id | total_duration |
| --- | -------------- |
| 1 | 10592 |
| 2 | 240 |

Basic group by query should solve your issue
select
id,
sum(duration) duration
from t
group by id
for the certain rows:
select
id,
sum(duration) duration
from t
where id = 1
group by id
if you want to include it in your result set
select id, duration, sequence from t
union all
select
id,
sum(duration) duration
null sequence
from t
group by id

Related

Get min and count rows group by id

EDIT I forget an important detail
I have a postgresql table like this:
| id | n_1 | n_2 |
| 1 | 3 | 5 |
| 1 | 2 | 6 |
| 1 | 8 | 4 |
| 1 | 1 | 5 |
| 2 | 4 | 3 |
| 2 | 5 | 1 |
I want to get the min values and the count count only if n_2 >= min(n_1):
| id | n_1 | n_2 | count |
| 1 | 1 | 4 | 4 |
| 2 | 4 | 1 | 0 |
The min number from n_1, min number from n_2 and count total when n_2 >= min(n_1) records from each id.
Any help?
here how you can do it by grouping them by id :
select id , min(n_1) ,min(n_2), count(case when n_2 >= min_n_1 then 1 end)
from ( select *, min(n_1) over (partition by id) as min_n_1 from table) t
group by id
I think this is just aggregation:
select id, min(n_1), min(n_2), count(*)
from t
group by id;

Selecting rows that doesn't have duplicates

Let's say I have the following table:
| sku | id | value | count |
|-----|----|-------|-------|
| A | 1 | 1 | 2 |
| A | 1 | 2 | 2 |
| A | 3 | 3 | 3 |
I want to select rows that don't have the same count for the same id. So my desired outcome is:
| sku | id | value | count |
|-----|----|-------|-------|
| A | 3 | 3 | 3 |
I need something that works with Postgres 10
A simple method is window functions:
select t.*
from (select t.*, count(*) over (partition by sku, id) as cnt
from t
) t
where cnt = 1;
This assumes you really mean the sku/id combination.

Creating a group by of a group by

I'm sure this is really straightforward, but I'm struggling! I'd like to create a group by for the count of the incidence of a value, eg. there are two incidences of case_id '10' and two of case_id '20', so there would be two counts of 'two'
Data table:
id | case_id
---------------
0 | 10
1 | 10
2 | 20
3 | 20
4 | 30
5 | 30
6 | 30
7 | 40
8 | 40
7 | 40
8 | 40
Creates this:
no of occurrences | count
of a case_id |
---------------------------
2 | 2
3 | 1
4 | 1
Thank you!
Use an inner query:
SELECT occurences, COUNT(*) cnt
FROM (
SELECT COUNT(*) occurences FROM mytable GROUP BY case_id
) x
GROUP BY occurences
Demo on DB Fiddle:
| occurences | cnt |
| ---------- | --- |
| 2 | 2 |
| 3 | 1 |
| 4 | 1 |

PostgreSQL - select count of repeated continuous sequences

I have the following table/data:
| user_id | action_id | data |
-------------------------------------
| 10 | 1 | fly |
| 10 | 2 | train |
| 10 | 3 | fly |
| 10 | 4 | fly |
| 10 | 5 | fly |
| 10 | 6 | train |
| 10 | 7 | fly |
| 10 | 8 | train |
| 10 | 9 | fly |
| 10 | 10 | fly |
Is there a way in postgresql to count repeated continuous 'fly' occurrences? In this example, the results should be:
counts
------
1
3
1
2
Yes, it's possible, using the lag window function and a cumulative sum:
with FlagCTE as (
select t.action_id, t.data,
case when t.data = 'fly' and t.data = lag(t.data) over (order by t.action_id) then 0 else 1 end as Flag
from some_table t),
GroupCTE as (
select t.action_id,
t.data,
sum(t.Flag) over (order by t.action_id) as GroupId
from FlagCTE t
where t.data = 'fly')
select count(*) as counts
from GroupCTE t
group by t.GroupId
order by t.GroupId
SQLFiddle Demo

Sql: Aggregation First() After Order by and Group by

id | name | value | time |
--------------------------
1 | A | 1 | 1 |
2 | B | 2 | 2 |
3 | C | 2 | 3 |
4 | A | 3 | 3 |
5 | A | 4 | 2 |
and I expected the result as below:
name | value |
--------------
A | 3 |
B | 2 |
C | 2 |
The results are to show name and value which are lastest time and not duplicate with name.
And I try to query:
SELECT name,First(value)
FROM
(SELECT name,value,time
FROM test
ORDER BY time DESC
)
GROUP BY name;
But I got this result:
name | value |
--------------
A | 1 |
B | 2 |
C | 2 |
I don't understand why A value isn't 3 because from subselect I got A values are 3,4,1 respectively.
Query:
SQLFIDDLEExample
SELECT t.name,
(SELECT t1.value
FROM test t1
WHERE t1.name = t.name
ORDER BY t1.time DESC
LIMIT 1) AS value
FROM test t
GROUP BY t.name
Result:
| NAME | VALUE |
----------------
| A | 3 |
| B | 2 |
| C | 2 |
also you can use partitionby
;with cte as (
select id, row_number() over (order by time desc) rn
from test
)
select * from test
join cte on test.id = cte.id and rn = 1
just choose the one which is faster