Recursive query in DB for z/OS - db2

Dear all I have a source table named "PROGRAM" as below
Program CSECT
X Y
B X
M P
A L
B D
C D
A C
B C
A B
D B
Given a Program say for example 'A' I need to find all the associated CSECTs
Program CSECT
A L
A C
A B
B D
B X
X Y
I have tried with recursive queries as below but it loops for a circular reference example B-D and D-B
WITH RPL (Program, Csect) AS
(SELECT ROOT.Program, ROOT.Csect
FROM Program ROOT
WHERE Program = 'A'
UNION ALL
SELECT CHILD.Program, CHILD.Csect
FROM RPL PARENT, Program CHILD
WHERE PARENT.Csect = CHILD.Program)
SELECT *
FROM RPL;

You may add and additional column (Chain) which would contain full path for the current row like below. A new row shouldn't be added, if CHILD.Program is already contained in such a path.
WITH RPL (Program, Csect, Chain) AS
(
SELECT ROOT.Program, ROOT.Csect, CAST('|' || ROOT.Program || '|' AS VARCHAR(1000))
FROM Program ROOT
WHERE Program = 'A'
UNION ALL
SELECT CHILD.Program, CHILD.Csect, PARENT.Chain || CHILD.Program || '|'
FROM RPL PARENT, Program CHILD
WHERE PARENT.Csect = CHILD.Program
AND LOCATE('|' || CHILD.Program || '|', PARENT.Chain) = 0
)
SELECT DISTINCT Program, Csect
FROM RPL
ORDER BY Program;

Related

Adding row value after grouping the table causes * must appear in the GROUP BY clause

I am trying to join 2 tables like so:
left join (
select t1.createdate, min(f1.createdate) as mindt, f1.status_aft
from new_table t1
left join new_folder f1 on t1.veh_id = f1.veh_id
where f1.createdate > t1.createdate
group by t1.createdate
) h3
on t1.createdate = h3.createdate
and f1.createdate = h3.mindt
But I am getting an error:
ERROR: column "f1.status_aft" must appear in the GROUP BY clause or be used in an aggregate function
This makes sense because I do not group it, my goal is just to take the value that is in that current row when f1.createdate is min.
For example:
A B C
one 10 a
one 15 b
two 20 c
two 25 d
Becomes
A B C
one 10 a
two 20 c
Because a and c was the values when column B were the lowest after grouping it by column A.
I've seen this answer but I still can't apply it to my scenario.
How can I achieve the desired result?
my goal is just to take the value that is in that current row when f1.createdate is min.
If you want just one row, you can order by and limit:
left join (
select t1.t1.createdate, f1.createdate as mindt, f1.status_aft
from new_table t1
left join new_folder f1 on t1.veh_id = f1.veh_id
where f1.createdate > t1.createdate
order by t1.createdate limit 1
) h3

calculate rank without using rank or rownums function by using single column

Do not use any functions like rank or rownums.
Hint: Formulate matrix operation using sql. A rank of an item indicates how many items are less than or equal to it.
A matrix can be simulated by cross join and rank can be derived by
counting items smaller than the current item.
Table A:-
x
----
d
b
a
g
c
k
k
g
Expected output:
x1 | rank
----+------
a | 1
b | 2
d | 3
g | 4
c | 5
k | 6
select x as x1, count(x) as rank
from (select DISTINCT x from A order by x) as sub
Your current query is on the right track, using a distinct subquery. For a working version, use a correlated subquery in the select clause which takes counts:
SELECT
x AS x1,
(SELECT COUNT(DISTINCT x) FROM A t WHERE t.x <= sub.x) rank
FROM (SELECT DISTINCT x FROM A) AS sub
ORDER BY
x;
Demo

JPQL: Access to outer attributes in JOIN of subquery

In my JPA model there are 3 tables A, B, C.
My query is:
SELECT a FROM A a
WHERE EXISTS (
SELECT c from C c LEFT JOIN B b"
ON c = b.c AND b.a = a
WHERE c.date BETWEEN CURRENT_TIMESTAMP AND :pUntil AND b.a IS NULL
)
Background is that I want all entities of A that do not have an entry in b that is linked to an event C in the future.
The problem is that I get Column 'T0.ID' is either not in any table in the FROM list or appears within a join specification and is outside the scope of the join specification or ...
EDIT
: Think of it as A is a user table, C are events, and B stores the registrations of users for events. I want to get all users, which have not registered for all future events until parameter pUntil.
Although I agree with Neil, I worked around this issue by changing my query. Here's the new query:
SELECT a FROM A a
WHERE EXISTS (
SELECT c from C c
WHERE c.date BETWEEN CURRENT_TIMESTAMP AND :pUntil
AND NOT EXISTS (
SELECT b from B b
WHERE b.c= c and b.a = a
)
)

PostgreSQL SQL query for traversing an entire undirected graph and returning all edges found

I have an edges table in my PostgreSQL database that represents the edges of a directed graph, with two columns: node_from and node_to (value is a node's id).
Given a single node (initial_node) I'd like to be able to traverse the entire graph, but in an undirected way.
What I mean is, for instance for the following graph :
(a->b)
(c->b)
(c->d)
If initial_node is a, b, c, or d, in any case, I would get [a, b, c, d].
I used the following SQL query (based on http://www.postgresql.org/docs/8.4/static/queries-with.html ):
WITH RECURSIVE search_graph(uniq, depth, path, cycle) AS (
SELECT
CASE WHEN g.node_from = 'initial_node' THEN g.node_to ELSE g.node_from END,
1,
CASE WHEN g.node_from = 'initial_node' THEN ARRAY[g.node_from] ELSE ARRAY[g.node_to] END,
false
FROM edges g
WHERE 'initial_node' in (node_from, node_to)
UNION ALL
SELECT
CASE WHEN g.node_from = sg.uniq THEN g.node_to ELSE g.node_from END,
sg.depth + 1,
CASE WHEN g.node_from = sg.uniq THEN path || g.node_from ELSE path || g.node_to END,
g.node_to = ANY(path) OR g.node_from = ANY(path)
FROM edges g, search_graph sg
WHERE sg.uniq IN (g.node_from, g.node_to) AND NOT cycle
)
SELECT * FROM search_graph
It worked fine... Until I had a case with 12 nodes that are all connected together, in all directions (for each pair I have both (a->b) and (b->a)), which makes the query loops indefinitely. (Changing UNION ALL to UNION doesn't eliminate the looping.)
Has anyone any piece of advice to handle this issue?
Cheers,
Antoine.
I got to this, it should not get into infinite loops with any kind of data:
--create temp table edges ("from" text, "to" text);
--insert into edges values ('initial_node', 'a'), ('a', 'b'), ('a', 'c'), ('c', 'd');
with recursive graph(points) as (
select array(select distinct "to" from edges where "from" = 'initial_node')
union all
select g.points || e1.p || e2.p
from graph g
left join lateral (
select array(
select distinct "to"
from edges
where "from" =any(g.points) and "to" <>all(g.points) and "to" <> 'initial_node') AS p) e1 on (true)
left join lateral (
select array(
select distinct "from"
from edges
where "to" =any(g.points) and "from" <>all(g.points) and "from" <> 'initial_node') AS p) e2 on (true)
where e1.p <> '{}' OR e2.p <> '{}'
)
select distinct unnest(points)
from graph
order by 1
Recursive queries are very limiting in terms of what can be selected, and since they don't allow using the recursive results inside a subselect, one can't use NOT IN (select * from recursive where...). Storing results in an array, using LEFT JOIN LATERAL and using =ANY() and <>ALL() solved this conundrum.

crystal report hierachical grouping options if part is repeat

I encounter a question about crystal report how to group by ?
I have a table named Part
Part_ID Parent_Part_ID
B A
c A
A NULL
C B
D B
E C
F C
A is a top part, B,C,D not only sub part but also are parent part, E,F are lowest sub part.
Now ,I need to show From Parent_part to Part with Levels,Like This
How Can I show this format data in Crystal report
I try use hierachical grouping options ,but the result is not i want
I need the result is:
A
B
C (shold be show even the part have two parent part)
E
F
D
C
E
F
SOLVED!
Tried menu voice called hierachical grouping options and specified the field that links each record to his parent.
The result should look similar to this:
A
B
C
E
F
D
C
E
F
But Crystal Reports Hierarchies take each record just once, and don't care if same element should be under two parents.
So i made a query-hack, creating hierarchy directly in the data using a JOIN on the same table based on Parent Item
DECLARE #t TABLE (Part_ID varchar(1), Parent_Part_ID varchar(1) );
insert into #t
SELECT 'B' , 'A'
UNION SELECT 'C' , 'A'
UNION SELECT 'A' , NULL
UNION SELECT 'C' , 'B'
UNION SELECT 'D' , 'B'
UNION SELECT 'E' , 'C'
UNION SELECT 'F' , 'C'
SELECT
t1.Part_ID as t1,
t2.Part_ID as t2,
t3.Part_ID as t3,
t4.Part_ID as t4
FROM #t t1
LEFT JOIN #t t2 on t1.Part_ID = t2.Parent_Part_ID
LEFT JOIN #t t3 on t2.Part_ID = t3.Parent_Part_ID
LEFT JOIN #t t4 on t3.Part_ID = t4.Parent_Part_ID
WHERE t1.Parent_Part_ID is null
and removed hierarchical grouping options, just created 3 groups on t1, t2, t3 using header for each group and using details for t4.
The result is, as needed,
A
B
C
E
F
D
C
E
F
Here the .rpt if someone needs it.