SELECT When child record doesn't exist - sql

I have two tables parent and children. The parent.mopid and children.mopid is the connection between the two tables. How would I write a SELECT that would end result show me just the parent records where there are no children records?

Use the NOT IN function:
SELECT * from parent
where parent.mopid NOT IN (SELECT mopid from children)
This will return all rows from the parent table that do not have a corresponding mopid in the childrens table.

If you have a lot of rows, a LEFT JOIN is often quicker than a NOT IN. But not always - it depends on the data so please try this answer and the one from #aktrazer and see which works best for you.
SELECT parent.*
FROM parent
LEFT JOIN children ON parent.mopid = children.mopid
WHERE children.mopid IS NULL
If there isn't a children row for the mopid, parent.mopid will have a value but child.mopid will be null.

SELECT * from parent p where NOT EXISTS
( select mopid from children c where p.mopid = c.mopid)
This should take care of the nulls as well
This link will explain you the difference between NOT IN and NOT EXISTS
NOT IN vs NOT EXISTS

Related

SQL loop. I want to iterate through a loop containing SELECT results

From a table with column structure (parent, child) I need:
For a particular parent I need all children.
From the result of (1) I need the children's children too.
For example for parent=1:
parent|child parent|child parent|child
1 a a d b f
b e g
This gets you the information you say you want, I think. Two columns: child and grandchild (if any, or else NULL). Not sure if it's the schema you'd like, since you don't specify. You may add JOINs to increase the recursion depth.
select t1.child, t2.child
from T as t1 left join T as t2
on t1.child = t2.parent
where t1.parent = 1
This works on SQLite; I think it's quite standard. Regarding schema if this one doesn't serve you, hopefully it may give you ideas; or else please specify more.

In SQL, how can I select all parents that have children?

Let's say I have two related tables parents and children with a one-to-many relationship (one parent to many children). Normally when I need to process the information on these tables together, I do a query such as the following (usually with a WHERE clause added in):
SELECT * FROM parents INNER JOIN children ON (parents.id = children.parent_id);
How can I select all parents that have at least one child without wasting time joining all of the children to their parents?
I was thinking of using some sort of OUTER JOIN but I am not sure exactly what to do with it.
(Note that I am asking this question generally, so don't give me an answer that is tied to a specific RDBMS implementation unless there is no general solution.)
As I put earlier in comments:
Solution with LEFT JOIN and GROUP BY:
SELECT p.parents.id FROM parents p
LEFT JOIN children c ON (p.parents.id = c.children.parent_id)
WHERE children.parent_id IS NOT NULL
GROUP BY p.parents_id
The same with DISTINCT:
SELECT DISTINCT p.parents.id FROM parents p
LEFT JOIN children c ON (p.parents.id = c.children.parent_id)
WHERE children.parent_id IS NOT NULL
It should work in most SQL dialects, though some require as when assigning table aliases.
The above is not tested. Hopefully I made no typos.
I think that the simplest solution that avoids a JOIN would be:
SELECT * FROM parents WHERE id IN (SELECT parent_id FROM children);
try this
select parent_id,(select count(1) from children where parent_id = x.parent_id)
from parent x where
(select count(1) from children where parent_id = x.parent_id) > 0

How to get rid of double column table in return data from select query

I have two tables:
Tasks[id_task,task_title,author,id_project]
SubTasks[id_subtask,subtask_title,author,id_task]
And I use this query to return data:
Select PS.task_title as subtask_category, PS.id_task, PS.id_project, P.*
From SubTasks P inner join Tasks PS
on P.id_task=PS.id_task
where PS.id_project = 1
order by PS.id_task desc
The problem is that the result table contains duplicate id_task column, how can I resolve this?
If you know that the SubTasks table is always going to have id_task (which you do because of the join) remove PS.id_task from the select so it will only be grabbed by the P.*
Change your SELECT clause to be SELECT PS.id_task, PS.task_title, PS.author, PS.id_project, P.id_subtask, P.subtask_title, P.author and leave off the P.id_task. Your P.* is telling the query to return all columns in the SubTasks table, when you've already told the query earlier to return PS.id_task in the Tasks table.

SQLite3 and "cascade" SELECTion

I have a parent table and a child table related to the parent table by some REFERENCE.
Suppose I exec a SELECT statement on the child and that it returns the at least one result. Can I arrange for my search to automatically yield all the content of all related parents with this child too?
Or must I always take the reference from the child and put this in a second SELECT statement and exec this myself?
You can use subqueries:
SELECT *
FROM Parent
WHERE Parent.Id IN (SELECT ParentId
FROM Child
WHERE Whatever_was_your_original_query)
Or a good old join:
SELECT Parent.*
FROM Parent INNER JOIN Child ON Parent.Id = Child.ParentId
WHERE Whatever_you_want_to_query
This is the very basic purpose of SQL. You will JOIN the two tables together to create one set of result rows with some or all columns from BOTH tables included.
For more info, see this page.

SQL Query to retrieve data while excluding a set of rows

I have basically four tables (SQL Server):
Objects:
id
ObjectName
Components
id
ComponentName
ObjectsDetails:
ObjectID
ComponentID
ExclusionTable
id
ComponentID
Basically, these tables describe Objects and what Objects are made of (what components)
For example, Object "A" may be made out of component "A" and component "B".
In this case, the tables would be populated this way:
Objects:
id ObjectName
1 A
Components:
id ComponentName
1 A
2 B
ObjectDetails:
ObjectID ComponentID
1 1
1 2
Now, "ExclusionTable" may have a list of components that are to be excluded from a search (therefore, excluding entire objects if the object is made out of at least one of those components).
For example, I would like to ask:
"Give me all the Objects that are not made out of components A and B".
Therefore, my question is:
Is there a way to write a query for that ? No views, no stored procedures please.. my SQL engine does not support that.
I tried something like:
SELECT DISTINCT ObjectName FROM Objects INNER JOIN ObjectsDetails ON Objects.id =
ObjectDetails.ObjectID WHERE ObjectsDetails.ComponentID NOT IN (1,2)
in case ExclusionTable tells us that Components A and B needs to be excluded.
Of course, that doesn't work...
I tried a few variations using WHERE NOT EXISTS (SELECT * FROM ExclusionTable) but I am not proficient enough in SQL to understand how to get it to work using one query only (if it is even possible).
Thanks!
You should avoid doing queries with [not] in (select ...)
SELECT DISTINCT ObjectName
FROM Objects
INNER JOIN ObjectsDetails ON Objects.id = ObjectDetails.ObjectID
LEFT JOIN ExclusionTable on ExclusionTable.ComponentId = ObjectsDetails.ComponentID
where ExclusionTable.ComponentId is null;
This will retrieve only rows for which the ComponentID is not in ExclusionTable.
Update:
SELECT ObjectName
FROM Objects
INNER JOIN ObjectsDetails ON Objects.id = ObjectDetails.ObjectID
LEFT JOIN ExclusionTable on ExclusionTable.ComponentId = ObjectsDetails.ComponentID
group by ObjectName
having count(distinct ObjectsDetails.ComponentID) = sum(case when ExclusionTable.id is null then 1 else 0 end)
New approach, I think the only other way I could do it is basically to compare the number of components per object with the number of components in the object not included on the list. When these number are equal, no component is on the excluded list and we can show the object.
I'm sorry I can't make a test right now, please use EXPLAIN select ... to compare the queries, if they work.
Basically, if you need to get all objects not made from A or B, you need to get all objects EXCEPT those made from A or B.
SELECT DISTINCT Id, ObjectName
FROM Objects
WHERE Id NOT IN (
SELECT DISTINCT ObjectDetails.ObjectID
FROM ObjectDetails
INNER JOIN Components ON ObjectDetails.ComponentID = Components.Id
WHERE Components.ComponentName = 'A' OR Components.ComponentName = 'B'
)
Would that be what you're looking for?
EDIT: Of course, you can omit the join if you already have the component ids - then just put those in the where clause to filter them out.
select id, objectname
from Objects
left outer join
( select objectid from ObjectsDetails od inner join Exclusiontable et
on od.ComponentID= et.ComponentID) excludedid
on Objects.ID = excludedid.ObjectID and excludedid.ObjectID is null