SQL Get all parent and child of active parent - sql

Here is my case I have a table structure like :
I just want to get all active parents (i.e record with name A,E and G) and their child.
The expected result should look like this :

with recursive as (
SELECT par.Id,
par.Name,
par.ParentID,
par.IsDeleted
FROM table1 par
JOIN table1 chi
ON par.Id = chi.ParentId
union all
SELECT par.Id,
par.Name,
par.ParentID,
rec.IsDeleted
FROM table1 par
JOIN recursive rec
ON rec.Id = par.ParentId
),
check_tbl as (
select Id,
sum(IsDeleted) as IsDeleted
from recursive
group by Id
having sum(IsDeleted)=0
)
select table1.id, Name, ParentID, table1.IsDeleted
from check_tbl join table1 on table1.Id=check_tbl.Id
;

Related

Use Exists with a Column of Query Result?

I have 2 tables.
One is bom_master:
CHILD
PARENT
1-111
66-6666
2-222
77-7777
2-222
88-8888
3-333
99-9999
Another one is library:
FileName
Location
66-6666_A.step
S:\ABC
77-7777_C~K1.step
S:\DEF
And I want to find out if the child's parents have related files in the library.
Expected Result:
CHILD
PARENT
FileName
1-111
66-6666
66-6666_A.step
2-222
77-7777
77-7777_C~K1.step
Tried below lines but return no results. Any comments? Thank you.
WITH temp_parent_PN(parentPN)
AS
(
SELECT
[PARENT]
FROM [bom_master]
where [bom_master].[CHILD] in ('1-111','2-222')
)
SELECT s.[filename]
FROM [library] s
WHERE EXISTS
(
SELECT
*
FROM temp_parent_PN b
where s.[filename] LIKE '%'+b.[parentPN]+'%'
)
If you have just one level of dependencies use the join solution proposed by dimis164.
If you have deeper levels you could use recursive queries allowed by WITH clause (
ref. WITH common_table_expression (Transact-SQL)).
This is a sample with one more level of relation in bom_master (you could then join the result of the recursive query with library as you need).
DECLARE #bom_master TABLE (Child NVARCHAR(MAX), Parent NVARCHAR(MAX));
INSERT INTO #bom_master VALUES
('1-111', '66-666'),
('2-222', '77-777'),
('3-333', '88-888'),
('4-444', '99-999'),
('A-AAA', '1-111');
WITH
leaf AS ( -- Get the leaf elements (elements without a child)
SELECT Child FROM #bom_master b1
WHERE NOT EXISTS (SELECT * FROM #bom_master b2 WHERE b2.Parent = b1.Child) ),
rec(Child, Parent, Level) AS (
SELECT b.Child, b.Parent, Level = 1
FROM #bom_master b
JOIN leaf l ON l.Child = b.Child
UNION ALL
SELECT rec.Child, b.Parent, Level = rec.Level + 1
FROM rec
JOIN #bom_master b
ON b.Child = rec.Parent )
SELECT * FROM rec
I think you don't have to use exists. The problem is that you need to substring to match the join.
Have a look at this:
SELECT b.CHILD, b.PARENT, l.[FileName]
FROM [bom_master] b
INNER JOIN [library] l ON b.PARENT = SUBSTRING(l.FileName,1,7)

Re-writting the query without "Connect By "

I am rewriting the query to replace to remove CONNECT BY:
SELECT *
FROM ADM_TRT AT
INNER JOIN UTILISATEUR U
ON U.UTI_ID = AT.UTI_ID
INNER JOIN
(
SELECT CM.MAI_ID
FROM CON_MAI CM
CONNECT BY CM.MAI_PER_RES = PRIOR CM.MAI_ID
START WITH CM.MAI_ID IN (
SELECT MAJ_ID
FROM DROIT_LOGIN
WHERE LOG_ID = 21543
)
) CON_MAI_FILTERED_ON_LOGIN
ON AT.TRT_MAI_ID = CON_MAI_FILTERED_ON_LOGIN.MAI_ID;
For CONNECT BY Part , I wrote this
WITH tree (MAI_ID,MAI_PER_RES, level1) AS (
SELECT MAI_PER_RES, MAI_ID, 1 as level1 FROM CON_MAI
UNION ALL
SELECT child.MAI_ID, child.MAI_PER_RES, parent.level1 + 1
FROM CON_MAI child --Line 20
JOIN tree parent
on parent.MAI_PER_RES = child.MAI_ID
)
SELECT MAI_ID FROM tree
But I am stuck to integrate this in subquery in the CONNECT BY sub-query. Can someone please help to integrate this?
It looks like you have the recursion reversed in the recursive sub-query and can use:
WITH tree (MAI_ID) AS (
SELECT MAI_ID
FROM CON_MAI
WHERE MAI_ID IN ( SELECT MAJ_ID
FROM DROIT_LOGIN
WHERE LOG_ID = 21543 )
UNION ALL
SELECT c.MAI_ID
FROM CON_MAI c
JOIN tree p
on c.MAI_PER_RES = p.MAI_ID
)
SELECT *
FROM ADM_TRT AT
INNER JOIN UTILISATEUR U
ON U.UTI_ID = AT.UTI_ID
INNER JOIN tree CON_MAI_FILTERED_ON_LOGIN
ON AT.TRT_MAI_ID = CON_MAI_FILTERED_ON_LOGIN.MAI_ID;
(untested as I do not have your tables or data)

Recursive Parent/Child in same table query in SQL where parent is PK

I have seen a lot of examples about how to implement a recursive query where there is the parent and the child in the same table, but in the examples, the child has a parent and I need at the contrary, when a parent has a child.
I would like to obtain all children in recursive mode just like in the image.
In the image, you can see, I have a parent with id 1, it has a child with id 2. The child 2 is a parent too who has a child with id 3, etc.
I don't know how to create a recursive query to obtain all the childs from a parent.
You can access to the next link to execute the sql online: http://www.sqlfiddle.com/#!18/dbed2/1
This produces the results you are asking for:
with cte as (
select idchild, idparent,
convert(varchar(max), idchild) as children
from family f
where not exists (select 1 from family f2 where f2.idparent = f.idchild)
union all
select f.idchild, f.idparent,
concat(f.idchild, ',', cte.children)
from cte join
family f
on cte.idparent = f.idchild
)
select *
from cte
order by idchild;
Here is the SQL Fiddle.
Here you go:
with
n as (
select idparent, idchild, 1 as lvl,
cast(concat('', idchild) as varchar(255)) as children from family
union all
select n.idparent, f.idchild, lvl + 1,
cast(concat(children, ',', f.idchild) as varchar(255))
from n
join family f on f.idparent = n.idchild
)
select n.idparent, f.idchild, n.children
from n
join (
select idparent, max(lvl) as maxlvl from n group by idparent
) m on n.idparent = m.idparent and n.lvl = m.maxlvl
join family f on f.idparent = n.idparent
order by n.idparent
See SQL Fiddle.
if you are using SQL Server 2017 or newer you can use the following:
WITH CTE
AS (SELECT *
FROM dbo.Table_1
UNION ALL
SELECT Child.idParent,
Parent.idChild
FROM CTE AS Parent
INNER JOIN dbo.Table_1 AS Child
ON Parent.idParent = Child.idChild)
SELECT CTE.idParent,
STRING_AGG(CTE.idChild, ', ') AS Childs
FROM CTE
GROUP BY CTE.idParent;
but if you have older version use the following :
WITH CTE
AS (SELECT *
FROM dbo.Table_1
UNION ALL
SELECT Child.idParent,
Parent.idChild
FROM CTE AS Parent
INNER JOIN dbo.Table_1 AS Child
ON Parent.idParent = Child.idChild)
SELECT DISTINCT
B.idParent,
STUFF(
(
SELECT ',' + CONVERT(VARCHAR(10), CTE.idChild)
FROM CTE
WHERE B.idParent = CTE.idParent
ORDER BY CTE.idChild
FOR XML PATH('')
),
1,
1,
''
) AS Childs
FROM CTE AS B

minus two tables with primary key

I have sql database with tables:
sc: s_id, m_id
s: id, name
m: id, name
sc_standart: s_id, m_id
s_standart: id, name
m_standart: id, name
sc.s_id is from s.id, sc.m_id is from m.id, sc_standart.s_id is from s_standart.id, sc_standart.m_id is from m_standart.id.
I should set m_id=null for all lines from sc which are not exist in sc_standart.
I had already written:
SELECT s.name, m.name
FROM s
JOIN sc
ON s.id=sc.s_id
JOIN m
ON m.id=sc.m_id
MINUS
SELECT s_standart.name, m_standart.name
FROM s_standart
JOIN sc_standart
ON s_standart.id=sc_standart.s_id
JOIN m_standart
ON m_standart.id=sc_standart.m_id
So I should update (s_id, m_id) lines relevant to (s.name, m.name) from the select above.
It looks like you could just do it as:
update sc
set m_id = null
where not exists
( select 1 from sc_standart s
where s.m_id = sc.m_id )
Or using minus:
update sc
set m_id = null
where m_id in
( select m_id from sc
minus
select m_id from sc_standart )
However, I might be missing something as I couldn't see how the other four tables were related to your question.

SQL hide rows specifically

This is my table structure and sample rows:
And I have a SQL query like this :
WITH Test(ObjId, ObjectIcerik, KeyMi) AS
(
SELECT
ObjId, ObjectIcerik, KeyMi
FROM
Tek
WHERE
ObjId = 8
UNION ALL
SELECT
T.ObjId, T.ObjectIcerik, T.KeyMi
FROM
Tek T
INNER JOIN
Test as TE ON T.ObjParent = TE.ObjId
)
SELECT *
FROM Test
This is the result :
But I also need to hide parent and child rows if parent's KeyMi column is '1'.
What do I need to change in the SQL query to do this?
You should be able to just add the condition to the recursive CTE:
WITH Test(ObjId, ObjectIcerik, KeyMi) AS (
SELECT ObjId, ObjectIcerik, KeyMi FROM Tek
WHERE ObjId = 8 AND (KeyMI <> 1 OR KeyMI IS NULL)
UNION ALL
SELECT T.ObjId, T.ObjectIcerik, T.KeyMi
FROM Tek T INNER JOIN
Test TE
ON T.ObjParent = TE.ObjId
WHERE (t.KeyMI <> 1 OR t.KeyMI IS NULL)
)
SELECT *
FROM Test ;