SQL to find last sibling in a linked list - sqlite

I've got a simple table that has a previous field for each row so as to create a linked list. I am trying to find a query that will find the id of the last element in the list. My first thought was that perhaps I could use some sort of self join, but I'm not sure how to express that what I am looking for is the id of the element which does not appear as the "previous" field in some other row.
My second thought was perhaps a query that uses "not in" and the list of all ids (e.g. SELECT id) but I'm not sure how to attach that a particular field (e.g. previous). In other words, I would want something like:
SELECT * FROM test WHERE (SELECT id) NOT IN previous
But the SQL code is expecting previous to be a table, whereas I want to find where non of the ids are in the previous value.
If I try the reverse, for some reason it matches all rows:
SELECT * FROM test WHERE previous NOT IN (SELECT id)

As for the second thought:
SELECT id FROM foo f1 WHERE id NOT IN (SELECT previous FROM foo f2)

Related

Teradata CASE WHEN attribute IN ( Select... from)

I have selected a bunch of IDs and I try to use CASE WHEN to get a column when the IDs which I really want to select are in the IDs I selected earlier.
But it shows Select Failed .3771:Illegal expression in WHEN clause of Case expression.
Any suggestion to get it right?
Please help.
p.s my goal is to select the IDs shown for the first time.

SQLITE EXCEPT on a single column

I've got two sub-queries on a table, and I want the result to be similar to
SELECT * FROM table WHERE condition1
EXCEPT
SELECT * FROM table WHERE condition2;
However, I only want a single column to be considered for the purpose of this set operation, because the other columns are always different. Thus, the above query always returns everything in the first set, instead of only those elements which don't appear in the second set (comparing only a single column).
If I was trying to find the UNION I could do it with a JOIN, but since I'm trying to find the complement instead I'm not sure the way to go about doing this.
SELECT *
FROM table
WHERE condition1
AND someColumn NOT IN (SELECT someColumn
FROM table
WHERE condition2)

How to reverse order of SQLite CTE

If I do a simple select, I can order the result using ORDER BY. But I cannot do this with a WITH RECURSIVE CTE, because I am using it to find a path from a leaf in a tree back up to the root, and the order that the CTE creates the result is not an order that can be obtained by sorting, therefore there is no ORDER BY I can reverse to get the reverse order.
The problem I have is, this constructs the results from leaf to root, but for a subsequent part of the query I need it to be in the reverse order, from the root to the leaf. But I cannot construct the query this way because it would wind up following all branches in the tree instead of the single path that I need. Thus, I need to somehow reverse the order of the resulting CTE. How can I do this?
I have done a bit of looking and there are some similar questions for other (non SQLite) database which seem to suggest that the result of the CTE table doesn't actually have any defined order. I am not sure if that is true for SQLite - I always see it output the table in the same child to parent order, and in fact there are other cases (such as in creating temporary tables, as in a previous question I asked) where if the table were not guaranteed to have this property it would break the only possible solution rendering it an impossible problem to solve.
The documentation says:
An ORDER BY clause on the recursive-select can be used to control whether the search of a tree is depth-first or breadth-first.
However, you want to sort the ultimate output of the CTE.
This can be done easily because you are using a normal SELECT to access the CTE:
WITH RECURSIVE test1(id, parent) AS (
VALUES(3, 2)
UNION ALL
SELECT test.id, test.parent
FROM test JOIN test1 ON test1.parent = test.id)
SELECT *
FROM test1
ORDER BY id -- this sorts normally
You can use multiple elements in your order by. For example the following will order the tree by name after performing the depth first search. Here I am sorting first by LEVEL descending then NAME ascending. The output would be a sorted tree with children underneath the appropriate parent.
WITH RECURSIVE TEMPTREE (
id,
name,
level
)
AS (
SELECT flow_id,
name,
0
FROM DATATABLE
WHERE parent_id IS NULL
UNION ALL
SELECT DATATABLE.id,
DATATABLE.name,
TEMPTREE.level + 1
FROM DATATABLE
JOIN
TEMPTREE ON DATATABLE.parent_id = TEMPTREE .id
ORDER BY 3 DESC, 2 ASC
)
SELECT substr('..........', 1, level * 3) || name AS Name,
id
FROM TEMPTREE;

Getting a range of tuples from an ordered SQLite table

First I'd like to apologize if the topic seems vague; I always have a hard time framing them succinctly. That done, I'll get into it.
Suppose I have a database table that looks like the following:
CREATE TABLE The_table(
item_id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
item TEXT);
Now, I have a pretty basic query that will get items from said table and order them:
SELECT *
FROM The_table
ORDER BY x;
where x could be either item_id or item. I can guarantee that both fields are order-able. My question is this:
Is there a way to modify the query I gave to get a range of the ordered elements: say from 20th element in the table to the 40th element in the table (after the table has been ordered) or something similar.
Any help would be appreciated.
Thanks,
Yes - it's called "between"
SELECT *
FROM The_Table
WHERE item_id BETWEEN 20 AND 40
This does exactly what it says - it looks for a value between the two numbers supplied. Very useful for finding ranges; works in reverse too (i.e. NOT BETWEEN). For more see here.
If you want a specific row or group of rows (as your updated question suggests) after sorting you can use the LIMIT clause to select a range of entries
SELECT *
FROM The_Table
LIMIT 20, 20
Using LIMIT this way the first number is the starting point in the table and the second number is how many records to return from that point. This statement will return 20 rows starting at row 20 whatever that value is.

Selecting unique rows from a table that are not found in two other tables in sqlite

I have three tables (forward, reverse and probe) that all contain the same columns (Query, QueryLength, Hit, Start, End, Strand, Description, Length, Percent_id, Score, Evalue).
I want to get the unique rows from 'forward' where the 'Hit' is not found in either the 'reverse' table or the 'probe' table. With 'AND' I don't get any results, with 'OR' I get the comparison only with reverse.
CREATE TABLE f AS SELECT * FROM forward WHERE forward.Hit NOT IN (SELECT Hit from reverse) OR (SELECT Hit FROM probe)
Thanks for your help.
When you write ... OR (SELECT Hit FROM probe), you have a scalar subquery, i.e., the database looks only at the first value returned by the subquery, and treats it as 'true' if the value is non-zero.
To check whether a value is found in another table, you have to use IN (in both cases):
SELECT * FROM forward
WHERE Hit NOT IN (SELECT Hit FROM reverse)
AND Hit NOT IN (SELECT Hit FROM probe)
If you want to check entire records instead of only one column, you can use EXCEPT:
SELECT * FROM forward
EXCEPT
SELECT * FROM reverse
EXCEPT
SELECT * FROM probe

Resources