tags:

views:

101

answers:

5

Let's say I have the following table:

ID | parentID | MoreStuff
1  | -1       |  ...
2  |  1       |  ...
3  |  1       |  ...
4  |  2       |  ...
5  |  1       |  ...

How can I generate an SQL SELECT statement to find out if a specific row has children? In other words, I want to know if ID 1 has children, which in this case it has 3.

I'm not sure how to create the SQL statement:

SELECT ID, hasChildren FROM myTable;

What would be replaced for hasChildren in the above SQL SELECT statement?

+7  A: 

Join the table on itself to find if it has children:

SELECT 
    parent.id as ID
,   case when count(child.id) > 0 then 1 else 0 end as hasChildren 
FROM       myTable parent
LEFT JOIN  myTable child
ON         child.parentID = parent.ID
GROUP BY   parent.id
Andomar
+1 Self joins are there for these queries only...
noob.spt
+1  A: 

If you know already know the parent ID, then the query is simple -- just select the number of rows with that parent ID.

SELECT count(*) FROM myTable where parentID = 1;
Kaleb Brasee
+1 for being the only query that actually answers if "a specific row has children"
Jørn Schou-Rode
Your query is to find if a specific row has children. But how do I get a list of all rows with an extra column created dynamically called hasChildren?
Stephane Grenier
To get a list of all rows with an extra column see Alex or Andomar's answers. However, the question explicitly asks for a query "to find out if *a specific row* has children", and this is what Kaleb's answer does.
Jørn Schou-Rode
+7  A: 

No group version:

SELECT MyTable.Id, CASE WHEN EXISTS 
    (SELECT TOP 1 1  --you can actually select anything you want here
     FROM MyTable MyTableCheck 
     WHERE MyTableCheck.ParentId = MyTable.Id
    ) THEN 1 ELSE 0 END AS HasRows
FROM MyTable
Alex Bagnolini
+1 for exists, beat me to it! :) Op: This is this most efficient on here so far, as exists returns as soon as it knows if a child rows exists, meaning it doesn't have to count all of the children. If all you care about is the existence of children this is the way to do it.
Donnie
Minor point, but you could have written that a little more elegantly as WHEN EXISTS (SELECT NULL FROM MyTable...)
Keith Williams
The Top 1 is not needed, see my above comment. Exists stops at the first match anyways. Selecting null, 1, or * has no real effect, all exists cares about is that something came back. The optimizer won't actually fetch the data.
Donnie
Thank you Donnie, edited the answer.
Alex Bagnolini
Subquery?? Bad idea :/
noob.spt
+2  A: 

There are very valid answers to your question which will work. However, I would consider the performance of such a query if your dataset is very large.

If your going to use a Group By or Sub Query to get the data, then make sure both the ID and Parent columns have separate indexes.

To get even better performance, you should add a column called "haschildren" which could be a "bit" datatype. This column should then be updated from your application code when items are Inserted or Deleted. This would allow you to run the much quicker query:

SELECT * FROM table WHERE haschildren IS NOT NULL
GateKiller
+1 for caching idea
Marc W
-1 for adding a column. First, you never store anything that can be easily calculated. Second, you add additional overhead; that additional field has to be maintained. It has to be updated when children are added or removed, it adds unnecessary storage requirements to transactions, logs, and backups, and defeats the whole purpose of normalizing data.
Ken White
@GateKiller: Forgot to mention. I gave you a -1, but didn't actually vote your answer down because of the mention of separate indexes, which might actually be valid if the data is large enough.
Ken White
+1  A: 

The solutions above are fine, but you shouldn't add column like 'haschildren' unless you really have a performance problem (see the post by GateKiller). Such a column denormalizes the database, i.e. the same piece of information will be stored in 2 places, which makes it more likely for your data to become inconsistent. You will have to maintain this column whenever you insert a new child, delete an existing one or update the parent of a child.

FelixM
Since he's asking for a query to indicate if a child exists or not, this is not denormalizing anything. If he were to update the base table, then it would, but I don't get the feeling that that is what he means.
Donnie
-1 Agree with Donnie
noob.spt
+1 - these are valid concerns, whether it's technically denormalisation or not.
gkrogers
I was referring to the post by GateKiller, and what he is suggests is denormailization.
FelixM
@FelixM: Then your answer should have been a comment to GateKiller's answer, and not a separate answer in itself. That's the way SO works - comments are comments to answers and answers are answers to the original question. Yours answered nothing related to the original question.
Ken White