Oracle query self-join? - oracle

I've simplified this example but hopefully the example provides enough substance to make sense.
If I have a table such as the following...
ITEM GROUP
---- -----
A 1
B 1
C 1
D 2
E 2
F 3
G 4
... and I am provided items A, B, D and F, I would like to contruct a query that will return those details along with the additional items in the associated groups, C and E.
It seems that I should be able to do some sort of inner join but I'm not clear on how it could be done. It would be best if this were done in a single query due to the constraints of the environment.
Thanks much!

If I understand you correctly, this would work.
SELECT item,
group_num
FROM table_name
WHERE grroup_num IN (SELECT group_num
FROM table_name
WHERE item IN ('A', 'B', 'D', 'F'))
You could also write it as an EXISTS
SELECT item,
group_num
FROM table_name a
WHERE EXISTS( SELECT 1
FROM table_name b
WHERE a.group_num = b.group_num
AND b.item IN ('A','B','D','F') )

Related

I am getting "missing keyword" error in co-related sub query in Oracle

EXPLAIN SELECT S.ITEMID, X.STATUS
FROM
(select itemid,itemdescription from A WHERE parent_itemid IN(SELECT ITEMID FROM A WHERE itemtype='CT') AND itemtype='SK' AND id='02') S,
(select s1.itemid from s1,s2 where s1.itemid=s2.itemid and status='RC' ) X
where S.itemid=X.itemid
It is not correlated subquery that makes problems, but syntax. Not just explain, but explain plan for.
I don't have your tables so I used Scott's (properly joined):
SQL> explain plan for select s.dname, x.ename
2 from (select d.deptno,
3 d.dname
4 from dept d
5 where d.deptno in (select b.deptno
6 from dept b
7 where b.deptno = 10
8 )
9 ) s join
10 (select e.deptno,
11 e.ename
12 from emp e
13 where e.deptno = 10
14 ) x
15 on s.deptno = x.deptno;
Explained.
SQL>
In your case, presuming that everything else is correct,
explain plan for select s.itemid, x.status
from (select a.itemid,
a.itemdescription
from a
where a.parent_itemid in (select b.itemid
from a b
where b.itemtype = 'CT'
)
and a.itemtype = 'SK'
and a.id = '02'
) s join
(select s1.itemid
from s1 join s2 on s1.itemid = s2.itemid
where s1.status = 'RC' --> which table does STATUS belong to?
) x
on s.itemid = x.itemid;
I'd also suggest you to always use table aliases because it is not clear what belongs to which table. For example, status = 'RC' - without alias, it is impossible to know which table has it. If both, you'd have ambiguity.
Finally, write formatted queries. Mess you posted is difficult to read and understand. Most modern GUI tools have built-in formatters; I suggest you use it. Or, use one of online formatters. Or, format it manually. Just try not to do what you're doing now.
The correct syntax for EXPLAIN is:
EXPLAIN PLAN FOR
SELECT...
Also in the 2nd subquery you must select the column status because you want to select it in the outer select:
EXPLAIN PLAN FOR
SELECT S.ITEMID, X.STATUS
FROM
(select itemid,itemdescription from A WHERE parent_itemid IN(SELECT ITEMID FROM A WHERE itemtype='CT') AND itemtype='SK' AND id='02') S,
(select s1.itemid, status from s1,s2 where s1.itemid=s2.itemid and status='RC' ) X
where S.itemid=X.itemid
Also status should be qualified by the table's name just to avoid any ambiguities.

OUTER JOIN from different column names to same column

I am trying to select columns from different tables (the columns have different name) and use an outer join to get them in a single table. How do I do this?
(I am using sqlplus)
Here is an example:
Table a:
a.NAME1 a.NAME2 a.RATING
Jack Sparrow 4
Table b:
b.FIRSTNAME b.LASTNAME b.RATING
Jack Sparrow 7
Table 3:
c.F_NAME c.L_NAME c.RATING
Jack Sparrow 6
I would like a table like this:
NAME RATING
Jack 4
7
6
I tried this code
SELECT
a.NAME1 AS NAME,
b.FIRSTNAME AS NAME,
c.F_NAME AS NAME,
a.RATING AS RATING,
b.RATING AS RATING,
c.RATING AS RATING
FROM a
FULL OUTER JOIN (b
CROSS JOIN c)
ON (a.NAME1 = b.FIRSTNAME
AND a.NAME1 = c.F_NAME);
But that didn't work. How do I go about achieving this?
It does not sound like you want to join the tables at all. If you joined three tables each with 1 row, you would end up with a result set that had a single row and many columns. Since your goal is to end up with three rows of data, you would want to use a union all
SELECT a.name1, a.rating
FROM a
UNION ALL
SELECT b.firstname, b.rating
FROM b
UNION ALL
SELECT c.f_name, c.rating
FROM c
If you want to eliminate duplicate rows, use a union rather than a union all.
select a.NAME1, a.NAME2, a.RATING, b.RATING, c.RATING
from a
left outer join b on b.FIRSTNAME = a.NAME1 and b.LASTNAME = a.NAME2
left outer join c on c.F_NAME = a.NAME1 and c.L_NAME = a.NAME2

Oracle join tables and always include all possible results

I am trying to join two tables that look like the following:
Table 1
Letter | Value
A 2
B 5
Table 2
Letter | Number
A 1
C 7
I am trying to join these tables so that, regardless of what is in the tables at the time, there will always be an A,B,C record in the result. In other words, this would be displayed:
Letter | Value | Number
A 2 1
B 5 null
C null 7
The three letter records should always be displayed regardless of if they are in the tables. So assume table2 looks like this:
Letter | Number
A 1
Then I want the following results even though there is now no 'C' record:
Letter | Value | Number
A 2 1
B 5 null
C null null
Could anyone show how to do this?
You can use a SELECT ... FROM DUAL with a CONNECT BY clause to generate a stable set of letters in case some letters don't appear in either table.
with base_set_of_letters as (
select chr(rownum + 64) as Letter -- ascii 65=A, 66=B, 67=C, ...
from dual
connect by rownum <= 3) -- increase this number if you want more letters
select l.letter, t1.value, t2.xNumber
from base_set_of_letters l
left join Table1 t1 on t1.letter = l.letter
left join Table2 t2 on t2.letter = l.letter
order by l.letter;
SQL Fiddle Demo
If you were just looking to get all rows that existed joined, irregardless of whether data existed on both sides of the relationship, you'd be looking for a FULL OUTER JOIN:
SELECT COALESCE(t1.LETTER, t2.LETTER) AS LETTER,
t1.VALUE,
t2.NUM
FROM TABLE_1 t1
FULL OUTER JOIN TABLE_2 t2
ON t2.LETTER = t1.LETTER
ORDER BY COALESCE(t1.LETTER, t2.LETTER);
which produces
LETTER VALUE NUM
A 2 1
B 5 (null)
C (null) 7
But this would only give you rows where you've got a key value ('A', 'B', or 'C') - however, if one is missing you'd get nothing. IMO you need a third table, perhaps called ALPHABET, containing all possible letters:
CREATE TABLE ALPHABET (LETTER CHAR(1));
and populated with 'A', 'B', 'C', etc. In this case your join would become:
SELECT a.LETTER,
t1.VALUE,
t2.NUM
FROM ALPHABET a
FULL OUTER JOIN TABLE_1 t1
ON t1.LETTER = a.LETTER
FULL OUTER JOIN TABLE_2 t2
ON t2.LETTER = a.LETTER
which, if ALPHABET is only populated with ('A, 'B', 'C', and 'D'), produces
LETTER VALUE NUM
A 2 1
B 5 (null)
C (null) 7
D (null) (null)
SQLFiddle here (and note that in the fiddle I changed the variable name NUMBER to NUM to eliminate the need to double-quote it everywhere it's used).

HiveQL UNION ALL

I have table_A:
id var1 var2
1 a b
2 c d
Table_B:
id var1 var2
3 e f
4 g h
All I want is table, combined:
id var1 var2
1 a b
2 c d
3 e f
4 g h
This is my .hql:
CREATE TABLE combined AS
SELECT all.id, all.var1, all.var2
FROM (
SELECT a.id, a.var1, a.var2
FROM table_A a
UNION ALL
SELECT b.id, b.var1, b.var2
FROM table_B b
) all;
I'm coding straight from page 112 of Programming Hive by Edward Capriolo, et al.
The error I get, no matter what ostensibly reasonable variation of the above that I try, is
cannot recognize input near '.' 'id' ',' in select expression.
I have tried using AS between the table name and the alias, asterisks since I want everything from both tables. Same error. I've tried other things and gotten other errors... All I want to do is UNION two tables. (I've tried UNION instead of UNION ALL — same error).
Just replace all with another word. It seems to be a reserved keyword. E.g:
CREATE TABLE combined AS
SELECT unioned.id, unioned.var1, unioned.var2
FROM (
SELECT a.id, a.var1, a.var2
FROM table_A a
UNION ALL
SELECT b.id, b.var1, b.var2
from table_B b
) unioned;
I have similar query working. Just changing table name and column names. Try this. Hope this helps you.
create table new_table as
select
distinct
id, name
FROM
table1
union all
select
distinct
id,name
from
table2
;
Try this, it worked for me.
CREATE TABLE combined AS
SELECT id, var1, var2
FROM (
SELECT id, var1, var2
FROM table_A
UNION ALL
SELECT id, var1, var2
from table_B
) a;

Hive QL - Limiting number of rows per each item

If I have multiple items listed in a where clause How would one go about limiting the results to N for each item in the list?
EX:
select a_id,b,c, count(*), as sumrequests
from table_name
where
a_id in (1,2,3)
group by a_id,b,c
limit 10000
Sounds like your question is to get the top N per a_id. You can do this with a window function, introduced in Hive 11. Something like:
SELECT a_id, b, c, count(*) as sumrequests
FROM (
SELECT a_id, b, c, row_number() over (Partition BY a_id) as row
FROM table_name
) rs
WHERE row <= 10000
AND a_id in (1, 2, 3)
GROUP BY a_id, b, c;
This will output up to 10,000 randomly-chosen rows per a_id. You can partition it further if you're looking to group by more than just a_id. You can also use order by in the window functions, there are a lot of examples out there to show additional options.

Resources