Oracle SQL Find First Match from single table [closed] - sql

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have a table that lists concurrent program IDs and names. However, the table allows more than one name for each program ID. I'm needing to report some data about the programs, but am having trouble getting it to display correctly, as the program name is what is being displayed and grouped by in Tableau.
So what I need is a way to pull the first name for each program ID from the table. Since I'm including the program name in my output, I can't use unique (it wouldn't filter the alternate names) & I can't use a join as there wouldn't be a unique match.

Several options (of varying efficiency) to get the (alphabetically) first name for each id.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE PROGRAMS ( ID, NAME ) AS
SELECT 1, 'Charlie' FROM DUAL
UNION ALL SELECT 1, 'Bob' FROM DUAL
UNION ALL SELECT 1, 'Alice' FROM DUAL
UNION ALL SELECT 2, 'Ed' FROM DUAL
UNION ALL SELECT 2, 'Doris' FROM DUAL
UNION ALL SELECT 3, 'Fern' FROM DUAL
UNION ALL SELECT 3, 'Godfrey' FROM DUAL;
Query 1:
SELECT ID,
MIN( NAME ) AS NAME
FROM PROGRAMS
GROUP BY ID
ORDER BY ID
Results:
| ID | NAME |
|----|-------|
| 1 | Alice |
| 2 | Doris |
| 3 | Fern |
Query 2:
SELECT DISTINCT
ID,
FIRST_VALUE( NAME ) OVER ( PARTITION BY ID ORDER BY NULL ) AS NAME
FROM PROGRAMS
ORDER BY ID
Results:
| ID | NAME |
|----|-------|
| 1 | Alice |
| 2 | Doris |
| 3 | Fern |
Query 3:
SELECT ID,
NAME
FROM PROGRAMS p
WHERE NOT EXISTS ( SELECT 'X'
FROM PROGRAMS x
WHERE p.ID = x.ID
AND p.NAME > x.NAME )
ORDER BY ID
Results:
| ID | NAME |
|----|-------|
| 1 | Alice |
| 2 | Doris |
| 3 | Fern |

Related

How to traverse postgresql in the form of linked list?

I have a table in the form of linked list.
| unique_id | next |
| -------- | ------- |
| 1 | 3 |
| 2 | null |
| 3 | 2 |
Here the unique_id is the id of the row. Next is the id of the row it is pointing to. There is another table which keeps track of the head. Let's say row with uId=1 is the head. So, I want to query my table such that it extracts head from the headTable and gives the data in the same order as this linked-list. 1->3->2 in the form of an array of rows.
Expected Result : [{unique_id:1, next:3},{unique_id:3, next:2}{unique_id:2, next:null}]
Sorry, I'm unable to render the above table properly that's why It's in the form of code.
Try a recursive query - and add a "path" column to the query:
CREATE TABLE
-- your input ....
indata(unique_id,next) AS (
SELECT 1,3
UNION ALL SELECT 2,null
UNION ALL SELECT 3,2
)
;
\pset null NULL
WITH RECURSIVE recursion AS (
SELECT
unique_id
, next
, (unique_id::VARCHAR(8)||'>'||next::VARCHAR(8))::VARCHAR(16) AS path
FROM indata
WHERE unique_id=1 -- need a starting filter
UNION ALL
SELECT
c.unique_id
, c.next
, p.path||'>'||NVL(c.next::VARCHAR(8),'NULL')
FROM recursion p
JOIN indata c ON p.next = c.unique_id
)
SELECT * FROM recursion;
-- out unique_id | next | path
-- out -----------+------+------------
-- out 1 | 3 | 1>3
-- out 3 | 2 | 1>3>2
-- out 2 | NULL | 1>3>2>NULL
A bit late with the answer, but here is my version, without adding columns.
with recursive headtablelist as (
select unique_id, next
from headtable
where unique_id = 1
union
select e.unique_id, e.next
from headtable e
inner join headtablelist s on s.next = e.unique_id
)
select * from headtablelist;
Demo in sqldaddy.io
More information about recursive queries can be found here.

Combine two rows in a table to one with SQL

I'm trying to write an SQL query (in Oracle DB) which performs the following:
Table:
Id | Name | Father_id
1 | John | 2
2 | Peter |
3 | Ann | 2
Expected result:
Name | Father_Name
John Peter
Ann Peter
I would like to list all the people who have a father in one row with the father's name. The user can have (of course) max. one father, but has not neccessarily one.
Which would be the best way to write such a query?
self join, if you want fatherless children, do a left outer join
select *
from table t_child join
table t_father on t_child.father_id = t_father.id
try this sql it will definatlly work
select child.MenuName as ChildName,parent.MenuName as ParentName from table_name as child
left join table_name as parent on child.parentId = parent.MenuId
you need to use left because you mention that not necessarily one
You do not need to use a self-join (and two table/index scans) and can instead do it with a hierarchical query:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE people ( Id, Name, Father_id ) AS
SELECT 1, 'John', 2 FROM DUAL UNION ALL
SELECT 2, 'Peter', NULL FROM DUAL UNION ALL
SELECT 3, 'Ann', 2 FROM DUAL
Query 1:
SELECT name,
PRIOR name AS father_name
FROM people
WHERE LEVEL > 1
OR CONNECT_BY_ISLEAF = 0 -- Comment out if you do not want Peter,NULL
CONNECT BY PRIOR id = father_id
Results:
| NAME | FATHER_NAME |
|-------|-------------|
| Peter | (null) |
| John | Peter |
| Ann | Peter |

Oracle SQL hierarchical query from bottom to top element

In my table I store the successor of each entry.
+----+-----------+--+
| ID | SUCCESSOR | |
+----+-----------+--+
| 1 | 2 | |
| 2 | 3 | |
| 3 | | |
+----+-----------+--+
I need to get from ID 3 to ID 1.
I have tried to archieve this with the following query, but this does not work. :-(
SELECT NVL (id, 3)
FROM my_table
WHERE LEVEL = 1
CONNECT BY id = PRIOR successor
START WITH id = 3;
Can somebody please give me some advice how to get this working?
The following version should also provide the correct answer:
with my_table as
(select 1 id, 2 successor from dual union
select 2 id, 3 successor from dual union
select 3 id, null successor from dual )
SELECT id FROM my_table
WHERE level = 3
CONNECT BY successor = PRIOR id
START WITH successor is null
;

How to fetch all product names of latest product version? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
In my table, I have two columns prod_name & prod_version_number. I want all prod_name of latest prod_version_number.
Update:
|prod_name| prod_version_number |
| abc | 1 |
| abc | 2 |
| xyz | 1 |
| xyz | 2 |
| xyz | 3 |
I want to fetch abc & xyz of version_number 2 & 3 respectively.
Here is my attempt.
select prod_name from t where prod_version_number= (select MAX(prod_version_number));
NOTE I know the rules of SOF. So can you undo the negative votes.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE products ( prod_name, prod_version_number ) AS
SELECT 'abc', 1 FROM DUAL
UNION ALL SELECT 'abc', 2 FROM DUAL
UNION ALL SELECT 'xyz', 1 FROM DUAL
UNION ALL SELECT 'xyz', 2 FROM DUAL
UNION ALL SELECT 'xyz', 3 FROM DUAL;
Query 1:
SELECT *
FROM (
SELECT p.*,
ROW_NUMBER() OVER ( PARTITION BY prod_name ORDER BY prod_version_number DESC ) AS rn
FROM products p
)
WHERE rn = 1
Results:
| PROD_NAME | PROD_VERSION_NUMBER | RN |
|-----------|---------------------|----|
| abc | 2 | 1 |
| xyz | 3 | 1 |
SELECT d.prod_name
FROM table d
WHERE d.prod_version_number= (SELECT MAX(d1.prod_version_number) FROM table d1 WHERE d1.prod_name = d.prod_name )
Not sure if there is a more efficient way to do it by using GROUP BY clauses, will think about it and edit later if I find one. But for the moment, this should work.

SQL query update by grouping

I'm dealing with some legacy data in an Oracle table and have the following
--------------------------------------------
| RefNo | ID |
--------------------------------------------
| FOO/BAR/BAZ/AAAAAAAAAA | 1 |
| FOO/BAR/BAZ/BBBBBBBBBB | 1 |
| FOO/BAR/BAZ/CCCCCCCCCC | 1 |
| FOO/BAR/BAZ/DDDDDDDDDD | 1 |
--------------------------------------------
For each of the /FOO/BAR/BAZ/% records I want to make the ID a Unique incrementing number.
Is there a method to do this in SQL?
Thanks in advance
EDIT
Sorry for not being specific. I have several groups of records /FOO/BAR/BAZ/, /FOO/ZZZ/YYY/. The same transformation needs to occur for each of these other (example) groups. The recnum can't be used I want ID to start from 1, incrementing, for each group of records I have to change.
Sorry for making a mess of my first post. Output should be
--------------------------------------------
| RefNo | ID |
--------------------------------------------
| FOO/BAR/BAZ/AAAAAAAAAA | 1 |
| FOO/BAR/BAZ/BBBBBBBBBB | 2 |
| FOO/BAR/BAZ/CCCCCCCCCC | 3 |
| FOO/BAR/BAZ/DDDDDDDDDD | 4 |
| FOO/ZZZ/YYY/AAAAAAAAAA | 1 |
| FOO/ZZZ/YYY/BBBBBBBBBB | 2 |
--------------------------------------------
Let's try something like this(Oracle version 10g and higher):
SQL> with t1 as(
2 select 'FOO/BAR/BAZ/AAAAAAAAAA' as RefNo, 1 as ID from dual union all
3 select 'FOO/BAR/BAZ/BBBBBBBBBB', 1 from dual union all
4 select 'FOO/BAR/BAZ/CCCCCCCCCC', 1 from dual union all
5 select 'FOO/BAR/BAZ/DDDDDDDDDD', 1 from dual union all
6 select 'FOO/ZZZ/YYY/AAAAAAAAAA', 1 from dual union all
7 select 'FOO/ZZZ/YYY/BBBBBBBBBB', 1 from dual union all
8 select 'FOO/ZZZ/YYY/CCCCCCCCCC', 1 from dual union all
9 select 'FOO/ZZZ/YYY/DDDDDDDDDD', 1 from dual
10 )
11 select row_number() over(partition by ComPart order by DifPart) as id
12 , RefNo
13 From (select regexp_substr(RefNo, '[[:alpha:]]+$') as DifPart
14 , regexp_substr(RefNo, '([[:alpha:]]+/)+') as ComPart
15 , RefNo
16 , Id
17 from t1
18 ) q
19 ;
ID REFNO
---------- -----------------------
1 FOO/BAR/BAZ/AAAAAAAAAA
2 FOO/BAR/BAZ/BBBBBBBBBB
3 FOO/BAR/BAZ/CCCCCCCCCC
4 FOO/BAR/BAZ/DDDDDDDDDD
1 FOO/ZZZ/YYY/AAAAAAAAAA
2 FOO/ZZZ/YYY/BBBBBBBBBB
3 FOO/ZZZ/YYY/CCCCCCCCCC
4 FOO/ZZZ/YYY/DDDDDDDDDD
I think that actual updating the ID column wouldn't be a good idea. Every time you add new groups of data you would have to run the update statement again. The better way would be creating a view and you will see desired output every time you query it.
rownum can be used as an incrementing ID?
UPDATE legacy_table
SET id = ROWNUM;
This will assign unique values to all records in the table. This link contains documentation about Oracle Pseudocolumn.
You can run the following:
update <table_name> set id = rownum where descr like 'FOO/BAR/BAZ/%'
This is pretty rough and I'm not sure if your RefNo is a single value column or you just made it like that for simplicity.
select
sub.RefNo
row_number() over (order by sub.RefNo) + (select max(id) from TABLE),
from (
select FOO+'/'+BAR+'/'+BAZ+'/'+OTHER as RefNo
from TABLE
group by FOO+'/'+BAR+'/'+BAZ+'/'+OTHER
) sub