Query to fetch the SEC_CODE of parent its child and all grand children. Children are connected through PREV_SEC value.
According to above image,
1. Here if sec_code is 1 then the query should return 1, 3, 4 7, 8
2. if sec_code is 2 then query return 2.
3. if sec_code is 4 then query return 4,7,8
You can use recursive CTE to get the desired output like following query.
WITH CTE2 (SEC_CODE,SEC_NAME,PREV_SEC)
AS (
SELECT SEC_CODE,SEC_NAME,PREV_SEC
FROM YOURTABLE
WHERE SEC_CODE = 1
UNION ALL
SELECT C1.SEC_CODE,C1.SEC_NAME,C1.PREV_SEC
FROM YOURTABLE C1
INNER JOIN CTE2 C2 ON C1.PREV_SEC = C2.SEC_CODE
)
SELECT *
FROM CTE2
Note: Replace YOURTABLE with the actual table name in above query.
If you strictly need an Oracle specific solution, You may try below query having CONNECT BY clause -
SELECT SEC_CODE,SEC_NAME,PREV_SEC
FROM YOURTABLE
START WITH SEC_CODE = 1
CONNECT BY PRIOR PREV_SEC = SEC_CODE;
Related
I have a big query that brings me a lot of rows, and based on each row I use this another query as a subselect.
This subselect brings me the following result rest on Oracle:
SELECT oc3.ID_ORGAO_INTELIGENCIA,
oc3.ord,
lag(oc3.ID_ORGAO_INTELIGENCIA, 1, NULL) OVER (
ORDER BY oc3.ord) ultimo
FROM
( SELECT DISTINCT oc2.*
FROM
( SELECT oc1.ID_ORGAO_INTELIGENCIA,
oc1.ID_ORGAO_INTELIGENCIA_PAI,
oc1.SG_ORGAO_INTELIGENCIA,
rownum AS ord
FROM TB_ORGAO_INTERNO oc1
WHERE oc1.DH_EXCLUSAO IS NULL START WITH oc1.ID_ORGAO_INTELIGENCIA =
-- this is a value that come from an outer select
-- If I put the value directly, like: S.ID_ORGAO_INTELIGENCIA, it does not work... I dont know why...
(SELECT sa.ID_ORGAO_INTELIGENCIA
FROM TB_SOLICITACAO sa
WHERE sa.ID_SOLICITACAO = 1077)-- s.ID_SOLICITACAO)
CONNECT BY
PRIOR oc1.ID_ORGAO_INTELIGENCIA_PAI = oc1.ID_ORGAO_INTELIGENCIA) oc2
INNER JOIN TB_PERMISSAO pe2_ ON pe2_.ID_ORGAO_INTELIGENCIA = oc2.ID_ORGAO_INTELIGENCIA
INNER JOIN TB_USUARIO u_ ON u_.ID_USUARIO = pe2_.ID_USUARIO
WHERE pe2_.ID_STATUS_PERMISSAO = 7
AND pe2_.ID_ATRIBUICAO IN :atribuicoes
ORDER BY oc2.ord) oc3
The result:
That important value from each row is the S.ID_SOLICITACAO, because based on that value that the subquery will be started.
I need to be able to filter the results by oc3.ID_ORGAO_INTELIGENCIA where it brings me all the rows before that number.
So, If I filter by 430, only the row with 311 will return.
If I filter by 329, it will bring me the: 311 and 430.
Is there a way to achieve this result?
One option might be to use your current query as a CTE, and then filter data it returns. Something like this:
with ycq as
-- your current query
(select ...
from ...
)
select *
from ycq a
where a.ord < (select b.ord
from ycq b
where b.id_orgao_inteligencia = :par_id_orgao_inteligencia
);
I have a submissions table which is essentially a single linked list. Given the id of a given row I want to return the entire list that particular row is a part of (and it be in the proper order). For example in the table below if had id 2 I would want to get back rows 1,2,3,4 in that order.
(4,3) -> (3,2) -> (2,1) -> (1,null)
I expect 1,2,3,4 here because 4 is essentially the head of the list that 2 belongs to and I want to traverse all the through the list.
http://sqlfiddle.com/#!15/c352e/1
Is there a way to do this using postgresql's RECURSIVE CTE? So far I have the following but this will only give me the parents and not the descendants
WITH RECURSIVE "sequence" AS (
SELECT * FROM submissions WHERE "submissions"."id" = 2
UNION ALL SELECT "recursive".* FROM "submissions" "recursive"
INNER JOIN "sequence" ON "recursive"."id" = "sequence"."link_id"
)
SELECT "sequence"."id" FROM "sequence"
This approach uses what you have already come up with.
It adds another block to calculate the rest of the list and then combines both doing a custom reverse ordering.
WITH RECURSIVE pathtobottom AS (
-- Get the path from element to bottom list following next element id that matches current link_id
SELECT 1 i, -- add fake order column to reverse retrieved records
* FROM submissions WHERE submissions.id = 2
UNION ALL
SELECT pathtobottom.i + 1 i, -- add fake order column to reverse retrieved records
recursive.* FROM submissions recursive
INNER JOIN pathtobottom ON recursive.id = pathtobottom.link_id
)
, pathtotop AS (
-- Get the path from element to top list following previous element link_id that matches current id
SELECT 1 i, -- add fake order column to reverse retrieved records
* FROM submissions WHERE submissions.id = 2
UNION ALL
SELECT pathtotop.i + 1 i, -- add fake order column to reverse retrieved records
recursive2.* FROM submissions recursive2
INNER JOIN pathtotop ON recursive2.link_id = pathtotop.id
), pathtotoprev as (
-- Reverse path to top using fake 'i' column
SELECT pathtotop.id FROM pathtotop order by i desc
), pathtobottomrev as (
-- Reverse path to bottom using fake 'i' column
SELECT pathtobottom.id FROM pathtobottom order by i desc
)
-- Elements ordered from bottom to top
SELECT pathtobottomrev.id FROM pathtobottomrev where id != 2 -- remove element to avoid duplicate
UNION ALL
SELECT pathtotop.id FROM pathtotop;
/*
-- Elements ordered from top to bottom
SELECT pathtotoprev.id FROM pathtotoprev
UNION ALL
SELECT pathtobottom.id FROM pathtobottom where id != 2; -- remove element to avoid duplicate
*/
In was yet another quest for my brain. Thanks.
with recursive r as (
select *, array[id] as lst from submissions s where id = 6
union all
select s.*, r.lst || s.id
from
submissions s inner join
r on (s.link_id=r.id or s.id=r.link_id)
where (not array[s.id] <# r.lst)
)
select * from r;
My table looks like this:
Value Previous Next
37 NULL 42
42 37 3
3 42 79
79 3 NULL
Except, that the table is all out of order. (There are no duplicates, so that is not an issue.) I was wondering if there was any way to make a query that would order the output, basically saying "Next row 'value' = this row 'next'" as it's shown above ?
I have no control over the database and how this data is stored. I am just trying to retrieve it and organize it. SQL Server I believe 2008.
I realize that this wouldn't be difficult to reorganize afterwards, but I was just curious if I could write a query that just did that out of the box so I wouldn't have to worry about it.
This should do what you need:
WITH CTE AS (
SELECT YourTable.*, 0 Depth
FROM YourTable
WHERE Previous IS NULL
UNION ALL
SELECT YourTable.*, Depth + 1
FROM YourTable JOIN CTE
ON YourTable.Value = CTE.Next
)
SELECT * FROM CTE
ORDER BY Depth;
[SQL Fiddle] (Referential integrity and indexes omitted for brevity.)
We use a recursive common table expression (CTE) to travel from the head of the list (WHERE Previous IS NULL) to the trailing nodes (ON YourTable.Value = CTE.Next) and at the same time memorize the depth of the recursion that was needed to reach the current node (in Depth).
In the end, we simply sort by the depth of recursion that was needed to reach each of the nodes (ORDER BY Depth).
Use a recursive query, with the one i list here you can have multiple paths along your linked list:
with cte (Value, Previous, Next, Level)
as
(
select Value, Previous, Next, 0 as Level
from data
where Previous is null
union all
select d.Value, d.Previous, d.Next, Level + 1
from data d
inner join cte c on d.Previous = c.Value
)
select * from cte
fiddle here
If you are using Oracle, try Starts with- connect by
select ... start with initial-condition connect by
nocycle recursive-condition;
EDIT: For SQL-Server, use WITH syntax as below:
WITH rec(value, previous, next) AS
(SELECT value, previous, next
FROM table1
WHERE previous is null
UNION ALL
SELECT nextRec.value, nextRec.previous, nextRec.next
FROM table1 as nextRec, rec
WHERE rec.next = nextRec.value)
SELECT value, previous, next FROM rec;
One way to do this is with a join:
select t.*
from t left outer join
t tnext
on t.next = tnext.val
order by tnext.value
However, won't this do?
select t.*
from t
order by t.next
Something like this should work:
With Parent As (
Select
Value,
Previous,
Next
From
table
Where
Previous Is Null
Union All
Select
t.Value,
t.Previous,
t.Next
From
table t
Inner Join
Parent
On Parent.Next = t.Value
)
Select
*
From
Parent
Example
Let's say I have query a database with a where clause
WHERE _id IN (5,6,424,2)
Is there any way for the returned cursor to be sorted in the order that the _id's where listed in the list? _id attribute from first to last in Cursor to be 5, 6, 424, 2?
This happens to be on Android through a ContentProvider, but that's probably not relevant.
Select ID list using subquery and join with it:
select t1.*
from t1
inner join
(
select 1 as id, 1 as num
union all select 5, 2
union all select 3, 3
) ids on t1.id = ids.id
order by ids.num
UPD: Code fixed
One approach might be to do separate SQL queries with a UNION between each. You would obviously issue each query in the order you would like it returned to you.
...
order by
case when _id=5 then 1
when _id=6 then 2
end
etc.
You can join it to a virtual table that contains the list required in sort order
select tbl.*
from tbl
inner join (
select 1 as sorter, 5 as value union all
select 2, 6 union all
select 3, 424 union all
select 4, 2) X on tbl._id = X.value
ORDER BY X.sorter
List? You don't have a list! ;)
This:
WHERE _id IN (5,6,424,2)
is mere syntactic sugar for this:
WHERE (
_id = 5
OR _id = 6
OR _id = 424
OR _id = 2
)
SQL has but one data structure, being the table. Your (5,6,424,2) isn't a table either! :)
You could create a table of values but your next problem is that tables do not have any logical ordering. Therefore, as per #cyberkiwi's answer, you'd have to create a column explicitly to model the sort order. And in order to make it explicit to the calling application, ensure you expose this column in the SELECT clause of your query.
Maybe an over elaborate title. Basically think of an email inbox. I have a table
as so:
As you can see, it is a recursive table, very simple, just has the parentID of a message, and as you can see with the green highlight ring, the end of the "chain" is when there is a NULL for the parentID.
What I need is to provide (for example) the INBOXID of 12, and return back all parents.. in this example I should get 1 record back which is INBOXID of 11.
In the second example, I should be able to pass in INBOXID of 9, but this time I should get back rows INBOXID 8,7 and 1
I did have some success with the following query:
with q as
(
select inboxid, parentid
from bizzbox
union all
select a.inboxid, a.parentid
from bizzbox a
inner join q on q.inboxID = a.parentID
)
select distinct * from q
.. but of course it returns all of the parents for any of the rows.. I know it is probably something really stupidly simple like a where clause on one of the selects.. but having tried it (i.e. to parameterize the passing in of the start point inboxid), I can't quite see what I need to do???
Any help much appreciated!!!!!
David.
Try with this:
WITH cte
AS ( SELECT InboxID,
ParentID
FROM BIZZBOX
WHERE InboxID = #inboxID
UNION ALL
SELECT prev.InboxID,
prev.ParentID
FROM BIZZBOX prev
INNER JOIN cte curr ON prev.InboxID = curr.ParentID ),
cte1
AS ( SELECT InboxID,
ParentID
FROM BIZZBOX
WHERE InboxID = #inboxID
UNION ALL
SELECT prev.InboxID,
prev.ParentID
FROM BIZZBOX prev
INNER JOIN cte1 curr ON prev.ParentID = curr.InboxID )
SELECT * FROM cte
UNION
SELECT * FROM cte1