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.)
Related
I want to query in database for some ledgername (like child),ledgergroupname (like parent,it's parent of ledgername) and all ascending parent's of ledgergroupname (or ledgername).Data i am searching from ACC_LEDGER table where ledgername and it's immediate parent termed as ledgergroupname are saved.Ascending parent of ledgergroupname are saved in ACC_LEDGERGROUP table.
sql--
select
pp.Ledgercode,
pp.Ledgername,
pp.Ledgergroupcode,
pp.Ledgergroupname,
(select Acc_Ledgergroup.Parentname from Acc_Ledgergroup where Acc_Ledgergroup.Ledgergrpcode=pp.Ledgergroupcode) as PARENTNAME
from
(select
LED.LEDGERCODE,
Led.Ledgername,
Led.Ledgergroupcode,
Led.Ledgergroupname
from ACC_LEDGER LED where Led.Ledgercode IN ('01003024007','01003024019'))pp
it gives me result--
what i want is --
so for every ledger i want to show parent upto root (it's level is different for different ledger means for some ledger it has 7 upper parent's to reach "root" parent).
I am trying to query something like this(it's for your understanding)--
select
pp.Ledgercode,
pp.Ledgername,
pp.Ledgergroupcode,
pp.Ledgergroupname,
(select Acc_Ledgergroup.Parentname from Acc_Ledgergroup where Acc_Ledgergroup.Ledgergrpcode=pp.Ledgergroupcode) as PARENTNAME
while(parentname != root)
{
select parent name from Ledger group
}
from the_table
So column selection from table or join of table is not fixed,it's depend on how much level of parent i have,how can i do that in oracle sql?
Generally this kind of problems can be solved with hierarchical queries (using CONNECT BY), however in Oracle a query cannot have a variable number of columns. As a workaround you can use sys_connect_by_path to concatenate all levels using some separator:
select sys_connect_by_path(Ledgergroupname, '/')
from Acc_Ledgergroup
where Ledgergroupname = 'root'
start with Ledgercode in ('01003024007', '01003024019')
connect by prior Ledgercode = Ledgergroupcode
Oracle documentations state that FOR UPDATE clause is not supported in subqueries.
I have two tables, Parent and Child. In the code, random records from the parent table are selected and the corresponding child records are updated. For example, the table structure might look like:
parent(obj_id string, status integer,....)
child(obj_id string, status integer, parent_id string,....)
and the query might look like:
UPDATE child
set status =1
WHERE parent_id IN (SELECT obj_id
FROM parent where status = 1
and rownum < 10 FOR UPDATE SKIP LOCKED)
This query is executed from two different processes in two different machines.
Can you please explain how to extend the FOR UPDATE locking mechanism to work in subquery too?
You could use PL/SQL and run two separate queries:
CREATE TYPE numbers AS TABLE OF NUMBER(18);
/
DECLARE
n numbers;
BEGIN
SELECT obj_id
BULK COLLECT INTO n
FROM parent WHERE status = 1 AND rownum < 10
FOR UPDATE SKIP LOCKED;
UPDATE child
SET status = 1
WHERE parent_id IN (SELECT * FROM TABLE(n));
END;
/
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).
I have a table in SQL Server that contains the following columns :
Id Name ParentId LevelOrder
8 vehicle 0 0/8/
9 car 8 0/8/9/
10 bike 8 0/8/10/
11 House 0 0/11/
...
This creates a tree.
Say that I have the LevelOrder 0/8/, this should return only the car and bike rows, but how do I handle this in SQL Server?
I have tried :
Select * FROM MyTable WHERE LevelOrder >= '0/8/'
but that does not work.
The underscore character will guarantee at least one character comes after '0/8/', so you don't get a match on the "vehicle" row.
SELECT *
FROM MyTable
WHERE LevelOrder LIKE '0/8/_%'
This code allows you to select values that start with 0/8/
Select * FROM MyTable WHERE LevelOrder like '0/8/%'
Okay -
While #Joe's answer is the simplest and easiest to implement (and possibly better performing than what I'm about to propose...), there are some issues with update anomalies.
Specifically:
You already have a parentId column. You need to synchronize both this and the levelOrder column, or risk inconsistent data. (I believe this also violates 1NF, although my understanding of the exact definition is a little sketchy...)
levelOrder contains the entire heirarchy. If any one parent is moved, all children rows must have levelOrder modified to reflect this (potentially very messy).
In light of this, here's what I recommend:
Drop the levelOrder column, as its existence will (generally) cause problems.
Use a recursive CTE and the parentId column to build the heirarchy dynamically. Either leave the column where it is, or move it to a dedicated relationship table. Moving one parent then requires only one cell to be updated, and cannot result in any (data, not semantic) anomalies. The CTE should look similar to this form (will need to be adjusted for purpose):
WITH heir_parent (parentId, id) as (SELECT parentId, id
FROM table
WHERE id =
UNION ALL
SELECT b.parentId, b.id
FROM heir_parent as a
JOIN table as b
ON b.parentId = a.id)
At the moment, the CTE returns a list of all children of the given id, with their id and their immediate parent. It can be adjusted to return a number of other things as well - although I recommend that the CTE be used only to generate the relationship, and join externally to get the remaining data.
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