SQLite query to GROUP BY nearby row - sql

I have a SQLite .db file that contains the Thread table that looks like this:
ThreadID ClusterID
1 0
2 0
3 0
4 1
5 1
6 0
7 1
8 1
9 0
10 1
And I would like to GROUP BY the ClusterID by only with the nearby row. Output would be:
ThreadID ClusterID
1 0
4 1
6 0
7 1
9 0
10 1
Or ideally:
ThreadID ClusterID ClusterSwitch
1 0 NO
2 0 NO
3 0 NO
4 1 YES
5 1 NO
6 0 YES
7 1 YES
8 1 NO
9 0 YES
10 1 YES
The whole design its to detect when a cluster switched from 0 to 1 and from 1 to 0
Thanks for your help it is really appreciated :)
-Steve

Assuming your thread ids are really in order with no gaps, you can just use a self join:
select t.*,
(case when tprev.clusterid <> t.clusterid then 1 else 0 end) as ClusterSwitch
from threads t left join
threads tprev
on t.threadid = tprev.threadid + 1;
If you cannot be sure of no gaps, you can do this with a correlated subquery:
select t.*,
(case when t.clusterid <>
(select t2.clusterid
from threads t2
where t2.id < t.id
order by t2.id desc
limit 1
)
then 1 else 0 end) as ClusterSwitch
from threads t;
However, this query will not scale well, so performance could be an issue.

Related

Is there a way to get max consecutive counts of 1s across columns in SQL?

Is there a way to get maximum consecutive counts across columns in SQL? I'm looking for longest duration of survival.
For example, if I have a dataset that looks like this
ID T1 T2 T3 T4 T5 T6 T7 T8 T9
1 1 1 0 0 0 1 1 1 1
2 0 0 0 1 1 1 1 1 0
3 0 1 0 1 0 1 1 0 0
4 0 1 0 0 0 0 0 0 0
5 0 1 1 0 0 0 0 0 0
6 1 0 1 1 0 1 1 1 0
I want to add a column to get the maximum consecutive 1s across the columns T1-T9 so it would look like this
ID T1 T2 T3 T4 T5 T6 T7 T8 T9 MAX
1 1 1 0 0 0 1 1 1 1 4
2 0 0 0 1 1 1 1 1 0 5
3 0 1 0 1 0 1 1 0 0 2
4 0 1 0 0 0 0 0 0 0 1
5 0 1 1 0 0 0 0 0 0 2
6 1 0 1 1 0 1 1 1 0 3
**The below code is a way to get maximum consecutive counts across Column in MySQL I think you want across the Row **
create table t(id integer,t1 integer,t2 integer,t3 integer,t4 integer,t5 integer,t6 integer,t7 integer,t8 integer,t9 integer);
insert into t values(1,1,0,1,0,1,1,0,0,0),(2,0,0,1,1,1,0,0,0,0),(3,1,0,1,1,1,1,0,0,0);
WITH CTE1 AS
(
SELECT id , ROW_NUMBER() OVER (ORDER BY id) Rnk FROM t
)
,CTE2 AS
(
SELECT *, CASE WHEN id-1 = LAG(id) OVER(ORDER BY rnk) THEN 0
ELSE 1 END cols FROM CTE1 c2
)
,CTE3 AS
(
SELECT *, SUM(cols) OVER(ORDER BY rnk) Grouper FROM CTE2 c2
)
SELECT * FROM
(
SELECT COUNT(*) Counts FROM CTE3 GROUP BY Grouper
)r
ORDER BY Counts DESC ;
I think the simplest method in proc sql might be a brute force approach:
select t.*,
(case when t1||t2||t3||t4||t5||t6||t7||t8||t9 like '%111111111%' then 9
when t1||t2||t3||t4||t5||t6||t7||t8||t9 like '%11111111%' then 8
when t1||t2||t3||t4||t5||t6||t7||t8||t9 like '%1111111%' then 7
when t1||t2||t3||t4||t5||t6||t7||t8||t9 like '%111111%' then 6
when t1||t2||t3||t4||t5||t6||t7||t8||t9 like '%11111%' then 5
when t1||t2||t3||t4||t5||t6||t7||t8||t9 like '%1111%' then 4
when t1||t2||t3||t4||t5||t6||t7||t8||t9 like '%111%' then 3
when t1||t2||t3||t4||t5||t6||t7||t8||t9 like '%11%' then 2
when t1||t2||t3||t4||t5||t6||t7||t8||t9 like '%1%' then 1
else 0
end) as max
from t;
Here is a db<>fiddle illustrating the logic using Postgres.

increasing value with condition on oracle

How to add an increment value (not summarize) with some condition on another column?
I'm using Oracle-like DBMS, named Tibero, for simple example i want to produce this data
ROWNUM GRP_STRT GRP_NO SLBY
1 1 1 1
2 1 1 1
3 1 1 1
4 1 1 1
5 1 1 1
6 1 2 0
7 1 2 0
8 1 3 1
9 1 3 1
10 1 3 1
11 1 4 0
12 1 5 1
Column SLBY is for Buy/Sell code (0=Buy, 1=Sell) then every changing type of transaction, column GRP_NO increasing (but it's not grouping by SLBY column)
SELECT CASE
WHEN ROWNUM = 1 THEN GRP_NO
WHEN ROWNUM <> 1 AND SLBY = LAG(SLBY,1) over (ORDER BY ROWNUM) THEN LAG(GRP_STRT,1) over (ORDER BY ROWNUM) - 1
WHEN ROWNUM <> 1 AND SLBY_DSTN_CD <> LAG(SLBY_DSTN_CD,1) over (ORDER BY ROWNUM) THEN LAG(GRP_STRT,1) over (ORDER BY ROWNUM) + 1
END TARGET_GROUPING
, A.*
FROM SOME_TABLE
I tried with that query but instead of getting what i want like in the picture above, I produced a GRP_NO like 1 1 1 1 1 2 1 1 1 1 2 1 1 1 (first change SLBY only)
Apologies for my bad english and bad explanation, I'll explain more if need further information, thanks for your help!
As far as I understood your problem,
You are trying to calculate GRP_NO from ROWNUM, GRP_STRT, GRP_NO, and SLBY.
I have created the following query for you.
You can check the logic and apply it in your code accordingly:
SELECT
RN,
GRP_STRT,
SUM(CASE
WHEN PREV_SLBY_DSTN_CD IS NULL
OR PREV_SLBY_DSTN_CD <> SLBY_DSTN_CD THEN 1
END) OVER(
ORDER BY
RN
) AS GRP_NO,
SLBY_DSTN_CD AS SLBY
FROM
(
SELECT
RN,
LAG(SLBY_DSTN_CD) OVER(
ORDER BY
RN
) AS PREV_SLBY_DSTN_CD,
SLBY_DSTN_CD,
GRP_STRT
FROM
(SELECT ROWNUM RN, .... FROM SOME_TABLE) A
)
This code is to generate the output as shown in question:
ROWNUM GRP_STRT GRP_NO SLBY
1 1 1 1
2 1 1 1
3 1 1 1
4 1 1 1
5 1 1 1
6 1 2 0
7 1 2 0
8 1 3 1
9 1 3 1
10 1 3 1
11 1 4 0
12 1 5 1
Cheers!!

Can I start a new group when value changes from 0 to 1?

Can I somehow assign a new group to a row when a value in a column changes in T-SQL?
I would be grateful if you can provide solution that will work on unlimited repeating numbers without CTE and functions. I made a solution that work in sutuation with 100 consecutive identical numbers(with
coalesce(lag()over(), lag() over(), lag() over() ) - it is too bulky
but can not make a solution for a case with unlimited number of consecutive identical numbers.
Data
id somevalue
1 0
2 1
3 1
4 0
5 0
6 1
7 1
8 1
9 0
10 0
11 1
12 0
13 1
14 1
15 0
16 0
Expected
id somevalue group
1 0 1
2 1 2
3 1 2
4 0 3
5 0 3
6 1 4
7 1 4
8 1 4
9 0 5
10 0 5
11 1 6
12 0 7
13 1 8
14 1 8
15 0 9
16 0 9
If you just want a group identifier, you can use:
select t.*,
min(id) over (partition by some_value, seqnum - seqnum_1) as grp
from (select t.*,
row_number() over (order by id) as seqnum,
row_number() over (partition by somevalue order by id) as sequm_1
from t
) t;
If you want them enumerated . . . well, you can enumerate the id above using dense_rank(). Or you can use lag() and a cumulative sum:
select t.*,
sum(case when some_value = prev_sv then 0 else 1 end) over (order by id) as grp
from (select t.*,
lag(somevalue) over (order by id) as prev_sv
from t
) t;
Here's a different approach:
First I created a view to provide the group increment on each row:
create view increments as
select
n2.id,n2.somevalue,
case when n1.somevalue=n2.somevalue then 0 else 1 end as increment
from
(select 0 as id,1 as somevalue union all select * from mytable) n1
join mytable n2
on n2.id = n1.id+1
Then I used this view to produce the group values as cumulative sums of the increments:
select id, somevalue,
(select sum(increment) from increments i1 where i1.id <= i2.id)
from increments i2

Update table records with accumulated result

Lets say I have a table Tbl (Represents simple timelogs for work made on different customers)
Five columns
Id: int
TimeUse: float
IdCustomer: int
Created: DateTime
TimeCalc: float
I have a number of records in this table, (TimeCalc is initialized to value = 0)
What I want my SQL to do is:
when TimeUse for all foregoing records on a specific customer accumulates to a value < 10 then the value in TimeCalc should be 0
when TimeUse for all foregoing records on a specific customer accumulates to a value >= 10 then the value in TimeCalc should be = TimeUse for the record...
I have messed around with Case routines with subqueries, but can't get it working.
BEFORE
Id TimeUse IdCustomer Created TimeCalc
1 2 1 14/09/09 0
2 5 2 14/09/10 0
3 2 1 14/09/11 0
4 5 2 14/09/12 0
5 4 1 14/09/13 0
6 2 2 14/09/14 0
7 4 1 14/09/15 0
8 1 1 14/09/16 0
9 3 2 14/09/17 0
10 2 1 14/09/18 0
11 4 2 14/09/19 0
AFTER
Id TimeUse IdCustomer Created TimeCalc
1 2 1 14/09/09 0
2 5 2 14/09/10 0
3 2 1 14/09/11 0
4 5 2 14/09/12 0
5 4 1 14/09/13 0
6 2 2 14/09/14 2
7 4 1 14/09/15 0
8 1 1 14/09/16 1
9 3 2 14/09/17 3
10 2 1 14/09/18 2
11 4 2 14/09/19 4
Can this be solved in an SQL update?
In SQL Server 2012+, you can do this with a cumulative sum:
select Id, TimeUse, IdCustomer, Created,
(case when sum(timeuse) over (partition by idcustomer order by id) < 10 then 0
else timeuse
end) as timecalc
from table t;
You can do the same thing in earlier versions using outer apply or a subquery.
If you want an update, just use a CTE:
with toupdate as (
select t.*,
(case when sum(timeuse) over (partition by idcustomer order by id) < 10 then 0
else timeuse
end) as new_timecalc
from table t
)
update toupdate
set timecalc = new_timecalc;
EDIT:
The following will work in any version of SQL Server:
with toupdate as (
select t.*,
(case when (select sum(t2.timeuse)
from table t2
where t2.idcustomer = t.idcustomer and
t2.id <= t.id
) < 10 then 0
else timeuse
end) as new_timecalc
from table t
)
update toupdate
set timecalc = new_timecalc;

how to double count column which already counted

Please help me to solve the problem
My real table is:
id group numberOfLevel(counted column)
1 10 4
2 10 2
3 11 2
4 11 1
5 11 3
6 11 2
7 21 1
8 21 2
9 30 1
10 40 2
But i want to show:
group 1st_level 2nd_level 3rd_level over4th_level
10 0 1 0 1
11 1 2 1 0
21 1 1 0 0
30 1 0 0 0
40 0 1 0 0
Which way do i need to use to show the table?
Please share experience ?
This is a basic pivot query, an ANSII SQL case expession can be used in such a query,
and it should work on most databases:
select group_nr,
sum( case when numberOfLevel = 1 then 1 else 0 end ) As level_1st,
sum( case when numberOfLevel = 2 then 1 else 0 end ) As level_2nd,
sum( case when numberOfLevel = 3 then 1 else 0 end ) As level_3rd,
sum( case when numberOfLevel >= 4 then 1 else 0 end ) As over4th_level
from table1
group by group_nr
;
demo: http://sqlfiddle.com/#!2/4bd04/4
Don't use group as a column name, because group is a keyword in SQL.