Using recursion with a self Foreign key - sql

I'm using PostgreSQL 10, and I have the following structure:
A table Type with a foreign key to itself.
id name parent_id
1 namea Null
2 nameb Null
3 namea1 1
4 namea11 3
5 namea111 4
6 nameb1 2
7 nameb2 2
A table Item_Type for a Many to Many relation
id type_id item_id
1 1 1
2 3 2
3 5 3
4 7 4
Table Item which has M2M relation to Type.
id name
1 item1
2 item2
3 item3
4 item4
At this moment, I'm using an additional path field, which I calculate every time I make operations(crud) with Type.
I'm wondering if is not faster and easy to try to use the PostgreSQL recursion.
I checked the documentation but I didn't understand very well, because I get an error, and I don't understate why.
WITH RECURSIVE descendants AS (
SELECT id, name FROM Type WHERE id = 1
UNION
SELECT t.id, t.name, t.parent_id FROM Type AS t
INNER JOIN descendants AS d ON d.id = t.parent_id
) SELECT * FROM descendants;
ERROR: each UNION query must have the same number of columns
What I need - Giving a Type name:
1) Get all names/id for the requested Type and is descendants
2) Get all Item for the requested Type and is descendants, and the number of Item per Type and descendants
For example:
If the requested Type name is 'namea1', I should get for Type ids 1,3,4,5 and
for Item ids 1,2,3

The error says it all. Your union is divided between:
SELECT <2 fields> from Type ...
SELECT <3 fields> from Type JOIN Descendant ...
Simply select 3 fields on both halves:
WITH RECURSIVE descendants AS (
SELECT id, name, parent_id FROM Type WHERE id = 1
UNION
SELECT t.id, t.name, t.parent_id FROM Type AS t
INNER JOIN descendants AS d ON d.id = t.parent_id
) SELECT * FROM descendants;

Related

hierarchy with parent and nested child id in bigquery

I have a table in bigquery with the following schema
Name STRING NULLABLE
Parent_id STRING NULLABLE
Child_ids STRING REPEATED
The table is filled with the following rows:
Name Parent_id Child_ids
A 1 [2,3]
B 2 [4]
C 3 null
D 4 null
I would like to make a query which could return not only child_ids but also their name, i.e:
Name Parent_id Child_info
A 1 [(2,B),(3,C)]
B 2 [(4,D)]
C 3 null
D 4 null
Do you have any idea?
Consider below approach
select * except(Child_ids),
array(
select as struct id, Name
from t.Child_ids id
join your_table
on id = Parent_id
) Child_info
from your_table t;
if applied to sample data in your question - output is

Table valued function for parent id

So I have a database table that looks like -
MemberId LinkedMemberId
1 1
2 1
3 1
4 2
5 4
6 4
And I want to build a table value function where I can pass in 1, 2, 3, 4, 5 or 6 and it will return all of the values because they are linked.
Example -
I pass in 4, so I want 2, my LinkedMemberId. Now because I have 2, I also want the LinkedMemberId of 1. And now because I have 1, I also want the MemberIds associated with LinkedMemberId of 1.
Is there already an algorithm to get this kind of data?
You seem to be looking for a hierarchical query that retrives all parents of a given node. A typical approach is a recursive common-table-expression:
with cte as (
select LinkedMemberId, 1 lvl from mytable where memberId = ?
union all
select t.LinkedMemberId, c.lvl + 1
from mytable t
inner join cte c on c.LinkedMemberId = t.memberId
)
select * from cte
This gives you one row for each parent of the input memberId (which is represented by the ? in the query). As a bonus, the second column contains an incrementing integer value that represents the level of the parent in the hierarchy (starting at 1 for the first level parent).

Linking together different columns in a SQL table?

I'm not very experienced with advance SQL queries, I'm familiar with basic statements and basic joins, currently trying to figure out how to write a query that seems to be out of my depth and I haven't been able to find a solution from google so far and I'm hoping somebody might be able to point me in the right direction.
The table I'm working with has an ID column, and a 'parent id' column.
I'm looking for all descendants of ID '1' - rows with a parent ID of '1', rows with a parent ID equal to any row's ID with a parent ID of '1' etc. Currently I've been doing this manually but there are hundreds of descendants so far and I feel like there's a way to put this into one query.
Any help would be appreciated, if this is unclear I can also try to clarify.
EDIT - I got it working with the following query:
with cteMappings as (
select map_id, parent_map_id, map_name
from admin_map
where map_id = '1'
union all
select a.map_id, a.parent_map_id, a.map_name
from admin_map a
inner join cteMappings m
on a.parent_map_id = m.map_id
)
select map_id, parent_map_id, map_name
from cteMappings
Sounds like it can be achieved by Common Table Expression:
DECLARE #temp TABLE (id INT IDENTITY(1, 1), parent_id INT);
INSERT #temp
SELECT NULL
UNION ALL
SELECT 1
UNION ALL
SELECT 2
UNION ALL
SELECT NULL
SELECT * FROM #temp
; WITH HierarchyTemp (id, parent_id, depth) AS (
SELECT id, parent_id, 0
FROM #temp
WHERE id = 1
UNION ALL
SELECT t.id, t.parent_id, ht.depth + 1
FROM #temp t
INNER JOIN HierarchyTemp ht ON ht.id = t.parent_id
)
SELECT *
FROM HierarchyTemp
So the above example is creating a table variable with 4 rows:
id parent_id
1 NULL
2 1
3 2
4 NULL
Result of descendent of id '1' (also including itself, but can be excluded with an additional WHERE clause):
id parent_id depth
1 NULL 0
2 1 1
3 2 2

Delete all level child item using sql query

I have a table where I have menus listed where I can insert and delete.
Structure goes like:-
ID Name ParentId
1 1. Home 0
2 2. Products 0
3 a. SubProduct1 2
4 b. SubProduct2 2
5 i. Subsub 4
6 ii. ...... 4
7 3. About 0
Top-level menu ParentId is always 0 as displayed in 1, 2 and 7.
Child level items would have ParentId of their parent for ex. Subproduct has 2 as its parentId.
When I delete menu item that time all level child item should be delete irrespective of there levels using SQL query.
There can be any number of levels
The levels can go upto subsubsubsub...... any number.
How about this query:
DECLARE #DelID INT
SET #DelID=1
;WITH T(xParent, xChild)AS
(
SELECT ParentID, ChildId FROM Table WHERE ParentID=#DelID
UNION ALL
SELECT ParentID, ChildId FROM TABLE INNER JOIN T ON ParentID=xChild
)
DELETE FROM TABLE WHERE ParentID IN (SELECT xParent FROM T)
You can use a common table expression to get all the heirarchy items from the item you want to delete to the end of the tree hten
;WITH ParentChildsTree
AS
(
SELECT ID, Name, ParentId
FROM MenuItems
WHERE Id = #itemToDelete
UNION ALL
SELECT ID, Name, ParentId
FROM ParentChildsTree c
INNER JOIN MenuItems t ON c.ParentId = t.Id
)
DELETE FROM MenuItems
WHERE ID IN (SELECT ID FROM ParentChildsTree);
Here is a Demo.
For example if you pass a parameter #itemToDelete = 4 to the query the the items with ids 2 and 4 will be deleted.

How to select parent ids

I have table with such structure.
ElementId | ParentId
-------------------
1 | NULL
2 | 1
3 | 2
4 | 3
Let say current element has Id 4. I want to select all parent ids.
Result should be: 3, 2, 1
How I can do it? DB is MSSQL
You can use recursive queries for this: http://msdn.microsoft.com/en-us/library/aa175801(SQL.80).aspx
You can use it like this:
with Hierachy(ElementID, ParentID, Level) as (
select ElementID, ParentID, 0 as Level
from table t
where t.ElementID = X -- insert parameter here
union all
select t.ElementID, t.ParentID, th.Level + 1
from table t
inner join Hierachy th
on t.ParentId = th.ElementID
)
select ElementID, ParentID
from Hierachy
where Level > 0
I think it might be easiest to do the following:
while parent != NULL
get parent of current element
I can't think of any way of doing this in plain SQL that wouldn't cause issues on larger databases.
if you want pure sql try:
select ParentId from myTable Desc
that would work in mysql... you might need to modify the Desc (sort in descending order) part