can you please explain why the error ORA-00918 is generated while executing this query
INSERT INTO CLG_TEST_2 (CLG_TEST_2.record_id, CLG_TEST_2.chain_id,
CLG_TEST_2.chain_n,
CLG_TEST_2.contact_info)
select * from (
SELECT 1, 1, 0, '2222' from dual UNION ALL
SELECT 2, 2, 0, '4444' from dual UNION ALL
SELECT 3, 3, 0, '6666' from dual
)
Error at line 1
ORA-00918: column ambiguously defined
Script Terminated on line 2.
The issue is in the fact that you are using a select * over a query without giving aliases to the columns; this will work:
INSERT INTO CLG_TEST_2 (CLG_TEST_2.record_id,
CLG_TEST_2.chain_id,
CLG_TEST_2.chain_n,
CLG_TEST_2.contact_info)
select *
from (
SELECT 1 a, 1 b, 0 c, '2222' d from dual UNION ALL
SELECT 2 , 2 , 0 , '4444' from dual UNION ALL
SELECT 3 , 3 , 0 , '6666' from dual
)
However, you can simplify your code:
INSERT INTO CLG_TEST_2 (record_id, chain_id, chain_n, contact_info)
SELECT 1, 1, 0, '2222' from dual UNION ALL
SELECT 2, 2, 0, '4444' from dual UNION ALL
SELECT 3, 3, 0, '6666' from dual
Something more about the reason of the error.
Your code:
SQL> INSERT INTO CLG_TEST_2 (
2 CLG_TEST_2.record_id,
3 CLG_TEST_2.chain_id,
4 CLG_TEST_2.chain_n,
5 CLG_TEST_2.contact_info)
6 select * from (
7 SELECT 1, 1, 0, '2222' from dual UNION ALL
8 SELECT 2, 2, 0, '4444' from dual UNION ALL
9 SELECT 3, 3, 0, '6666' from dual
10 );
select * from (
*
ERROR at line 6:
ORA-00918: column ambiguously defined
Slightly different:
SQL> INSERT INTO CLG_TEST_2 (
2 CLG_TEST_2.record_id,
3 CLG_TEST_2.chain_id,
4 CLG_TEST_2.chain_n,
5 CLG_TEST_2.contact_info)
6 select * from (
7 SELECT 1, 2, 0, '2222' from dual UNION ALL
8 SELECT 2, 2, 0, '4444' from dual UNION ALL
9 SELECT 3, 3, 0, '6666' from dual
10 );
3 rows created.
What's different?
In the first row, I changed
SELECT 1, 1, 0, '2222' --> SELECT 1, 2, 0, '2222'
^ ^
The reason:
SQL> SELECT 1, 2, 0, '2222' from dual UNION ALL
2 SELECT 2, 2, 0, '4444' from dual UNION ALL
3 SELECT 3, 3, 0, '6666' from dual;
1 2 0 '222
---------- ---------- ---------- ----
1 2 0 2222
2 2 0 4444
3 3 0 6666
SQL> SELECT 1, 1, 0, '2222' from dual UNION ALL
2 SELECT 2, 2, 0, '4444' from dual UNION ALL
3 SELECT 3, 3, 0, '6666' from dual;
1 1 0 '222
---------- ---------- ---------- ----
1 1 0 2222
2 2 0 4444
3 3 0 6666
SQL>
Here you have two columns with the same alias '1', and this is confusing for the external select *.
Also, a direct-path insert is something different
I don't see any "Direct-Path" insert. Anyway, try this one
INSERT INTO CLG_TEST_2 (CLG_TEST_2.record_id, CLG_TEST_2.chain_id,
CLG_TEST_2.chain_n,
CLG_TEST_2.contact_info)
SELECT 1, 1, 0, '2222' from dual UNION ALL
SELECT 2, 2, 0, '4444' from dual UNION ALL
SELECT 3, 3, 0, '6666' from dual
btw, why do you use string from numbers?
Related
I have the following setup, which is working perfectly. I am difficulty figuring out the syntax how to display the course name in the output. In my test CASE all the rows should have the value Geometry.
In addition, how could I use rank or rank_dense to limit the output to display only 1 row with the highest average?
CREATE TABLE students(student_id, first_name, last_name) AS
SELECT 1, 'Faith', 'Aaron' FROM dual UNION ALL
SELECT 2, 'Lisa', 'Saladino' FROM dual UNION ALL
SELECT 3, 'Leslee', 'Altman' FROM dual UNION ALL
SELECT 4, 'Patty', 'Kern' FROM dual UNION ALL
SELECT 5, 'Betty', 'Bowers' FROM dual;
CREATE TABLE courses(course_id, course_name) AS
SELECT 1, 'Geometry' FROM dual UNION ALL
SELECT 2, 'Trigonometry' FROM dual UNION ALL
SELECT 3, 'Calculus' FROM DUAL;
CREATE TABLE grades(student_id,
course_id, grade) AS
SELECT 1, 1, 75 FROM dual UNION ALL
SELECT 1, 1, 81 FROM dual UNION ALL
SELECT 1, 1, 76 FROM dual UNION ALL
SELECT 2, 1, 100 FROM dual UNION ALL
SELECT 2, 1, 95 FROM dual UNION ALL
SELECT 2, 1, 96 FROM dual UNION ALL
SELECT 3, 1, 80 FROM dual UNION ALL
SELECT 3, 1, 85 FROM dual UNION ALL
SELECT 3, 1, 86 FROM dual UNION ALL
SELECT 4, 1, 88 FROM dual UNION ALL
SELECT 4, 1, 85 FROM dual UNION ALL
SELECT 4, 1, 91 FROM dual UNION ALL
SELECT 5, 1, 98 FROM dual UNION ALL
SELECT 5, 1, 74 FROM dual UNION ALL
SELECT 5, 1, 81 FROM dual;
/* average grade of each student */
select s.student_id
, s.first_name
, s.last_name
, round(avg(g.grade), 1) as student_avg
from students s
join grades g
on s.student_id = g.student_id
group by s.student_id, s.first_name, s.last_name
ORDER BY avg(g.grade) DESC;
Something like this?
SQL> with temp as
2 (select s.student_id
3 , s.first_name
4 , s.last_name
5 , c.course_name
6 , round(avg(g.grade), 1) as student_avg
7 , rank() over (order by avg(g.grade) desc) rnk
8 from students s join grades g on s.student_id = g.student_id
9 join courses c on c.course_id = g.course_id
10 group by s.student_id, s.first_name, s.last_name, c.course_name
11 )
12 select student_id, first_name, last_name, course_name, student_avg
13 from temp
14 where rnk <= 3
15 order by rnk;
STUDENT_ID FIRST_ LAST_NAM COURSE_NAME STUDENT_AVG
---------- ------ -------- ------------ -----------
2 Lisa Saladino Geometry 97
4 Patty Kern Geometry 88
5 Betty Bowers Geometry 84.3
SQL>
I have a table including CONTRACT_ID, ADDENDUM_ID and PAYMENT_MONTH (payment dates of a yearly contract).
Everytime an update occurs for any reason in the system:
ADDENDUM_ID udates as +1
PAYMENT_MONTH records are duplicated for the remaining months
In attached picture I tried to explain in detail using an example (a contract with 3 updates).
The question is how to write a query to get a summary table ignoring the duplicated but unnecessary records (grey filled ones) because of a new update on addendum column.
Please note that there are hundreds of contracts in the original table, while the example contains only one.
Thanks in advance.
If I correctly understand your desired output, maybe this can help:
with test(contract_id, addendum_id, payment_month) as
(
select 155, 1, 1 from dual union all
select 155, 1, 2 from dual union all
select 155, 1, 3 from dual union all
select 155, 1, 4 from dual union all
select 155, 1, 5 from dual union all
select 155, 1, 6 from dual union all
select 155, 1, 7 from dual union all
select 155, 1, 8 from dual union all
select 155, 1, 9 from dual union all
select 155, 1, 10 from dual union all
select 155, 1, 11 from dual union all
select 155, 1, 12 from dual union all
select 155, 2, 5 from dual union all
select 155, 2, 6 from dual union all
select 155, 2, 7 from dual union all
select 155, 2, 8 from dual union all
select 155, 2, 9 from dual union all
select 155, 2, 10 from dual union all
select 155, 2, 11 from dual union all
select 155, 2, 12 from dual union all
select 155, 3, 10 from dual union all
select 155, 3, 11 from dual union all
select 155, 3, 12 from dual
)
select contract_id, addendum_id, payment_month from (
select
max(addendum_id) over ( partition by payment_month) as max_addendum_id,
contract_id, payment_month, addendum_id
from test
)
where max_addendum_id = addendum_id
order by 1, 2, 3
I have 3 columns a,b,c in table.i need to find the duplicates for the columns a & b but with distinct value in c column.
Maybe you need something like this:
with test(a, b, c) as (
select 1, 2, 10 from dual union all
select 1, 2, 20 from dual union all
select 4, 5, 30 from dual union all
select 4, 5, 30 from dual union all
select 3, 2, 3 from dual union all
select 6, 2, 2 from dual
)
select a, b
from test
group by a,b
having count(distinct c) > 1
That is, you need to aggregate for A,B, but only keeping pairs for which there are more DISTINCT values for column C
We have a table with a self-referencing tree structure (id, parent_id). Let's assume the following tree structure:
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
I'd like to fetch this data for displaying it in a tree. But only certain records expanded. I'm currently using the following query:
SELECT ID, NAME "PATH"
FROM GROUPS
WHERE PRIOR ID IN(1, 4)
CONNECT BY PARENT_ID = PRIOR ID
START WITH PARENT_ID IS NULL;
This works very well and returns the following records:
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
The problem is that this query returns every record of which the direct parent is expanded, but not the whole parent chain. So if we're just expanding id 4, records 5, 6, 7 still shouldn't be returned as 1 is not expanded.
What I have been trying so far is to fetch a custom column which indicates whether the element is expanded, which computes out of whether it is explicitly expanded AND the parent is expanded as well.
SELECT ...
CASE WHEN (ID IN (4) AND PRIOR EXPANDED = 1) THEN 1 ELSE 0 end "EXPANDED"
...
WHERE "EXPANDED" = 1
This does not work as I can use the EXPANDED alias neither in the WHERE statement nor the PRIOR EXPANDED statement.
Is there a simple way of achieving this using a simple query?
Oracle Setup:
CREATE TABLE hierarchy ( id, parent_id ) AS
SELECT 1, NULL FROM DUAL UNION ALL
SELECT 2, 1 FROM DUAL UNION ALL
SELECT 3, 2 FROM DUAL UNION ALL
SELECT 4, 1 FROM DUAL UNION ALL
SELECT 5, 4 FROM DUAL UNION ALL
SELECT 6, 5 FROM DUAL UNION ALL
SELECT 7, NULL FROM DUAL UNION ALL
SELECT 8, 7 FROM DUAL UNION ALL
SELECT 9, 8 FROM DUAL UNION ALL
SELECT 10, 9 FROM DUAL UNION ALL
SELECT 11, 8 FROM DUAL;
Query - IN clause has all parents explanded:
SELECT LPAD( '+ ', LEVEL*2, ' ' ) || id
FROM hierarchy
START WITH parent_id IS NULL
CONNECT BY PRIOR id = parent_id
AND parent_id IN ( 1, 2, 4, 5, 7, 8, 9 );
Output:
+ 1
+ 2
+ 3
+4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
Query - IN clause has all parents expanded except 4 and 8:
SELECT LPAD( '+ ', LEVEL*2, ' ' ) || id
FROM hierarchy
START WITH parent_id IS NULL
CONNECT BY PRIOR id = parent_id
AND parent_id IN ( 1, 2, 5, 7, 9 );
Output:
+ 1
+ 2
+ 3
+4
+ 7
+ 8
Update - Showing leaf nodes:
SELECT LPAD( '+ ', LEVEL*2, ' ' ) || id AS value,
isleaf
FROM (
-- Find the leaves first (as if all parents are expanded)
SELECT h.*,
CONNECT_BY_ISLEAF AS isLeaf
FROM hierarchy h
START WITH parent_id IS NULL
CONNECT BY PRIOR id = parent_id
)
START WITH parent_id IS NULL
CONNECT BY PRIOR id = parent_id
AND parent_id IN ( 1, 2, 4, 7, 9 );
Output:
VALUE ISLEAF
---------------- ----------
+ 1 0
+ 2 0
+ 3 1
+ 4 0
+ 5 0
+ 7 0
+ 8 0
1 Indicates that the node has no children and 0 indicates that the node has children (even though they might not be expanded).
OK, just saw your note about requiring the entire parent chain to be expanded. The following does this by using sys_connect_by_path to build that chain, then checking that it is all 1's (have to lop off the last node which is at the current level):
With 1 and 4 expanded you get:
WITH hier as (
SELECT 1 id, NULL parent_id, 1 expanded FROM DUAL UNION ALL
SELECT 2, 1, 0 FROM DUAL UNION ALL
SELECT 3, 2, 0 FROM DUAL UNION ALL
SELECT 4, 1, 1 FROM DUAL UNION ALL
SELECT 5, 4, 0 FROM DUAL UNION ALL
SELECT 6, 4, 0 FROM DUAL UNION ALL
SELECT 7, 4, 0 FROM DUAL UNION ALL
SELECT 8, 1, 0 FROM DUAL UNION ALL
SELECT 9, 1, 0 FROM DUAL UNION ALL
SELECT 10, 9, 0 FROM DUAL UNION ALL
SELECT 11, 9, 0 FROM DUAL )
SELECT LPAD( '+ ', lvl*2, ' ' ) || id
FROM (
SELECT ID
, parent_id
, level as lvl
, sys_connect_by_path(expanded,'-') as path_expanded
FROM hier
CONNECT BY PARENT_ID = PRIOR ID
START WITH PARENT_ID IS NULL
)
WHERE --every node in the path from the parent is expanded.
instr(substr(path_expanded,1,length(path_expanded)-2),'0') = 0
OR parent_id is null ;
LPAD('+',LVL*2,'')||ID
+ 1
+ 2
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
Change to un-expand at node 1 and you get:
WITH hier as (
SELECT 1 id, NULL parent_id, 0 expanded FROM DUAL UNION ALL
SELECT 2, 1, 0 FROM DUAL UNION ALL
SELECT 3, 2, 0 FROM DUAL UNION ALL
SELECT 4, 1, 1 FROM DUAL UNION ALL
SELECT 5, 4, 0 FROM DUAL UNION ALL
SELECT 6, 4, 0 FROM DUAL UNION ALL
SELECT 7, 4, 0 FROM DUAL UNION ALL
SELECT 8, 1, 0 FROM DUAL UNION ALL
SELECT 9, 1, 0 FROM DUAL UNION ALL
SELECT 10, 9, 0 FROM DUAL UNION ALL
SELECT 11, 9, 0 FROM DUAL )
SELECT LPAD( '+ ', lvl*2, ' ' ) || id
FROM (
SELECT ID
, parent_id
, level as lvl
, sys_connect_by_path(expanded,'-') as path_expanded
FROM hier
CONNECT BY PARENT_ID = PRIOR ID
START WITH PARENT_ID IS NULL
)
WHERE --every node in the path from the parent is expanded.
instr(substr(path_expanded,1,length(path_expanded)-2),'0') = 0
OR parent_id is null ;
LPAD('+',LVL*2,'')||ID
+ 1
If i give this query,
Select 1,2,3,4,5,6,7,8,9 from dual;
It will look like this
1 2 3 4 5 6 7 8 9 - column names
1 2 3 4 5 6 7 8 9 - Associated values
But i want to show like this
1
2
3
4
5
6
7
8
9
I don't know how to do this with dual table
"Unpivot version":
select val from (select 1, 2, 3, 4, 5, 6, 7, 8, 9 from dual)
unpivot (val for tmp in ("1", "2", "3", "4", "5", "6", "7", "8", "9"))
Simpler alternative giving the same results:
select * from table(sys.odcinumberlist(1, 2, 3, 4, 5, 6, 7, 8, 9))
Just use union all:
select 1 as name from dual union all
select 2 as name from dual union all
select 3 as name from dual union all
select 4 as name from dual union all
select 5 as name from dual union all
select 6 as name from dual union all
select 7 as name from dual union all
select 8 as name from dual union all
select 9 as name from dual;