Simple SQL select overloads my server - sql

Problem is that this Task, though looking easy challenges my SQL Server so I have to look for an easier one.
I have table items (with 300.000 rows)
item
-----
10
11
13
14
15
Then I have table parent-Child (with 900.000 rows)
Parent Child
--------------
10 13
14 13
13 15
For every row in items I want to find out if
item is at least one time in Parent and NOT in Child
item is in Parent AND Child
item is in Child AND NOT in Parent
is neither (ok - the rest...)
I want to write the related case a/b/c/d into a dedicated column in item table.
The approaches Select -> worked fine as long as there were few rows -> kill my server with growing log and extreme CPU load
-- Select with CTE
With G1 (P) as
(
select PARENT
from parent_child
where < ... condition>
), G2 (C) as
(
select CHILD
from parent_child
where < ... condition>
)
update Item_Master
set Item_Assembly_Level = '1'
where Item_Number in (select * from G1)
and Item_Number not in (select * from G2) ;

you can test this.
UPDATE I SET Item_Assembly_Level =
CASE
WHEN P.PARENT IS NOT NULL AND C.CHILD IS NULL THEN 1 --a) item is at least one time in Parent and NOT in Child
WHEN P.PARENT IS NOT NULL AND C.CHILD IS NOT NULL THEN 2 --b) item is in Parent AND Child
WHEN P.PARENT IS NULL AND C.CHILD IS NOT NULL THEN 3 --c) item is in Child AND NOT in Parent
ELSE 4 --d) is neither (ok - the rest...)
END
FROM Item_Master I
LEFT JOIN parent_child P ON I.Item_Number = P.PARENT
LEFT JOIN parent_child C ON I.Item_Number = C.CHILD

With G1 (P)
as (
select DISTINCT PARENT from parent_child
where < ... condition>
EXCEPT
select DISTINCT CHILD from parent_child
where < ... condition>
)
update Item_Master set Item_Assembly_Level = '1' where
Item_Number in (select P from G1)
;

Related

Recursive Query CTE Father - Son - Grandson error

I have a table that has an ID and IDFATHER of some projects, these projects can receive N sons, so, the structure is like
ID
IDFATHER
REV
1
1
0
2
1
1
5
2
2
I need to, iniciating in ID 5 go to ID 1, so I did a CTE Query:
WITH lb (ID, IDFATHER) AS (
SELECT ID, IDFATHER
FROM PROJECTS
WHERE ID = 5
UNION ALL
SELECT I.ID, I.IDFATHER
FROM PROJECTS I
JOIN lb LBI ON I.ID = LBI.IDFATHER
--WHERE I.ID = LBI.IDFATHER -- Recursive Subquery
)
SELECT *
FROM lb
WHERE LB.ID = LB.IDFATHER
When this code runs it gives me:
The statement terminated. The maximum recursion 100 has been exhausted
before statement completion.
So basically I handle it by just adding:
SELECT TOP 1 * FROM LB WHERE LB.ID = LB.IDFATHER
But I really want to know were is my error. Can anyone give me a hand on these?
The first row points to itself so the recursion never stops. You need to add this condition inside the recursive cte:
WHERE LBI.ID <> LBI.IDFATHER
I would rather set IDFather of the first row to NULL.
The recursion didn't stop because your top row refers to itself endlessly.
If the top row has a null parent, that would have stopped the recursion.
Another approach is to use that case id = parentid as the termination logic.
The fiddle
WITH LB (ID, IDFATHER, idstart) AS (
SELECT ID, IDFATHER, id
FROM PROJECTS WHERE ID = 5
UNION ALL
SELECT I.ID, I.IDFATHER, lbi.idstart
FROM PROJECTS I
JOIN LB LBI
ON I.ID = lbi.IDFATHER
AND lbi.id <> lbi.idfather
)
SELECT id AS idtop, idstart
FROM LB
WHERE LB.ID = LB.IDFATHER
;
The result:

SQL - where condition for multple child tables

I have some 10 tables in which 1 is parent and other 9 are parallel children.
All these 9 tables have a column named Version with values 0 & above. zero is draft.
I tried with JOINS but with joins I got ambiguity for Version Column.
Is there any way where I can say that any of these 9 child tables has any drafts
Required output is Parent table columns + HasDrafts (From child tables).
Is there any way to achieve this ? If yes then guide me please.
If you don't care which table has the drafts or how many, then you can use exists in a case expression:
select p.*,
(case when exists (select 1 from child1 c where c.parentid = p.parentid and c.version = 0) or
exists (select 1 from child2 c where c.parentid = p.parentid and c.version = 0) or
exists (select 1 from child3 c where c.parentid = p.parentid and c.version = 0) or
. . .
then 1 else 0
end) as has_drafts
from parent p;
I would have made a union and set an extra column for which table it is Ex.
Select ID, Version, 'tableA' from TableA
union
Select ID, Version, 'tableB' from TableB
Thats my dirty solution.

Look for data where child doesn't exisit

How to look in Table C for those inspectors who have got ParentID but not child.
Table A has both parent and child data. Parent ID 0 is for parents and child has their parent ID.
In Table C, one inspector can have many parents and many childs.
I need to run a query to look for those inspectors who have got parents but not child.
Table A Table B Table C
-------- ------- -------
DisciplineID(PK) InspectorID(PK) ID (PK)
ParentID DisciplineID(FK)
InspectorID (Fk)
Table A Table C
In above mentioned data, Inspector 7239 and 7240 only have parent but not child. So query should return those two not 7242 because he has both parent and childs.
Use EXISTS and NOT EXISTS:
SELECT c.ID, c.InspectorID, c.DisciplineID
FROM dbo.TableC c
WHERE EXISTS
(
SELECT 1 FROM dbo.TableA a
WHERE a.DisciplineID = c.DisciplineID
AND a.ParentID = 0 -- parent exists
)
AND NOT EXISTS
(
SELECT 1 FROM dbo.TableC c2
WHERE c.InspectorID = c2.InspectorID
AND c.ID <> c2.ID -- look for another record with this InspectorID
AND EXISTS
(
SELECT 1 FROM dbo.TableA a
WHERE a.DisciplineID = c2.DisciplineID
AND a.ParentID <> 0 -- no child exists
)
)
I would start with a pre-qualifying query per discipline based on those having a count of entries that HAVE a parent ID = 0 but also no records as child... Join that result to your TableC
SELECT
c.ID,
c.InspectorID,
c.DisciplineID
FROM
dbo.TableC c
JOIN ( select
a.DisciplineID
from
TableA a
group by
a.DisciplineID
having
sum( case when a.ParentID = 0 then 1 else 0 end ) > 0
AND sum( case when a.ParentID > 0 then 1 else 0 end ) = 0 ) qual
on c.DisciplineID = qual.DisciplineID
You can try this:
SELECT DISTINCT B.INSPECTORID FROM TABLEA A
LEFT JOIN TABLEC CHILD ON CHILD.DISCIPLINEID = A.DISCIPLINEID
LEFT JOIN TABLEC PARENT ON PARENT.DISCIPLINEID = A.PARENTID
JOIN TABLEB B ON A.INSPECTORID = B.INSPECTORID
WHERE (A.PARENTID = 0 AND CHILD.DISCIPLINEID IS NOT NULL)

SQL Query to find Parent-Child Child-Parent relationships?

o_O
If I have the following records in a table:
Parent Child
1 2 <--
2 1 <--
3 2
3 4
etc...
And I want to identify records that are both the parent of their child AND the child of their parent such as the 2 records identified by arrows above, how would I accomplish this?
I am trying to run some recursive SQL on this table, but these items are causing an infinite loop. I would like to identify these items so they can be addressed manually.
My brain is fried-enough from messing with recursive queries, I have nothing left to solve this one. Please help :)
If understood you well, you don't need recursion at all:
SELECT a.parent, a.child
FROM table1 a
INNER JOIN table1 b ON (b.child=a.parent and a.child = b.parent)
You might want to use LEFT JOIN instead of INNER if you also need to display rows that don't satisfy condition .
The following query will work in your example case. If it needs more you'll have to extend the demonstration information
;WITH CTE_DATA AS (
Select Parent = 1, Child = 2
union Select Parent = 2, Child = 1
union Select Parent = 3, CHild = 2
union Select Parent = 3, Child = 4
)
select
d1.*
from
CTE_DATA d1
join CTE_DATA d2 on d1.Child = d2.Parent and d2.Child = d1.Parent
DECLARE #YourTable TABLE (Parent INT, Child INT)
INSERT INTO #YourTable
SELECT 1, 2
UNION
SELECT 2, 1
UNION
SELECT 3, 2
UNION
SELECT 3, 4
SELECT *
FROM #YourTable A
INNER JOIN #YourTable B
ON A.Parent = B.Child AND A.Child = B.Parent

Select count(*) or zero

Tiredness prevents me from finding this one... Say you have the following tables:
Parent
PARENT_ID (LONG)
Child
CHILD_ID (LONG)
PARENT_ID (LONG, FK)
HAS_GRADUATED (BOOLEAN)
I want a query to return the following true (1, in the case of Oracle) if the parent has at least one child that has graduated, and false (0, in the case if Oracle) if the parent does not have a child that has graduated, or has no children at all:
PARENT_ID................HAS_CHILDREN_WHO_GRADUATED
5.................................1
3.................................1
6.................................0
2.................................0
In the above, parent with parent_id=5 may have >=1 children that have graduated. Same is parent with parent_id=3. Parent with parent_id=6 either has no children at all, or has children but none of them has graduated.
What would the query to this be like?
Use:
SELECT DISTINCT
p.parent_id,
CASE WHEN c.parent_id IS NULL THEN 0 ELSE 1 END
FROM PARENT p
LEFT JOIN CHILD c ON c.parent_id = p.parent_id
AND c.has_graduated = 1
You have to use an outer join in order to see the parent values that don't have supporting records in the child table.
Will this give you what you expect?
SELECT
P.Parent_Id,
CASE WHEN (SUM (CASE WHEN Has_Graduated = 1 then 1 else 0 END)) = 0 THEN 0 ELSE 1 as HAS_CHILDREN_WHO_GRADUATED
FROM Parent P
LEFT JOIN Child C
ON P.Parent_Id = C.Parent_Id
GROUP BY P.Parent_Id
It is likely that OMG Ponies solution will perform better (which is why he got my +1), but this yet another way of solving the problem.
Select Parent_Id
, Case
When Exists( Select 1
From Child
Where Child.Parent_Id = Parent.Parent_Id
And Child.Has_Graduated = 1 ) Then 1
Else 0
End
From Parent
First of all I don't think you can use LONG columns for this since LONG values cannot be used in WHERE conditions. Note this is true as of 10g, since that's what I use.
Second I assume you mean that your child table should have a column called PARENT_ID otherwise there would be no way to link the two tables. Given that, this query ought to work:
SELECT PARENT_ID, COUNT(1) FROM Child WHERE HAS_GRADUATED = 1 GROUP BY PARENT_ID
Here's the form of the query, though the syntax for Oracle may be off:
SELECT
Parent.PARENT_ID
,case count(Child.PARENT_ID) when 0 then 0 else 1 end HAS_CHILDREN_WHO_GRADUATED
from Parent
left outer join Child
on Child.PARENT_ID = Parent.PARENT_ID
where Child.HAS_GRADUATED = 1
group by Parent.PARENT_ID
This will list all Parent items once, with HAS_CHILDREN_WHO_GRADUATED
set to 1 or 0 set as desired.
(Edited to add the where clause)