Print unreferenced orphans from single table - sql

I have a table (oracle database if it's important) that looks like this:
NAME VALUE
parent.1 aa1234
parent.2 bb1234
child.3H hh1234
child.2B bb1234
child.6P oo6666
parent.3 hh1234
child.1A aa1234
child.5K ee9999
child.2C bb1234
child.1A aa1234
child.3G hh1234
The table contains parents and children in pretty random order. They referencing each other by the VALUE column. A parent has same string value as it's child. Parents usually have one or more children, so parent and it's children will have exact same value.
This is an example, but it's valid to distinguish parent from child by substring like '%parent%' or like '%child%'. Both NAME and VALUE columns are NVARCHARS2(255).
I'm trying to find orphans - children that don't have a parent by the value (in the example child.6p and child.5K). Is it possible in one query or script?

You can use not exists as follows:
SELECT T.NAME, T.VALUE
FROM YOUR_TABLE T
WHERE T.NAME LIKE '%child%'
AND NOT EXISTS (SELECT 1
FROM YOUR_TABLE T1
WHERE T1.NAME LIKE '%parent%'
AND T.VALUE = T1.VALUE);

select * from tab C
where NAME LIKE ('child%')
AND NOT EXISTS
( SELECT 1 FROM TAB P WHERE
P.NAME LIKE ('parent%')
AND C.VAL = P.VAL
)
SQL Fiddel Demo

Related

SQL query not returning rows if empty

I am new to SQL and I would like to get some insights for my problem
I am using the following query,
select id,
pid
from assoc
where id in (100422, 100414, 100421, 100419, 100423)
All these id need not have pid, some doesn't and some has pid. Currently it skips the records which doesn't have pid.
I would like a way which would show the results as below.
pid id
-----------
703 100422
313 100414
465 100421
null 100419
null 100423
Any help would be greatly appreciated. Thanks!
Oh, I think I've got the idea: you have to enumerate all the ids and corresponding pids. If there's no corresponding pid, put null (kind of outer join). If it's your case, then Oracle solution can be:
with
-- dummy: required ids
dummy as (
select 100422 as id from dual
union all select 100414 as id from dual
union all select 100421 as id from dual
union all select 100419 as id from dual
union all select 100423 as id from dual),
-- main: actual data we have
main as (
select id,
pid
from assoc
-- you may put "id in (select d.id from dummy d)"
where id in (100422, 100414, 100421, 100419, 100423))
-- we want to print out either existing main.pid or null
select main.pid as pid,
dummy.id as id
from dummy left join main on dummy.id = main.id
id is obtained from other table and assoc only has pid associated with id.
The assoc table seems to be the association table used to implement a many-to-many relationship between two entities in a relational database.
It contains entries only for the entities from one table that are in relationship with entities from the other table. It doesn't contain information about the entities that are not in a relationship and some of the results you want to get come from entities that are not in a relationship.
The solution for your problem is to RIGHT JOIN the table where the column id comes from and put the WHERE condition against the values retrieved from the original table (because it contains the rows you need). The RIGHT JOIN ensures all the matching rows from the right side table are included in the result set, even when they do not have matching rows in the left side table.
Assuming the table where the id column comes from is named table1, the query you need is:
SELECT assoc.id, assoc.pid
FROM assoc
RIGHT JOIN table1 ON assoc.id = table1.id
WHERE table1.id IN (100422, 100414, 100421, 100419, 100423)

Sqlite fetch from table

I have a table named Text_Field which consists of a column named ID,
I have another table named Content which consists of a table named value,
I want to fetch those values of ID from the Text_Field table which are present in the value column of the Content and satisfying a said condition.
I know I can construct a query like this
SELECT ID
FROM Text_Field
WHERE ID IN (
SELECT value
FROM CONTENT
WHERE USER='CURRENT_USER')
My only problem is that for some scenarios the value table might contain the ID inside a string
So the inner query might return something like
56789
12334
12348
Rtf(833405)
Now if my ID is 833405 it is present in the value column but the IN query would return false,
I tried
group_concat(value)
So that the inner query returns a single row which is a string,
56789,12334,12348,Rtf(833405)
I want to know that after group_concat can I use something as LIKE to satisfy my need
Or is there some other way I can do this?
Use exists instead, with like:
SELECT t.ID
FROM Text_Field t
WHERE EXISTS (SELECT 1
FROM CONTENT c
WHERE c.USER = 'CURRENT_USER' AND
(c.value = t.id OR
c.value LIKE '%(' || t.id || ')%'
)
);
Note:

delete all the child rows in sql table by parentid

I have a table from which I create a tree with multiple levels and parents. The table structure looks like this.
When I delete the "TitleID", I want all the children and even the grandchildren to be deleted.
What is the easiest way to do such in sql.
If I simple delete with "where ParentID=TitleID", only children with level 1 depth are deleted.
DECLARE #TitleId INT
SELECT ##TitleId = 2
;WITH results AS(
SELECT TitleId
FROM myTable
WHERE TitleId = #TitleId
UNION ALL
SELECT t.TitleId
FROM myTable t
INNER JOIN ret r ON t.ParentID = r.TitleId
)
DELETE FROM myTable WHERE TitleId IN (SELECT TitleId FROM results )
To handle tree structured data in relational database, you can add another column FullID, which contains value like 1.1.3. Then what you need is just a simple where clause WHERE FullID LIKE '1.1.%' if you want to delete node 1.1 and it's children.
The value of FullID can be generated by a stored procedure (for old data), or better by your application (for new data).

Nested query using while condition - sql

I need to do a nested query on a single table. Each row is potentially the parent or child of another row.
Is it possible to do this with a single select statement? Ive started using this statement but it only goes down one level.
select * from myTable where parent_id in
(select id from myTable where name = 'manager' )
This select however will only go down one level. If a row has multiple children they will be ignored. (In the table each row has an Id field , if a row has a parent then the parents Id value will be in the child's parent_Id field. )
If i could include a while loop in the SQL which would always check to see if the returned Id was a parent or not and if it was check and see if any other row was its child by checking the other rows parent_Id. However i m concerned this would take alot of cycles to eventually find all parent child relationships. Any suggestions? Thanks
using Oracle db
I think you are looking for a hierarchical query like this:
select * from mytable
connect by prior id = parent_id
start with name = 'Manager';
(A "nested table" is something else entirely.)

how to query with child relations to same table and order this correctly

Take this table:
id name sub_id
---------------------------
1 A (null)
2 B (null)
3 A2 1
4 A3 1
The sub_id column is a relation to his own table, to column ID.
subid --- 0:1 --- id
Now I have the problem to make a correctly SELECT query to show that the child rows (which sub_id is not null) directly selected under his parent row. So this must be a correctly order:
1 A (null)
3 A2 1
4 A3 1
2 B (null)
A normal SELECT order the id. But how or which keyword help me to order this correctly?
JOIN isn't possible I think because I want to get all the rows separated. Because the rows will be displayed on a Gridview (ASP.Net) with EntityDataSource but the child rows must be displayed directly under his parent.
Thank you.
Look at Managing Hierarchical Data in MySQL.
Since recursion is an expensive operation because basicly you're firing multiple queries to your database you could consider using the Nested Set Model. In short you're assigning numbers to ranges in your table. It's a long article but it worth reading it. I've used it during my internship as a solution not to have 1000+ queries, But bring it down to 1 query.
Your handling 'overhead' now lies at the point of updating the table by adding, updating or deleting records. Since you then have to update all the records with a bigger 'right-value'. But when you're retrieving the data, it all goes with 1 query :)
select * from table1 order by name, sub_id will in this case return your desired result but only because the parents names and the child name are similar. If you're using SQL 2005 a recursive CTE will work:
WITH recurse (id, Name, childID, Depth)
AS
(
SELECT id, Name, ISNULL(childID, id) as id, 0 AS Depth
FROM table1 where childid is null
UNION ALL
SELECT table1.id, table1.Name, table1.childID, recurse.Depth + 1 AS Depth FROM table1
JOIN recurse ON table1.childid = recurse.id
)
SELECT * FROM recurse order by childid, depth
SELECT
*
FROM
table
ORDER BY
COALESCE(id,sub_id), id
btw, this will work only for one level.. any thing more than that requires recursive/cte function