Recursive Query CTE in SQL Lite - sqlite

I have the Following table Structure. (I am new to SQL Lite)
create table Relations
(
Code int,
ParentCode int ,
fname text
)
GO
insert into Relations values(1,null,'A');
insert into Relations values(2,null,'B');
insert into Relations values(3,2,'C');
insert into Relations values(4,3,'D');
I want to get the initial parent of Code =4 :
i.e. values 2 null B
I am not able to figure out how to write a recursive query in sqllite.
Thanks in Advance..

Was a version issue..
This query was not working & was getting a syntax Error.
I upgraded From 3.7.17 To 3.8.7.4 version & it worked..
WITH RECURSIVE
works(Code,Parent) AS (
Select Code,ParentCode from Relations a where a.Code=4
UNION
SELECT Relations.Code, Relations.ParentCode FROM Relations , works
WHERE Relations.Code=works.Parent
)
SELECT * FROM works where Parent is null

Related

How to write complex recursive maria db query

Im trying to write a recursive query for a use on a old and poorly designed database - and so the queries get quite complex.
Here is the (relevant) table relationships
Because people asked - here is the creation code for these tables:
CREATE TABLE CircuitLayout(
CircuitLayoutID int,
PRIMARY KEY (CircuitLayoutID)
);
CREATE TABLE LitCircuit (
LitCircuitID int,
CircuitLayoutID int,
PRIMARY KEY (LitCircuitID)
FOREIGN KEY (CircuitLayoutID) REFERENCES CircuitLayout(CircuitLayoutID)
);
CREATE TABLE CircuitLayoutItem(
CircuitLayoutItemID int,
CircuitLayoutID int,
TableName varchar(255),
TablePK int,
PRIMARY KEY (CircuitLayoutItemID)
FOREIGN KEY (CircuitLayoutID) REFERENCES CircuitLayout(CircuitLayoutID)
);
TableName refers to another table in the database and thus TablePK is a primary key from the specified table
One of the valid options for TableName is LitCircuit
I'm trying to write a query that will select a circuit and any circuit it is related to
I am having trouble understanding the syntax for recursive ctes
my non-functional attempt is this:
WITH RECURSIVE carries AS (
SELECT LitCircuit.LitCircuitID AS recurseList FROM LitCircuit
JOIN CircuitLayoutItem ON LitCircuit.CircuitLayoutID = CircuitLayoutItem.CircuitLayoutID
WHERE CircuitLayoutItem.TableName = "LitCircuit" AND CircuitLayoutItem.TablePK IN (00340)
UNION
SELECT LitCircuit.LitCircuitID AS CircuitIDs FROM LitCircuit
JOIN CircuitLayout ON LitCircuit.CircuitLayoutID = CircuitLayoutItem.CircuitLayoutID
WHERE CircuitLayoutItem.TableName = "LitCircuit" AND CircuitLayoutItem.TablePK IN (SELECT recurseList FROM carries)
)
SELECT * FROM carries;
the "00340" is a dummy number for testing, and it would get replaced with an actual list in usage
What i'm attempting to do is get a list of LitCircuitIDs based on one or many LitCircuitIDs - that's the anchor member, and that works fine.
What I want to do is take this result and feed it back into itself.
I lack an understanding of how to access data from the anchor member:
I don't know if it is a table with the columns from the select in the anchor or if it is simply a list of resulting values
I dont understand if or where I need to include "carries" in the FROM part of a query
If I were to write this function in python I would do it like this:
def get_circuits(circuit_list):
result_list = []
for layout_item_key, layout_item in CircuitLayoutItem.items():
if layout_item['TableName'] == "LitCircuit" and layout_item['TablePK'] in circuit_list:
layout = layout_item['CircuitLayoutID']
for circuit_key, circuit in LitCircuit.items():
if circuit["CircuitLayoutID"] == layout:
result_list.append(circuit_key)
result_list.extend(get_circuits(result_list))
return result_list
How do I express this in SQL?
danblack's comment made me realize something I was missing:
Here is what I was trying to do:
WITH RECURSIVE carries AS (
SELECT LitCircuit.LitCircuitID FROM LitCircuit
JOIN CircuitLayoutItem ON LitCircuit.CircuitLayoutID = CircuitLayoutItem.CircuitLayoutID
WHERE CircuitLayoutItem.TableName = 'LitCircuit' AND CircuitLayoutItem.TablePK IN (00340)
UNION ALL
SELECT LitCircuit.LitCircuitID FROM carries
JOIN CircuitLayoutItem ON carries.LitCircuitID = CircuitLayoutItem.TablePK
JOIN LitCircuit ON CircuitLayoutItem.CircuitLayoutID = LitCircuit.CircuitLayoutID
WHERE CircuitLayoutItem.TableName = 'LitCircuit'
)
SELECT DISTINCT LitCircuitID FROM carries;
I did not think of the CTE as a table to query against - rather just a result set, so I did not realize you have to SELECT from it - or in general treat it like a table.

DELETE from same table used in the WHERE

I have the following query that is supposed to delete from a table with a circular FK requirement;
DELETE FROM question
WHERE defaultGotoQuestionId IN (
SELECT id from question WHERE facilityId IN (
SELECT id FROM facility WHERE customerId NOT IN (1,76)
)
);
But I get the following error;
Table is specified twice, both as a target for 'DELETE' and as a separate source for data
I understand the error message - that I can't DELETE from a TABLE that I am specifying in the WHERE - I just can't seem to work out how to solve it, for myself.
I saw a few examples of using a join - but perhaps I am having an off day - because I have been iterating through copy/paste examples - but still can't manage it.
It works as a SELECT : In that the result gives me the records I want to delete;
SELECT id FROM question
WHERE defaultGotoQuestionId IN (
SELECT id from question WHERE facilityId IN (
SELECT id FROM facility WHERE customerId NOT IN (1,76)
)
);
Thanks for any help!
What version of MariaDB are you using?
DELETE :: Same Source and Target Table
Until MariaDB 10.3.1, deleting from a table with the same source and target was not possible. From MariaDB 10.3.1, this is now possible.
See dbfiddle.
In older versions of MariaDB (or in MySQL, for example), one option you can use is:
DELETE
`question`
FROM
`question`
INNER JOIN (
SELECT
`id`
FROM
`question`
WHERE
`defaultGotoQuestionId` IN (
SELECT
`id`
FROM
`question`
WHERE
`facilityId` IN (
SELECT
`id`
FROM
`facility`
WHERE
`customerId` NOT IN (1, 5)
)
)
) `der` ON
`question`.`id` = `der`.`id`;
See dbfiddle.

Teradata, volatile table and nocount?

So I'm having some issues with a ETL-job where I'm trying to query out a statement including the creation of a volatile table (VT) with the adjoining insert.
Though I'm not sure I think I'm having an issue equivalent to MS-SQL temp table insert if you don't have the "SET NOCOUNT ON" -> I.e. the row count from the insert into the VT is returned to my to my cursor instead of the query using the VT.
I can't use a CTE (don't think I can) because I am inserting a pivoted result into the VT as I need to be able to reference the columns in the main select.
I can't create a view because this is a managed system for a banking core solution; with other words I have no right other than read from which I use to synthesize data from views and extract them.
For the same reason I can't create a stored procedure.
I've googled my way half around the world in 2,5 languages, but I'm not able to find any Teradata equivalent of "SET NOCOUNT ON".
I'm triggering the load from Azure Data Factory and I have a On Prem self hosted integration runtime to ensure connectivity to the TeradataDB.
Needless to say Teradata is not my strong suit and I'm hoping for some help from you guys :)
In advance! Many thanks!
Edit:
So here is the structure of the query:
Create volatile table StackOverflowTable
(
Key1(40),
Pivot1 float,
Pivot2 float,
Pivot3 float
)primary index (Key1) ON COMMIT PRESERVE ROWS;
;
insert into StackOverflowTable
select *
from
(
select atv.row1 Key1
, atv.row2
atv.row3
, row_number() over(partition by atv.row1 order by atv.row2 desc) RowNum
from aTeradataView atv
)s1
Pivot
(
sum(s1.row2) amt1,
sum(s1.row3) amt2
for RowNum in(1,2,3,4)
)p
;
with cte as
(
select av.row_av_1
, av.row_av_2
, av.row_av_3
, av.row_av_4
, av.ReportDate
from anotherView av
)
select cte.row_av_1
, cte.row_av_2
, cte.row_av_3
, cte.row_av_4
, sf.Pivot1
, sf.Pivot2
, sf.Pivot3
, cte.ReportDate StartLoadDate
, '9999-12-31' EndLoadDate
from cte
inner join StackOverflowTable sf on sf = cte.row_av_1
;
DROP TABLE StackOverflowTable
;

UPDATE a table from the SELECT of another one

I have a first table articles where some data are missing.
In the table articles_tmp I have a part of the missing data.
So I want to UPATE articles.path WHERE path IS NULL with the data in articles_tmp.path WHERE path IS NOT NULL.
With SQLite, this doesn't works :
UPDATE articles
SET path = (
SELECT at.path
FROM articles_tmp AS at, articles AS a
WHERE at.article_id = a.id AND a.path IS NULL AND NOT at.path IS NULL
)
WHERE path IS NULL
With MS Access, this works fine :
UPDATE articles
INNER JOIN articles_tmp
ON articles.id = articles_tmp.id
SET articles.path = articles_tmp.path
WHERE articles.path IS NULL AND articles_tmp.path IS NOT NULL
Can someone help ?
Since the SQL Server syntax I provided did not work, here is the solution I came up with. Just a slight modification of your original query, but with my "correlation" suggestion added. Here is an SQL fiddle for it: http://sqlfiddle.com/#!7/34589/7
Here is the code:
UPDATE articles
SET path = (SELECT path FROM articles_tmp AS t WHERE t.id = articles.id)
WHERE path IS NULL;
That works (very correlated, probably too much) :
UPDATE articles
SET path = (
SELECT at.path
FROM articles_tmp AS at
WHERE at.article_id=articles.id
)
WHERE EXISTS (
SELECT *
FROM articles_tmp AS at
WHERE at.article_id=articles.id AND articles.path IS NULL AND NOT at.path=''
)

sqlite3 if exists alternative

I am trying to run simple query for sqlite which is update a record if not exists.
I could have used Insert or replace but article_tags table doesn't have any primary key as it is a relational table.
How can I write this query for sqlite as if not exists is not supported.
And I don't have idea how to use CASE for this ?
Table Structure:
articles(id, content)
article_tags(article_id, tag_id)
tag(id, name)
SQLITE Incorrect Syntax Tried
insert into article_tags (article_id, tag_id ) values ( 2,7)
if not exists (select 1 from article_tags where article_id =2 AND tag_id=7)
I think the correct way to do this would be to add a primary key to the article_tags table, a composite one crossing both columns. That's the normal way to do many-to-many relationship tables.
In other words (pseudo-DDL):
create table article_tags (
article_id int references articles(id),
tag_id int references tag(id),
primary key (article_id, tag_id)
);
That way, insertion of a duplicate pair would fail rather than having to resort to if not exists.
This seems to work, although I will, as others have also said, suggest that you add some constraints on the table and then simply "try" to insert.
insert into article_tags
select 2, 7
where not exists ( select *
from article_tags
where article_id = 2
and tag_id = 7 )

Resources