Get rows of parents without children - sql

I have this table:
UID
CHILD_UID
a
{}
b
{}
c
{a}
UID is a VARCHAR and CHILD_UID is a VARCHAR[]. I need a query that returns b,c. I mean a list of parents without children, checking that the uid is not in any of the child_uid rows.
a is not a parent, is a child of c.
b is a parent.
c is a parent.
I have tried this but with no results:
SELECT *
FROM table
WHERE NOT uid = ANY(SELECT child_uid FROM table);
In words, get the items that its uid is not in the child_uid column.

child_uid is an array, so it should be converted to a list of childs (using UNNEST)
SELECT * FROM table
WHERE NOT uid = ANY(SELECT unnest(child_uid) FROM table);

Related

Recursive SQL query with Ecto.Query

I have a categories table with the following columns:
id
name
parent_id (nullable)
And a books table which has a category_id column inside of it.
I want a function that takes a list of category ids (category_ids) and returns a query that gets books which belong to one of the given categories or their children (recursive).
I've already written a query that returns all of a given category's children. I could use that to fetch all of the subcategories of category_ids categories and use the new list. But it would send several queries to the database and I want to do it in one query. Here's the query:
with recursive cat_tree as (
select id,
name,
parent_id
from categories
where id = $1
union all
select child.id,
child.name,
child.parent_id
from categories as child
join cat_tree as parent on parent.id = child.parent_id
)
select *
from cat_tree;
EDITED
#raw_sql """
select id,
name,
parent_id
from categories
where id in (?)
union all
select child.id,
child.name,
child.parent_id
from categories as child
join cat_tree as parent on parent.id = child.parent_id
"""
def category_search_query(query, []), do: query
def category_search_query(query, category_ids) do
query
|> recursive_ctes(true)
|> with_cte("cat_tree", as: fragment(#raw_sql, ^category_ids))
|> join(:inner, [b], c in "cat_tree", on: c.id == b.category_id)
end
But when I pass [12, 13] (for example) to the function, it gives me the following error:
(DBConnection.EncodeError) Postgrex expected an integer in -9223372036854775808..9223372036854775807, got '\f\r'. Please make sure the value you are passing matches the definition in your table or in your query or convert the value accordingly.
But when I pass just an integer (and not a list), it works correctly.
I would make a procedure to get list of categories as parameter (can be an array) and change your query to this :
create function funcName (categoryIds int[])
returns table ( bookid int ,categoryid int , ...<deffine book columns>)
as
$$
with recursive cat_tree as (
select
id,name,parent_id
from
categories
where id in (select unnest(categoryIds))
union all
select
child.id,child.name,child.parent_id
from
categories as child
join cat_tree as parent on parent.id = child.parent_id
)
select
b.*
from
cat_tree c
join books on c.id = b.categoryid
$$ Language sql;

Recursive query for postgresSQL parent/child

Asking for a little help on a recursive query syntax, and of course result.
As you will see I have a table with category parent and child ( a parent can have infinite children). Querying the category dictionary (linked to a real category)
And I want to return only the last child of every category tree
Updated my code, and information
EDIT
WITH RECURSIVE cat(id) AS (
SELECT
*
FROM
category_dictionary
LEFT JOIN category_dictionary.category ON category.id
WHERE
category.parent is NOT NULL
UNION
SELECT
*
FROM
cat
LEFT JOIN cat.category ON category.id
WHERE
category.parent is NOT NULL
)
SELECT
*
FROM
cat
Table information:
Category_dictionary is a table the join category on parameter category
Category is the main table with Parent entry.
Sample data:
category_dictionary entry:
ID : name (Men) : category_id
category entries:
category_id : name : parent (null or category_id)
As a result I want all the last child of each category entries, I mean the category that doesn't have child.
A recursive query is not needed to find the deepest children. Instead, one would look at entries that are not a parent (so no other child exists). Such entries ID is not included in the parent column.
You can then join this categories to other tables
SELECT *
FROM category cat
JOIN category_dictionary cat_dic ON cat.id = cat_dic.id
WHERE NOT EXISTS
(SELECT 1 FROM category cat2
WHERE cat2.parent = cat.id);

Order parent records by child record count

I have a table that has a foreign key that points to the id column same table.
pages
=====
id integer primary key autoincrement
name text
parent integer
FOREIGN KEY(parent) REFERENCES pages(id)
When I do a select query is it possible to sort the results by the number of children records ?
You could join it with an aggregate query on the child records and sort according to that:
SELECT p.*
FROM pages p
JOIN (SELECT parent, COUNT(*) AS cnt
FROM pages
GROUP BY parent) c ON p.id = c.parent
ORDER BY c.cnt
You could compute the count of children with a correlated subquery and sort according to that:
SELECT id, name
FROM pages
ORDER BY (SELECT count(*)
FROM pages AS p2
WHERE p2.parent = pages.id);

Updating order of child record

I've got two tables:
Parent
| id |
Child
| id | owner | ordernr |
owner is a foreign key referencing Parent's id. There is a uniqueness constraint on (owner, ordernr)
Now, there are some gaps in the orders and I'm trying to fix them as follows:
CREATE OR REPLACE VIEW myView AS
(SELECT childid, ordernr, n
FROM (SELECT child.id as childid, ordernr, ROW_NUMBER() OVER ( PARTITION BY parent.id ORDER BY ordernr) AS n
FROM Parent, Child WHERE owner = parent.id)
WHERE ordernr <> n)
UPDATE
(SELECT c.ordernr, n
FROM Child c, myView WHERE childid = c.id) t
SET t.ordernr = t.n
But I get: ORA-01779: cannot modify a column which maps to a non key-preserved table
ORA-01779: cannot modify a column which maps to a non key-preserved table
This error occurs when you try to INSERT or UPDATE columns in a join view which map to a non-key-preserved table.
You could use a MERGE.
For example,
MERGE INTO child c
USING (SELECT n
FROM myview) t
ON (t.childid = c.id)
WHEN matched THEN
UPDATE SET c.ordernr = t.n
/

Query that selects the sum of all records that are referenced in another table

I have two tables, parent(id, name, child_id) and child(id, name, number) - not all parents may have childs and not all childs may have parents. I need a query that selects the sum of all records in child table and also selects the sum of only those records that have a parent and those that dont - that is determined by parent tables child_id column. How can this be done?
select
sum(c.number) AS sum AS a,
sum(all_child_records_that_have_a_parent) AS b,
sum(all_child_records_that_do not have a parent) AS c /*do not use a-b if possible*/
from
child c
The "all_child_records_that_have_a_parent" is the one i cant figure out :)
all_child_records_that_do not have a parent:
SELECT *
FROM child
WHERE id NOT IN (SELECT child_id FROM parent)
You can select distinct child ids from the parent table and outer join these to your child table. Then check for NULL.
select
sum(c.number) AS sum_all_c,
sum(case when x.child_id is not null then c.number end) AS sum_c_with_parent,
sum(case when x.child_id is null then c.number end) AS sum_c_without_parent
from child c
left outer join (select distinct child_id from parent) x on x.child_id = c.id;