How to recursively calculate tree depth in SQLite - sqlite

I currently have a table in SQLite that looks something like the following, forming a tree-like structure:
+-----+-----------+---------------+
| _id | parent_id | tree_depth |
+=====+===========+===============+
| 1 | 0 | 0 |
| 2 | 1 | (should be 1) |
| 3 | 2 | (should be 2) |
+-----+-----------+---------------+
I have very limited SQLite experience and the table is quite large, so I would hate to have to fill it out manually. Is there a query I could use to update the tree_depth column such that it properly represents the depth of the tree at that node? I tried selecting the parent's tree depth and incrementing, but for some reason it set everything to 1.
Any advise would be greatly appreciated.
EDIT: The query that I'm trying is:
UPDATE table SET tree_depth = (SELECT p.tree_depth FROM table JOIN table p ON p._id=table.parent_id) +1

You need a recursive CTE to compute the tree depth of each entry.
You can then use this data to look up the value to UPDATE:
WITH RECURSIVE depths(id, depth) AS (
SELECT _id, 0
FROM MyTable
WHERE parent_id = 0
UNION ALL
SELECT MyTable._id, depths.depth + 1
FROM MyTable
JOIN depths ON MyTable.parent_id = depths.id
)
UPDATE MyTable
SET tree_depth = (SELECT depth
FROM depths
WHERE depths.id = MyTable._id);
(Note: older Android versions do not support CTEs.)

Please try?
update table
set a.tree_depth = b.parent_id
If it doesn't wok, try to add this too:
FROM table a
INNER JOIN table b
on a._id= b._id

Related

How to select the next 50 records from a specified row in an SQLite table

Consider that my SQLite table has the following schema,
|'''''''''''''''''''''''''''''''''''''
| unique_id(TXT) | object_data(BLOB) |
|'''''''''''''''''''''''''''''''''''''
| | |
| | |
| | |
''''''''''''''''''''''''''''''''''''''
Assume that the row_id property is enabled, and so my question is, for a given unique_id, is it possible to fetch the next 50 records from the table,
using a single SQL query? (Using the row_id property)
Try getting result through this method.
Select * from table_name [WHERE conditions] Limit 50 offset (Select row_id from table_name where unique_id = x);

How to rank rows in a table in sqlite?

How can I create a column that has ranked the information of the table based on two or three keys?
For example, in this table the rank variable is based on Department and Name:
Dep | Name | Rank
----+------+------
1 | Jeff | 1
1 | Jeff | 2
1 | Paul | 1
2 | Nick | 1
2 | Nick | 2
I have found this solution but it's in SQL and I don't think it applies to my case as all information is in one table and the responses seem to SELECT and JOIN combine information from different tables.
Thank you in advance
You can count how many rows come before the current row in the current group:
UPDATE MyTable
SET Rank = (SELECT COUNT(*)
FROM MyTable AS T2
WHERE T2.Dep = MyTable.Dep
AND T2.Name = MyTable.Name
AND T2.rowid <= MyTable.rowid);
(The rowid column is used to differentiate between otherwise identical rows. Use the primary key, if you have one.)

In clause in oracle

I have select query like this
SELECT * FROM ACTITIVY WHERE CODE in ('L','D')
Instead of hardcording the values in IN PARAMETER I have created a PARAM table. The param table has the below values
CODE | CODE_VAL | ACTIVE
TRIGGER_XM | 'L','D' | Y
so when i rewrite the query as below
select * from ops_ACTITIVY WHERE CODE IN (
SELECT CODE_VAL FROM OPS_CONFIG_PARAMETER
WHERE CODE='TRIGGER_XML' AND ACTIVE='Y')
It doesn't work any idea how to resolve this??
You may try like this:
select * from ops_ACTITIVY t1
WHERE t1.CODE IN ( SELECT CODE_VAL FROM OPS_CONFIG_PARAMETER t2
WHERE t2.CODE='TRIGGER_XML' AND t2.ACTIVE='Y' )
As you are checking for the existence of a string inside another string you could try something like this:
select * from activity a where (
select instr(b.code_val, a.code)
from param b
where b.code = 'TRIGGER_XM'
AND active = 'Y'
) > 0;
But it will most likely only work as long as as you have singlechar codes.
Worked for me at: SQL Fiddle
which table are you really using? ACTITIVY or ops_ACTITIVY?
Assuming that those tables are the same, i would suggest that your PARAMETERS Table have the below values:
| CODE | CODE_VAL | ACTIVE |
| ----------- ----------- -------------
| TRIGGER_XM | L | Y |
| TRIGGER_XM | D | Y |
It is much more manageable, and i think makes much more sense to separate the Code Values of L and D in case you only need to select one of them.
Now, the query below would surely fetch both Codes with 'L' and 'D' values from the ops_ACTITIVY table:
select *
from ops_ACTITIVY
WHERE CODE IN (SELECT CODE_VAL
FROM OPS_CONFIG_PARAMETER
WHERE CODE ='TRIGGER_XML'
AND ACTIVE = 'Y');

SQLite Compare two columns

I am creating a database for my Psych class and I am scoring a personality profile. I need to compare two test items and, if they match a condition, then copy into a separate table.
Example (pseudocode is between \)Sqlite3
INSERT INTO Scale
SELECT* FROM Questions
WHERE \\if Question 1 IS 'TRUE' AND Question 3 IS 'FALSE' THEN Copy this Question
and its response into the Scale table\\;
I have about 100 other questions that work like this. Sample format goes like this:
IF FirstQuestion IS value AND SecondQuestion IS value THEN
Copy both questions into the Scale TABLE.
---------- EDITED AFTER FIRST RESPONSE! EDITS FOLLOW-------------
Here is my TestItems table:
ItemID | ItemQuestion | ItemResponse
```````````````````````````````````````````````````
1 | Is the sky blue? | TRUE
2 | Are you a person? | TRUE
3 | 2 Plus 2 Equals Five | FALSE
What I want to do: If Question 1 is TRUE AND Question 3 is FALSE, then insert BOTH questions into the table 'Scale' (which is setup like TestItems). I tried this:
INSERT INTO Scale
SELECT * FROM TestItems
WHERE ((ItemID=1) AND (ItemResponse='TRUE'))
AND ((ItemID=3) AND (ItemResponse='FALSE'));
HOWEVER: The above INSERT copies neither.
The Resulting 'Scale' table should look like this:
ItemID | ItemQuestion | ItemResponse
```````````````````````````````````````````````````
1 | Is the sky blue? | TRUE
3 | 2 Plus 2 Equals Five | FALSE
There is nothing wrong with your query. You're just there:
INSERT INTO Scale
SELECT * FROM Questions
WHERE `Question 1` = 1 AND `Question 3` = 0;
Here 1 and 0 are values (in your first case, true and false). First of all you should ensure there are fields Question 1 and Question 3 in your Questions table. Secondly the column count as well as data types of Scale table should match Questions table. Otherwise you will have to do selectively choose the fields in your SELECT query.
Edit: To respond to your edit, I am not seeing an elegant solution. You could do this:
INSERT INTO Scale
SELECT * FROM TestItems WHERE ItemID = 1 AND ItemResponse = 'TRUE'
UNION
SELECT * FROM TestItems WHERE ItemID = 3 AND ItemResponse = 'FALSE'
WHERE (SELECT COUNT(*) FROM (
SELECT 1 FROM TestItems WHERE ItemID = 1 AND ItemResponse = 'TRUE'
UNION
SELECT * FROM TestItems WHERE ItemID = 3 AND ItemResponse = 'FALSE'
) AS t) >= 2
Your insert did not work because ItemID cant be both 1 and 3 at the same time. My solution gets the required records to be inserted into Scale table, but verifies both the record exists by checking the count. Additionally you could (should) do as below since this can be marginally more efficient (the above SQL was to clearly show the logic being used):
INSERT INTO Scale
SELECT * FROM TestItems WHERE ItemID = 1 AND ItemResponse = 'TRUE'
UNION
SELECT * FROM TestItems WHERE ItemID = 3 AND ItemResponse = 'FALSE'
WHERE (
SELECT COUNT(*)
FROM TestItems
WHERE ItemID = 1 AND ItemResponse = 'TRUE'
OR ItemID = 3 AND ItemResponse = 'FALSE'
) >= 2

Complicated query with SQLite

I have a complicated query that I just cant create. I'm thinking of doing it with JOIN's but don't know where to start. I'll just try to explain my problem as clearly as possible.
I am creating software that deals with compensations. Every compensation can have several links (like in a chain). Each link is basically a customer. So, I'll just tell you the table structures:
Customer
CustomerID | Name
Compensation
CompensationID | CustomerID | Date
Link
LinkID | CompensationID | CustomerID | Sequential
Now, the Sequential field increases with every link added. Let me demonstrate by filling the tables with some data:
CustomerID | Name
-----------+-----
0 | Foo
1 | Bar
2 | Baz
CompensationID | CustomerID | Date
---------------+------------+------
0 | 0 | 2-2-2010
1 | 1 | 2-3-2010
LinkID | CompensationID | CustomerID | Sequential
-------+----------------+------------+-----------
0 0 0 0
1 0 2 1
2 0 1 2
So no matter what the LinkID/CompensationID/CustomerID the Sequential always goes from 0 to N in the Links table (depending on how many links a compensation has).
Now here is the problem: I want to list all Compensation's whose Link's meet the following requirements:
Search in Links
CustomerID = A
Sequential = 0 (first link) AND Sequential = LAST (in this case 2)
List compensations
Here is what I got so far:
SELECT * FROM Compensation JOIN Link ON Compensation.ID = Link.CompensationID
WHERE Link.CustomerID=A AND Link.Sequential = 0 AND Link.Sequential=LAST
This is more or less pseudo SQL since I know Link.Sequential cant be 0 and another value at the same time, but I don't know how to do this.
Any help would be appreciated.
Thank you.
P.S.
Sorry for the big wall of text.
If subqueries in where statements work how I remember:
select *
from
Compensation
left join
Link
on Compensation.CompensationID = Link.CompensationID
where
Link.CustomerID = :A
AND (
Link.Sequential = 0
OR
Link.Sequential = (
select MAX(Sequential) from Link where Link.CustomerID = :A
)
)
Try
SELECT c.*
FROM Compensation c
JOIN (select CompensationID, MAX(Sequential) AS LastSeq FROM Link GROUP BY CompensationID) AS LastOnes ON c.ID = LastOnes.CompensationID
JOIN (select CompensationID FROM Link WHERE CustomerID=A AND Sequential=0) AS FirststOnes ON c.ID = FirststOnes.CompensationID
JOIN Link AS l on l.CompensationID=c.CompensationID AND l.CustomerID=A AND l.Sequential=LastOnes.LastSeq

Resources