How to Capture Original "Start With" ID as a Column in Oracle SQL LEVEL Query - sql

Working with a large database of material being consumed as "inputs" to create various "outputs" over multiple generations. The final output (the product for market) can have potentially a dozen+ generations of inputs in its history. Each of these inputs has its own record.
Currently I'm creating a top-down view of this genealogy (meaning starting with final product and working back through all inputs) using LEVEL.
Simplified/Conceptual example of the code as follows:
SELECT
OL.LOT_NAME AS output_id,
IL.LOT_NAME AS input_id,
LEVEL
FROM GENEALOGY_TABLE G
INNER JOIN LOT_TABLE OL
on G.OUTPUT_LOT_KEY = OL.LOT_KEY
INNER JOIN LOT_TABLE IL
on G.INPUT_LOT_KEY = IL.LOT_KEY
START WITH OL.LOT_NAME IN ('X', 'Y', etc...)
CONNECT BY NOCYCLE PRIOR IL.LOT_NAME = OL.LOT_NAME
ORDER BY LEVEL
I am looking to add another column to this output table that holds the original "START WITH" value that is the origin of any the given record. Meaning that even if the record has a level of 10, I won't just see the level 9 output that that material created, but which of the multiple final products ('X', 'Y', etc... in the above example) that was ultimately created downstream.
Does Oracle have a function that can handle this? Is there a simple trick for this I'm missing? Any suggestions would be wonderful.

You can use the connect_by_root operator:
SELECT
OL.LOT_NAME AS output_id,
IL.LOT_NAME AS input_id,
LEVEL,
CONNECT_BY_ROOT(OL.LOT_NAME) AS STARTED_WITH
FROM GENEALOGY_TABLE G
...
Quick demo using HR-schema tables:
SELECT employee_id, last_name, manager_id, connect_by_root(manager_id)
FROM employees
START WITH manager_id in (101, 102)
CONNECT BY PRIOR employee_id = manager_id;
EMPLOYEE_ID LAST_NAME MANAGER_ID CONNECT_BY_ROOT(MANAGER_ID)
----------- ------------------------- ---------- ---------------------------
108 Greenberg 101 101
109 Faviet 108 101
110 Chen 108 101
111 Sciarra 108 101
112 Urman 108 101
113 Popp 108 101
200 Whalen 101 101
203 Mavris 101 101
204 Baer 101 101
205 Higgins 101 101
206 Gietz 205 101
103 Hunold 102 102
104 Ernst 103 102
105 Austin 103 102
106 Pataballa 103 102
107 Lorentz 103 102
16 rows selected.

With Oracle there is always a way. Use CONNECT_BY_ROOT.

Related

find records with same key but different second column value

My Input data is :
Id salary
101 1000
101 1000
102 2500
102 3000
105 5000
105 5000
105 5000
106 12
106 142
106 12
Output :
102 2500
102 3000
106 12
106 142
106 12
I mean based on the id , I want to find out which Id has different salary. If the salary is the same in all the records , I want to discard those records. Kindly help.
select *
from t
where id in(
select Id
from t
group by Id
having max(salary) <> min(salary)
)
Id
salary
102
2500
102
3000
106
12
106
142
106
12
Fiddle
SELECT `Id`, `salary` FROM salary
WHERE Id IN( SELECT Id FROm salary GROUP By Id HAVING COUNT(DISTINCT SALARY) > 1)
Id
salary
102
2500
102
3000
106
12
106
142
106
12
fiddle

SQL Query to order data based on other column value

I have the below set of data(current data), where system_id is the ID of the particular system. And pre_system_id's are ID of system where it is dependent. Now I need the order in such a way that rows with no dependent system should come first , then rows with one dependent system come second and so on.
The current result:
System_ID PRE_SYSTEM_ID1 PRE_SYSTEM_ID2 PRE_SYSTEM_ID3 PRE_SYSTEM_ID4
106 100
105
112 105 100 109
100
109 100 105
119 100 109 105 112
102 112 109
104 109 106
The actual result should be like below:
Order System_ID PRE_SYSTEM_ID1 PRE_SYSTEM_ID2 PRE_SYSTEM_ID3 PRE_SYSTEM_ID4
1 100
2 105
3 106 100
4 109 100 105
5 112 105 100 109
6 119 100 109 105 112
7 104 109 106
8 102 112 109 104
The query for the current result is simply
Select * from ImpactedSystem;
Sorting by the various PRE_SYSTEM_IDn columns using the nulls first clause should produce the order you want:
select *
from ImpactedSystem
order by PRE_SYSTEM_ID1 nulls first,
PRE_SYSTEM_ID2 nulls first,
PRE_SYSTEM_ID3 nulls first,
PRE_SYSTEM_ID4 nulls first,
SYSTEM_ID
Finally sort by SYSTEM_ID, to order the values with no dependent IDs.
you can use the below query to obtain the result as well.
select *
from Current_data
order by DECODE(pre_system_td1,null,1),
DECODE(pre_system_td2,null,1),
DECODE(pre_system_td3,null,1),
DECODE(pre_system_td4,null,1);

Oracle select query based on multiple conditions

MESSAGE_ID GROUP_ID REV_NO
100 200 1
101 201 1
102 202 1
103 203 1
104 204 1
105 200 2
106 201 2
107 202 2
108 203 2
109 204 2
110 205 2
First I want to select all group ID's and their correpsponding lowest revision number.
Then I want select first X message ID's (Controllable X input) with condition that it should contain all the revisions of of any selected group. For e.g if I select first 5 messages by rownum then all revisions of group_id 200 is not selected.
Hope I made it clear.

ORA 00918- Column ambiguosly defined error [duplicate]

This question already has answers here:
ORA-00918: column ambiguously defined in SELECT *
(4 answers)
Closed 9 years ago.
There are two tables in my Oracle database.
First table is (customers)-
customer_id Customer_name Customer_age Customer_address salary
103 Giriraj Rathi 22 Kolkata 12000
100 Subir Adhikari 22 Bolpur 10000
101 Rakesh Chatterjee 21 Tarkeshwar 8000
102 Jayanta Patra 20 Tarkeshwar 9000
104 Abhi Karmakar 22 Burdwan 8000
105 Mainak Manna 21 Burdwan 9000
106 Subho Gupta 20 Kolkata 10000
107 Aritra Das 23 Kolkata 7000
108 Pradip Paul 22 Kolkata 5000
109 Sourav Banerjee 22 Bolpur 9000
Second table is (Orders):
Order_id Order_date customer_id amount
200 12-03-13 100 1100
201 09-05-13 101 1400
202 07-04-12 103 2500
204 29-05-13 104 2400
203 09-02-13 105 9000
205 18-06-13 106 2100
206 09-07-13 107 1600
207 18-05-13 108 2900
209 18-04-13 109 2400
Now I wanted to join both the tables. So I used the query:
select customer_id,
customer_name,
customer_address,
order_id,order_date,
amount
from customers,
orders
where customers.customer_id=orders.customer_id;
I Googled about the error and found this happens when there is ambiguity in the SQL code itself, but in this case I see nothing.
It is always a good idea to add the table name/alias to the column like this
select c.customer_id,
c.customer_name,
c.customer_address,
o.order_id,
o.order_date,
o.amount
from customers c
inner join orders o on c.customer_id = o.customer_id
If you don't then the DB don't know which column to take and both tables have a column named customer_id.

How I select record that not appear in another table

Table: Movie
mID title year director
101 Gone with the Wind 1939 Victor Fleming
102 Star Wars 1977 George Lucas
103 The Sound of Music 1965 Robert Wise
104 E.T. 1982 Steven Spielberg
105 Titanic 1997 James Cameron
106 Snow White 1937 <null>
107 Avatar 2009 James Cameron
108 Raiders of the Lost Ark 1981 Steven Spielberg
Table: Rating
rID mID stars ratingDate
201 101 2 2011-01-22
201 101 4 2011-01-27
202 106 4 <null>
203 103 2 2011-01-20
203 108 4 2011-01-12
203 108 2 2011-01-30
204 101 3 2011-01-09
205 103 3 2011-01-27
205 104 2 2011-01-22
205 108 4 <null>
206 107 3 2011-01-15
206 106 5 2011-01-19
207 107 5 2011-01-20
208 104 3 2011-01-02
I need to fetch movies which are not rate yet. In this case Titanic (mID 105) and Star Wars (mID 102) never get rate in rating table.
I figured out it with
select distinct movie.title from movie,rating where
rating.mid!=movie.mid except select distinct movie.title from
movie,rating where rating.mid=movie.mid
however I think it might have better (easier/cleaner) way to do.
Simple:
SELECT Movies.* FROM Movies LEFT JOIN Rating ON Movies.mID = Rating.mID WHERE Rating.mID IS NULL
If I understood your question properly, that looks like textbook application of outer joins.
You could do it like this:
SELECT * FROM Movie WHERE mid NOT IN (SELECT DISTINCT(mid) FROM Rating)
Basically it will select all records from the movie table that are not in the rating table, linking them on the 'mid' column, which I am assuming is a unique identifier.
I will add another possibility.
Select [list columns here]
from Movie m
where NOT exists (SELECT * FROM RATING r where m.mid = r.mid)