SQL to find next greater records for each element - sqlite

I've got a table defined like this:
CREATE TABLE event (t REAL, event TEXT, value);
For each record in the table which have event='type' and value='G' there will be two corresponding records with event='Z' - one with value=1 and one with value=0. Here is an example:
t | event | value
1624838448.123 | type | G
1624838448.123 | Z | 1
1624839543.215 | Z | 0
Note that there could be other event='Z' records that don't have corresponding type='G' records. I'm trying to write a query to find all the event='G' records that do have a corresponding type='G' record to use as the bounds for an additional query (or join?).
Note: The t value for the "type" event and the Z event where value=1 will always be the same.
So for instance if the table looked like this:
t | event | value
1624838448.123 | type | G
1624838448.123 | Z | 1
1624839543.215 | Z | 0
1624839555.555 | type | H
1624838555.555 | Z | 1
1624839602.487 | Z | 0
1624839999.385 | type | G
1624839999.385 | Z | 1
1624840141.006 | Z | 0
Then I want the results of the query to return this:
t1 | t2
1624838448.123 | 1624839543.215
1624839999.385 | 1624840141.006

From your comment:
There are always three records (ignoring any other events in between)
in chronological order: the "type" event, the first "Z" record with
the same timestamp, and the second "Z" record with a later timestamp
So, there is no need to return t1 separately since it is equal to t in the row where event = 'type' and value = 'G'.
For t2 you can use conditional aggregation with MIN() window function:
SELECT t1, t2
FROM (
SELECT t AS t1, event, value
MIN(CASE WHEN event = 'Z' AND value = '0' THEN t END) OVER (ORDER BY t ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING) t2
FROM Event
)
WHERE event = 'type' AND value = 'G'
See the demo.

I found a solution using the RANK() function. With this I get an intermediate table which has the same rank for both the "type" and first "Z" record, since they have the same timestamp, and a rank two greater for the second "Z" record. I use WITH so I can self join repeatedly without having to specify the same query over and over. I first join the "type" and first "Z" row by requiring that the type of two second record be greater than that of the first (so I only get the type:Z combination and not type:type, Z:type, or Z:Z). Then I self join again to get the rank-2 row which picks up the second Z record. Overall, the query looks like this:
WITH Seq(t,event,A,I)
AS
(
SELECT t, event, value,
RANK() OVER (ORDER BY t) I
FROM Event e1
WHERE (e1.event='type' OR e1.event='Z')
)
SELECT s2.t,s3.t
FROM Seq s1
INNER JOIN Seq s2 ON s1.I = s2.I AND s1.event < s2.event
INNER JOIN Seq s3 ON s1.I = s3.I-2
WHERE s1.value='G';

Related

Compare multiple numbers row by row of same table in teradata

Here is my table data from which I want to assign values to the record.
Member_ID | Claim_ID | Codes | Pull
123 | Y | 12,23,35,78 | Y
123 | N | 12,35 | Y
123 | N | 23,34 | N
123 | N | 33,34 | N
I am using the teradata to assign 'Y' or 'N' to Pull depending on the codes and claims.
SEL A.MEMBER_ID,A.CLAIM_ID,A.CODES,
'Y' AS PULL
FROM (SEL * FROM DBC.PULL_COMP WHERE CLAIM_ID='Y') A
INNER JOIN ((SEL * FROM DBC.PULL_COMP WHERE CLAIM_ID='N') B
ON A.MEMBER_ID=B.MEMBER_ID
UNION
SEL B.MEMBER_ID,B.CLAIM_ID,B.CODES,
CASE WHEN OREPLACE(A.CODES,B.CODES,B.CODES)=A.CODES THEN 'Y'
ELSE 'N' END AS PULL
FROM (SEL * FROM DBC.PULL_COMP WHERE CLAIM_ID='Y') A
INNER JOIN ((SEL * FROM DBC.PULL_COMP WHERE CLAIM_ID='N') B
ON A.MEMBER_ID=B.MEMBER_ID
If the Claim_id is 'Y' the Pull will remain 'Y'. I want to compare the records whose claim_id is 'Y' with those whose claim_id id 'N'. The second record contains no new numbers when comparing with 1st record so Pull='Y'. The 3rd record contains one new number(34) hence Pull='N'. The 4th record contains all new numbers compared to 1st record hence 'N'. Even if there is one new number then Pull='N'. If all the numbers(Codes) of Claim_id='N' matches with the Codes of Claim_id='Y' then only Pull='Y'. I am populating the Pull column looking at member_id, claim_id and codes.
I am getting not the desired result with above query.

SQLite subquery: "IN" the result of the outer query

I have two tables user and pair. I want to get the number of duplicate pairs (a, b) for each user.name.
user
name | id
-------------
"Alice" | 0
"Bob" | 1
"Alice" | 2
pair
id | a | b
-----------
0 | 0 | 1
0 | 1 | 3
1 | 0 | 1
2 | 1 | 3
In the above example, the result should be:
name | id | c
-------------------
"Alice" | 0,2 | 1
"Bob" | 1 | 0
When there is only one id for each user, I can do this:
SELECT name, id, (
SELECT COUNT(*) FROM pair JOIN pair AS p USING (id, a, b)
WHERE id = user.id AND pair.rowid < p.rowid
) AS c FROM user;
When there is multiple ids, I can get the correct result from the below query, but it is quite slow when there is more rows and more subqueries.
SELECT name, GROUP_CONCAT(id), (
WITH t AS (SELECT id FROM user AS u WHERE name = user.name)
SELECT COUNT(*) FROM pair JOIN pair AS p USING (a, b)
WHERE pair.id IN t AND p.id IN t AND pair.rowid < p.rowid
) AS c FROM user GROUP BY name;
I want to know that is there a simple and efficient way for this, like changing the WHERE clause from pair.id = user.id to pair.id IN <<the user.id list>>?
/* This will not work! "Error: no such table: user.id" */
SELECT name, GROUP_CONCAT(id), (
SELECT COUNT(*) FROM pair JOIN pair AS p USING (a, b)
WHERE pair.id IN user.id AND p.id IN user.id AND pair.rowid < p.rowid
) AS c FROM user GROUP BY name;
The GROUP BY name operation can be sped up if the database is able to go through the rows in order, without having to sort the table.
This can be done with an index on the name column (the other column makes this a covering index, which helps only a little more):
CREATE INDEX user_name_id_index ON user(name, id);
The query looks up pair rows by their id, a, and b values; these lookups can be sped up with an index on these columns:
CREATE INDEX pair_id_a_b_index ON pair(id, a, b);
To help the query optimizer make better decisions when selecting indexes, run ANALYZE.
The query optimizer gets improved constantly; get the newest SQLite version, if possible.
To check how your queries are executed, look at the output of the EXPLAIIN QUERY PLAN command.

selecting a row based on a number of column values in SQLite

I have a table with this structure:
id | IDs | Name | Type
1 | 10 | A | 1
2 | 11 | B | 1
3 | 12 | C | 2
4 | 13 | D | 3
except id nothing else is a FOREIGN or PRIMARY KEY. I want to select a row based on it's column values that are not PRIMARY KEY. I have tried the following syntax but it yields no results.
SELECT * FROM MyTable WHERE Name = 'A', Type = 1;
what am I doing wrong? What is exactly returned by a SELECT statement? I'm totally new to Data Base and I'm currently experimenting and trying to learn it. so far my search has not yield any results regarding this case.
Use and to add multiple conditions to your query
SELECT *
FROM MyTable
WHERE Name = 'A'
AND Type = 1;

Passing result variable to nested SELECT statement in Sqlite

I have the following query which works:
SELECT
SoftwareList,
Count (SoftwareList) as Count
FROM [assigned]
GROUP BY SoftwareList
This returns the following result set:
*SoftwareList* | *Count*
--------------------------
Office XP | 3
Adobe Reader | 3
Dreamewaver | 2
I can also run the following query:
SELECT
GROUP_CONCAT(LastSeen) as LastSeen
FROM [assigned]
WHERE SoftwareList = 'Dreamweaver';
Which would return the following result set:
*LastSeen*
----------
2007-9-23,2012-3-12
I wish to combine both of these queries into one, so that the following results are returned:
*SoftwareList* | *Count* | *LastSeen*
--------------------------------------------------------
Office XP | 3 | 2001-2-12,2008-3-19,2002-2-17
Adobe Reader | 3 | 2008-2-12,2009-3-20,2007-3-16
Dreamewaver | 2 | 2007-9-23,2012-3-12
I am trying this but don't know how to refer to the initial SoftwareList variable within the nested statement:
SELECT
SoftwareList,
Count (SoftwareList) as Count,
(SELECT
GROUP_CONCAT(LastSeen) FROM [assigned]
WHERE SoftwareList = SoftwareList
) as LastSeen
FROM [assigned]
GROUP BY SoftwareList;
How can I pass SoftwareList which is returned for each row, into the nested statement?
I think this is what you want:
SELECT SoftwareList, COUNT(SoftwareList) AS Count, GROUP_CONCAT(LastSeen)
FROM assigned GROUP BY SoftwareList

UPDATE multiple rows using SELECT

I have A table and two rows with id=1 and id=2 and their x parameter is 1. I also have B table and two rows with same id 1 and 2. I am trying to update all of the data(column)on B table which has same id with A table whose x parameter is 1.
A table
id | x |
1 | 1 |
2 | 1 |
B table
id | Y |
1 | yes|
2 | yes|
My query is
UPDATE B SET y='No' WHERE B.id=(SELECT A.id FROM A WHERE A.x=1);
The problem is select returns mutliple data and i can only update the first data.
I tried to use JOIN but sqlite gives syntax error near INNER i couldn't find the problem.
UPDATE B SET B.y='No' INNER JOIN A ON B.id=A.id WHERE A.x=1;
Use this:
UPDATE ... WHERE B.id IN (SELECT A.id ...);

Resources