Reputation: 1241
I have a simple table of category names that relates to itself with a category_parent = id. I need to select records that have no children.
From other answers I have cobbled together this statement:
SELECT cat.category_name AS 'Child Name', cat.id AS 'Child ID',
cat.category_parent AS 'Childs Parent', cat_par.category_name AS 'Parent Name',
cat_par.id AS 'Parent ID'
FROM category AS cat
LEFT JOIN category AS cat_par ON cat.category_parent = cat_par.id
WHERE cat_par.id IS NULL;
This will successfully select records that have no PARENT. I tried changing the last clause to WHERE cat.category_parent IS NULL
but that yielded an empty yet.
I have also tried this statement based on another answer:
SELECT cat.category_name AS 'Child Name', cat.id AS 'Child ID',
cat.category_parent AS 'Childs Parent' cat_par.category_name AS 'Parent Name',
cat_par.id AS 'Parent ID'
FROM category AS cat
WHERE NOT EXISTS
(SELECT id FROM category AS cat_par WHERE cat.category_parent = cat_par.id);
Which returns the error No value given for one or more required parameters.
Upvotes: 2
Views: 2470
Reputation: 8135
-- get parents categories without children
SELECT id, category_name
FROM category
WHERE id NOT IN
(
SELECT c.id
FROM category c, category p
WHERE c.parent_id = p.id
)
AND id NOT IN
(
SELECT p.id
FROM category c, category p
WHERE c.parent_id = p.id
)
EXPLANATION: The logic here is very simple. With the query below (used inside both NOT IN) we get parent categories and its children:
SELECT c.id, p.id
FROM category c, category p
WHERE c.parent_id = p.id
As NOT IN only allows comparison with one column, we use it twice:
Once to get the inverse of the parents, another to get the inverse of the children. What's left are "parents" without children.
Upvotes: 0
Reputation: 49049
If you just need the id and the category name of records with no children this also works:
SELECT
category.id,
category.category_name
FROM
category LEFT JOIN category AS category_1
ON category.id = category_1.category_parent
WHERE
category_1.category_parent IS NULL
and i think this query looks nice. But if you also need the parent's name, you can use this:
SELECT
category.id,
category.category_name,
category_1.category_name
FROM
(category LEFT JOIN category AS category_2
ON category.id = category_2.category_parent)
LEFT JOIN category AS category_1
ON category.category_parent = category_1.ID
WHERE
category_2.category_parent Is Null;
and yes, it gets a little more complicated: it's just a nice sql exercise but i would prefer to use the Exists version instead.
Upvotes: 1
Reputation: 3400
The problem with the second query is that you are trying to include cat_par.category_name
in your results set, even though it's not in your FROM
clause. You cannot return a column from the tables in your EXISTS subquery.
YOu want the following:
SELECT
cat.category_name AS 'Child Name',
cat.id AS 'Child ID',
cat.category_parent AS 'Childs Parent',
cat_par.category_name AS 'Parent Name',
cat_par.id AS 'Parent ID'
FROM
category AS cat
LEFT JOIN category AS cat_par ON cat.category_parent = cat_par.id
WHERE
NOT EXISTS
(SELECT
NULL
FROM
category AS cat_childless
WHERE cat.id = cat_childless.category_parent);
Upvotes: 0
Reputation: 10976
Select p.id, p.category_name
From category As p
Where Not Exists (
Select 'x'
From Category c
Where c.category_parent = p.id
)
Upvotes: 3
Reputation: 12804
I think I understand the relation enough. How about this?
SELECT cat.*
FROM category cat
WHERE cat.id not in (
SELECT distinct category_parent FROM category
);
Upvotes: 2