SQLITE get row continous value - sqlite

I have a simple table. One of the example rows looks like this:
id | name |
1 | a |
2 | a |
3 | a |
4 | b |
6 | b |
7 | a |
8 | a |
I want to get last continuous id.
so if i start at '1', the result should be '4'
in this example, the result should be '7'
3 |a |
4 |b |
5 |a |
6 |a |
7 |a |
10|a |
Only i now is that select all after my input number, and find continuous programmatically.
how can i do..?

If I understand the question correctly, this should work for you:
select id from tableName t1 where not exists(select id from tableName t2 where t2.id=t1.id+1) and (id-(select count(*) from tableName t3 where t3.id<t1.id))=(select min(id) from tableName);
If you want to start from 10, it should be:
select id from tableName t1 where not exists(select id from tableName t2 where t2.id=t1.id+1) and (id-(select count(*) from tableName t3 where t3.id<t1.id and t3.id>=10))=10;

Related

Sqlite / populate new column that ranks the existing rows

I've a SQLite database table with the following columns:
| day | place | visitors |
-------------------------------------
| 2021-05-01 | AAA | 20 |
| 2021-05-01 | BBB | 10 |
| 2021-05-01 | CCC | 3 |
| 2021-05-02 | AAA | 5 |
| 2021-05-02 | BBB | 7 |
| 2021-05-02 | CCC | 2 |
Now I would like to introduce a column 'rank' which indicates the rank according to the visitors each day. Expected table would look like:
| day | place | visitors | Rank |
------------------------------------------
| 2021-05-01 | AAA | 20 | 1 |
| 2021-05-01 | BBB | 10 | 2 |
| 2021-05-01 | CCC | 3 | 3 |
| 2021-05-02 | AAA | 5 | 2 |
| 2021-05-02 | BBB | 7 | 1 |
| 2021-05-02 | CCC | 2 | 3 |
Populating the data for the new column Rank can be done with a program like (Pseudocode).
for each i_day in all_days:
SELECT
ROW_NUMBER () OVER (ORDER BY `visitors` DESC) Day_Rank, place
FROM mytable
WHERE `day` = 'i_day'
for each i_place in all_places:
UPDATE mytable
SET rank= Day_Rank
WHERE `Day`='i_day'
AND place = 'i_place'
Since this line by line update is quite inefficient, I'm searching how to optimize this with a SQL sub query in combination with the UPDATE.
(does not work so far...)
for each i_day in all_days:
UPDATE mytable
SET rank= (
SELECT
ROW_NUMBER () OVER (ORDER BY `visitors` DESC) Day_Rank
FROM mytable
WHERE `day` = 'i_day'
)
Typically, this can be done with a subquery that counts the number of rows with visitors greater than the value of visitors of the current row:
UPDATE mytable
SET Day_Rank = (
SELECT COUNT(*) + 1
FROM mytable m
WHERE m.day = mytable.day AND m.visitors > mytable.visitors
);
Note that the result is actually what RANK() would return, if there are ties in the values of visitors.
See the demo.
Or, you could calculate the rankings with ROW_NUMBER() in a CTE and use it in a subquery:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY day ORDER BY visitors DESC) rn
FROM mytable
)
UPDATE mytable
SET Day_Rank = (SELECT rn FROM cte c WHERE (c.day, c.place) = (mytable.day, mytable.place));
See the demo.
Or, if your versipn of SQLite is 3.33.0+ you can use the join-like UPDATE...FROM... syntax:
UPDATE mytable AS m
SET Day_Rank = t.rn
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY day ORDER BY visitors DESC) rn
FROM mytable
) t
WHERE (t.day, t.place) = (m.day, m.place);

Get all ids of GROUP_CONCAT in SQLite

Table B
id name tablename
1 abc table1
2 xyz table2
3 abc table1
4 sdf table2
5 dfg table1
Query:
SELECT B.tablename, GROUP_CONCAT(B.id),GROUP_CONCAT(B.name||'-'||cnt)
FROM (
SELECT tablename, id, name, COUNT(*) cnt
FROM B
GROUP BY tablename,name
) B GROUP BY B.tablename
Output:
| tablename | GROUP_CONCAT(B.id) | GROUP_CONCAT(B.nameB||'-'||cnt) |
| ------ | ------------------ | ------------------------------- |
| table1 | 1,5 | abc-2,dfg-1 |
| table2 | 2,4 | xyz-1,sdf-1 |
But here i'm not getting full ids as you can see in output of table 1.
i want something like :
| tablename | GROUP_CONCAT(B.id) | GROUP_CONCAT(B.nameB||'-'||cnt) |
| ------ | ------------------ | ------------------------------- |
| table1 | 1,3,5 | abc-2,df-1 |
| table2 | 2,4 | xyz-1,sdf-1 |
Pls help me fix this.
You should use GROUP_CONCAT() for the ids in the subquery also:
SELECT tablename, GROUP_CONCAT(id), GROUP_CONCAT(name||'-'||cnt)
FROM (
SELECT tablename, GROUP_CONCAT(id) id, name, COUNT(*) cnt
FROM B
GROUP BY tablename, name
)
GROUP BY tablename
See the demo.

sql count of rows from two tables where rows from table 1 don't exist in table 2

I have two tables in a SQLite db like so
| t1 |
|===============|
| t1_id | other |
|-------|-------|
| 1 | sdfds |
| 2 | asdaa |
| 3 | lkjeq |
| t2 |
|=======================|
| t2_id | t1_id | other |
|-------|-------|-------|
| 1 | 1 | dggeh |
| 2 | 1 | iohio |
| 3 | 3 | ytucc |
| 4 | 3 | .noih |
| 5 | 3 | /oioi |
There are approx. 300K+ rows in both tables. I want the counts of t1 that have related rows in t2 as well as those that don't have. That is,
"count of t1 with related t2" : 2
"count of t1 with no related t2": 1
Of course, I can get "count of t1 with related t2" from
SELECT Count(*) FROM t1 JOIN t2 ON t1.t1_id = t2.t1_id;
and the "count of t1 with no related t2" by subtracting the above from the total count of t1. But how can I get it from a SQL query efficiently? I tried the following
EXPLAIN QUERY PLAN SELECT t1_id FROM t1 AS t
WHERE NOT EXISTS (SELECT * FROM t2 WHERE t.t1_id = t2.t1_id);
and I see that the index on t1_id in table t2 is not used. When I try the query, it takes really long, like 100s of seconds.
A couple of possibilities:
SELECT count(*) FROM
(SELECT t1_id FROM t1
EXCEPT
SELECT t1_id FROM t2);
or
SELECT count(*)
FROM t1
WHERE t1_id NOT IN (SELECT t1_id FROM t2);
or (A slight variation on your original):
SELECT count(*)
FROM t1
WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE t1.t1_id = t2.t1_id);
All three of those should use an index on t2(t1_idx). You'll have to do benchmarking on real data to see which is faster.

SQLite take N rows per each group

I have an SQLite table similar to the following:
| A | B |
_________
| e | 5 |
| f | 7 |
| a | 5 |
| n | 7 |
| g | 5 |
| d | 7 |
| i | 5 |
| j | 5 |
| e | 7 |
| v | 7 |
How can I retrieve three random rows with value 5 in column B and three random rows with value 7? I don't know values in B, neither values5 ad 7. I want 3 random rows for each different value in B. Result may be not grouped by column B values. It could be something like:
| A | B |
_________
| e | 5 |
| g | 5 |
| e | 7 |
| v | 7 |
| j | 5 |
| f | 7 |
The following almost does what you want:
select t.*
from t
where t.rowid in (select t2.rowid
from t t2
where t2.b = t.b
order by random()
limit 3
);
Alas, the subquery will be run for every row, so this is only approximate because the random number generator changes values on each execution.
One solution is to use a temporary table to store a random number for each row, which can then be used for sorting. Unfortunately, a CTE doesn't seem to do the trick, because these are re-evaluated on each reference.
After some thought, I think a temporary table might be the only solution:
drop table if exists tempt;
create temporary table tempt as
select t.*, random() as rand
from t;
select t.*
from tempt t
where t.rowid in (select t2.rowid
from tempt t2
where t2.b = t.b
order by rand
limit 3
);
You can use the hidden RowID column to get three rows per B value as follows:
SELECT A, B FROM T T1
WHERE RowID IN (SELECT RowID FROM T T2 WHERE B = T1.B LIMIT 3);
Note that you're likely (but not 100% guaranteed) to get the same three rows each time. If you want to get random rows at the expense of some performance, you can do:
SELECT A, B FROM T T1
WHERE RowID IN (SELECT RowID FROM T T2 WHERE B = T1.B ORDER BY random() LIMIT 3);

SQLite - Update a column based on values from two other tables' columns

I am trying to update Data1's ID to Record2's ID when:
Record1's and Record2's Name are the same, and
Weight is greater in Record2.
Record1
| ID | Weight | Name |
|----|--------|------|
| 1 | 10 | a |
| 2 | 10 | b |
| 3 | 10 | c |
Record2
| ID | Weight | Name |
|----|--------|------|
| 4 | 20 | a |
| 5 | 20 | b |
| 6 | 20 | c |
Data1
| ID | Weight |
|----|--------|
| 4 | 40 |
| 5 | 40 |
I have tried the following SQLite query:
update data1
set id =
(select record2.id
from record2,record1
where record1.name=record2.name
and record1.weight<record2.weight)
where id in
(select record1.id
from record1, record2
where record1.name=record2.name
and record1.weight<record2.weight)
Using the above query Data1's id is updated to 4 for all records.
NOTE: Record1's ID is the foreign key for Data1.
For the given data set the following seems to serve the cause:
update data1
set id =
(select record2.id
from record2,record1
where
data1.id = record1.id
and record1.name=record2.name
and record1.weight<record2.weight)
where id in
(select record1.id
from record1, record2
where
record1.id in (select id from data1)
and record1.name=record2.name
and record1.weight<record2.weight)
;
See it in action: SQL Fiddle.
Please comment if and as this requires adjustment / further detail.

Resources