Sql delete parent from child/delete whole tree - sql

Delete parent and child in loop
Table 1 (Parent table)
Id int
Table 2 (Relationship table)
Id1 int FOREIGN KEY (Id1) REFERENCES Table1 (Id)
Id2 int FOREIGN KEY (Id2) REFERENCES Table1 (Id)
Id - Id1 one to one or one to zero relationship
Id - Id2 one to many
Data in table 1
Id
1
2
3
4
5
6
7
8
9
10
Data in table 2
Id1 Id2
2 1
3 1
4 2
5 2
6 4
7 4
8 5
9 5
So it is like a tree with root as 1
1 has two childs 2 and 3
2 has two childs 4 and 5
4 has two childs 6 and 7
5 has two childs 8 and 9
3,6,7,8,9,10 has no child
Best possible way to achieve the below mentioned case:
Deleting 1 => deletes the complete table2 and table1(except 10 in table 1)

Try
update table2 set id2 = null;
delete from table1 where id <> 10;
delete from table2;

You can do this using Recursive CTE
;WITH cte
AS (SELECT Id1,
Id2,
id2 AS parent
FROM Yourtable
UNION ALL
SELECT a.Id1,
a.Id2,
b.Id2
FROM cte a
JOIN Yourtable b
ON a.parent = b.id1)
SELECT *
FROM cte
WHERE parent = 1
OPTION (maxrecursion 0)
--DELETE FROM Yourtable
--WHERE id1 IN (SELECT id1
-- FROM cte
-- WHERE parent = 1)
--OPTION (maxrecursion 0)
If the select is returning expected results then comment the select and un-comment the Delete

Related

Insert into new table an id with several values

I've been struggling with this problem.
I have 2 populated tables and a third empty one and I would like to populate the third with data from the other two. Correlate values
The idea is to assign every single ID from the 1st table to entries (several) found in the 2nd table that respect the condition where DestinedUserTypeID should be equal to UserTypeID),
Table 1
Id
UserName
UserTypeID
1
Bla
1
2
Ble
2
3
Bli
3
Table 2
ID
TaskName
DestinedUserTypeID
1
Task A
1
2
Task B
1
3
Task C
1
4
Task D
2
DESIRED TABLE, Table 3
ID
UserID
TaskID
1
1
1
2
1
2
3
1
3
...
Insert into Table3 ([UserId],[TaskID])
SELECT
Id,
(SELECT [Id] FROM [Table2] t2
WHERE [Id] <= 5 AND [DestinedUserTypeId] = 1)
FROM t1 WHERE [UserTypeId] = 1
Thank you!
You can do it with a simple join linked to your table 1 and 2 and just insert into your table3
SELECT
u.id,
t.id,
from
table1 as u inner join
table2 as t on u.userTypeId = t.DestinedUserTypeID

SQL - Delete specific set of raw in a table using another table

Tabel 1 :
ID1
ID2
ID3
MainID
Location
1
A
X
1AX
VIC
2
B
Y
2BY
SYD
3
C
W
3CW
TAS
4
D
Z
4DZ
TAS
Tabel 2 :
SALESID
QTY
AMT
DIFF
1AX
1
100
2
2BY
2
0
3
3CW
3
5
4DZ
3
12
2
Ignore other fields, I need to delete all raws in Tabel 1 where AMT in Tabel 2 has zero or no value for the SALESID.
For example, after the query, only raws containing 1AX & 4DZ should be remain in Tabel 1.
this can be done by subquery
get all MainID from table2 where amt is 0 or null
delete all rows that equal to previous fetched MainID
delete from table1 where MainID in (
select SALESID from table2 where AMT <=0 or AMT is null
)
You can use exists:
delete from table1
where exists (select 1
from table2 t2
where table1.mainid = t2.salesid and
(t2.amt = 0 or t2.amt is null)
);
Thinking an INNER JOIN would be much faster on larger data sets. Something like this:
DELETE
T1
FROM
Table1 T1
INNER JOIN
Table2 T2 ON T2.SalesID = T1.MainID
WHERE
IsNull(T2.Amt,0) = 0

Select within select with multiple matches on the other table SQL

I have these 3 tables
Table 1:
id_Table1 field_table1_1 field_table1_2
1 A B
2 C D
3 E F
Table 1:
id_Table2 field_table2_1 field_table2_2
4 G H
5 I J
List item
Table 3:
id_Table3 id_Table1 id_Table2
1 1 4
2 1 5
3 2 5
So table 3 holds the relation between table 1 and 2.
What I want to do, is with a query, get all the fields in the table 1, plus one extra field that contains all the ids of the table 2 separated by coma.
So the result should be something like this:
id_Table1 field_table1_1 field_table1_2 id_Table2
1 A B 4, 5
2 C D 5
3 E F
One option use a lateral join and string_agg():
select t1.*, x.*
from table1 t1
outer apply (
select string_agg(t3.id_table2) id_table2
from table3 t3
where t3.id_table1 = t1.id_table1
) x
There is no need to bring table2 to get the results you want.

How to get the list of parent and Child in a Hierarchy using Oracle SQL

I have two tables, structures of the same is as below:
Table 1. Transactional data table
trx id.
1
2
3
4
5..etc
Table 2
table 2 has the parent child relationship as below .
id subject_id (Child) object_id (Parent)
1 2 1
2 3 1
3 4 1
4 5 1
Now using above tables, the expected output is as follow:
1
2
3
4
5
Please let me know how can I achieve the same. I need to get the details from the Table 1 along with parent and its all children in the hierarchy. I just have one level of hierarchy.
As you just have a one level hierarchy you can get it to work just ordering the results correctly. Try this one:
select obj.object_id, t.*
from
(
select
object_id,
object_id as parent_id
from table2
union
select
subject_id as object_id,
object_id as parent_id
from table2
) obj
inner join table1 t
on t.id = obj.object_id
order by
obj.parent_id,
case when obj.object_id = obj.parent_id then 0 else 1 end,
obj.object_id
;
I light variation on the comment of the #a_horse...
select * from table1
where id in
(select object_id from table2
union all
select subject_id from table2)
order by id;
as expected
1
2
3
4
5
If you want to constraint the parent, simple add WHERE predicates in the subquery.

How to find all 'related' parents from a table containing set of (parent, child)?

I have a SQL Server 2005 table as follows:
parent child
1 a
2 a
2 b
3 b
3 c
4 c
5 d
6 d
7 d
8 e
9 e
9 f
10 f
Each parent can have one or more child, each child can also have one or more parents.
How can I find (or group) all parents that are related?
In above case, I want to group:
parent 1, 2, 3, 4 into group 1
parent 5, 6, 7 into group 2
parent 8, 9, 10 into group 3
A result from the query would look like: (Doesn't matter which parent use as group as long as it is from one of those parent in the group, min ID, or max ID would do)
parent child parent_group
1 a 1
2 a 1
2 b 1
3 b 1
3 c 1
4 c 1
5 d 5
6 d 5
7 d 5
8 e 8
9 e 8
9 f 8
10 f 8
This is similar to those standard boss - subordinate recursive SQL questions except the subordinate may have more than 1 boss.
Is it possible to use SQL to generate result as above? If so how?
Appreciate any help.
There is no way to do this in a single query. I found a blog post (with some ruby code) describing how you can calculate connected components in SQL (MySQL flavor).
Based on the article, I wrote the following SQL (SQL Server flavor):
-- Step 1: Create temporary tables
CREATE TABLE #items (
id int PRIMARY KEY,
component_id int
);
CREATE TABLE #links (
first int,
second int,
PRIMARY KEY (first, second)
);
CREATE TABLE #components_to_merge (
component1 int,
component2 int
PRIMARY KEY (component1, component2)
);
-- Step 2: Populate tables
INSERT INTO #items (id, component_id)
SELECT DISTINCT parent, parent
FROM children;
INSERT INTO #links (first, second)
SELECT DISTINCT c1.parent, c2.parent
FROM children c1
INNER JOIN children c2 ON c1.child = c2.child
WHERE c1.parent <> c2.parent;
-- Step 3: Merge components
WHILE 1 = 1 BEGIN
-- Step 3.1: Update #components_to_merge
TRUNCATE TABLE #components_to_merge;
INSERT INTO #components_to_merge (component1, component2)
SELECT DISTINCT t1.component_id, t2.component_id
FROM #links l
INNER JOIN #items t1 ON t1.id = l.first
INNER JOIN #items t2 ON t2.id = l.second
WHERE t1.component_id <> t2.component_id;
INSERT INTO #components_to_merge (component1, component2)
SELECT component2, component1
FROM #components_to_merge m1
WHERE component2 NOT IN (
SELECT m2.component2
FROM #components_to_merge m2
WHERE m2.component1 = m1.component1
);
IF (SELECT COUNT(*) FROM #components_to_merge) = 0
BREAK;
-- Step 3.2: Update #items
UPDATE i
SET component_id = target
FROM #items i
INNER JOIN (
SELECT
component1 AS source,
MIN(component2) AS target
FROM #components_to_merge
GROUP BY component1
) new_components
ON source = component_id
WHERE target < component_id;
END;
-- Step 4: Generate result
SELECT parent, child, component_id
FROM children
INNER JOIN #items ON id = parent;
You could wrap this up in a stored procedure:
CREATE PROCEDURE CalculateComponents AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION;
-- SQL code from above
ROLLBACK TRANSACTION;
END;
And then call it with
EXEC CalculateComponents;
Output:
parent child component_id
1 a 1
2 a 1
2 b 1
3 b 1
3 c 1
4 c 1
5 d 5
6 d 5
7 d 5
8 e 8
9 e 8
9 f 8
10 f 8