Select count(*) or zero - sql

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)

Related

sql query to update parent with more than two children

I have two tables like these:
parents(id:int, name:string, large_family:boolean default false)
children(id:int, name:string, parent_id:foreign key to parents)
how can i write a query to update large_family field in parent to true if a parent has more than two children.
thank you
In most databases, you can do this with a correlated subquery:
update parents
set large_family = 1
where (select count(*) from children c where c.parent_id = parent.id) > 2
You can do this with a subquery in the SET set clause to set the large_family field for all rows, or you could use a subquery in the WHERE clause to only set it for rows with more than 2 children. Here is an example using the SET clause:
UPDATE p
SET p.large_family = CASE WHEN (SELECT COUNT(*) FROM children c WHERE c.parent_id = p.id) > 2 THEN 1 ELSE 0 END
FROM parents p

In Django, how do I query that all of the related objects have the same value for a certain field?

Let's say I have the following models in Django:
class Parent(models.Model):
pass
class Child(models.Model):
parent = models.ForeignKey(Parent, related_name='children', null=True)
foo = models.CharField(max_length=5, blank=True, null=True)
How would I query the Parent model to find all Parent records where ALL of it's children have a value of 'ABC' for foo?
If I run:
Parent.objects.filter(children__foo='ABC'), it returns Parent objects where at least one of it's children has a value of 'ABC' for foo, which is not what I want. Any help is appreciated, thank you.
You can work in the opposite way: we first filter the related Children, such that we only have children where foo is not 'ABC', and then we count the number of Children. If that is zero, we know that all these children have 'ABC' (this includes Parents that have no children).
from django.db.models import Count, Q
Parent.objects.annotate(
nabc=Count('children', filter=~Q(children__foo='ABC'))
).filter(
nabc=0
)
This will produce a query that looks like:
SELECT parent.*,
COUNT(CASE WHEN NOT (child.foo = ABC AND child.foo IS NOT NULL)
THEN child.id ELSE NULL END) AS nabc
FROM parent LEFT OUTER JOIN child ON parent.id = child.parent_id
GROUP BY parent.id
HAVING COUNT(CASE WHEN NOT (child.foo = ABC AND child.foo IS NOT NULL)
THEN child.id ELSE NULL END) = 0

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.

Simple SQL select overloads my server

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)
;

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)