Use result of upper query in union clause in lower query - oracle

I am using union operator to combine results of 2 queries. Now I want to use the result of first query in second query so that I can exclude some records from second query.
E.g.
select <some_columns> from tableA Union select <same_columns> from tableA where <one_column_val> != <some_val_from_first_query>
Below is my query
SELECT a.*, b.*, c.*
FROM tableA a,
tableB b,
tableC c
where b.field_1 = c.field_1
and a.field_2 = c.field_2
union
SELECT a.*, b.*, c.*
FROM tableA a,
tableB b,
tableC c
where b.field_1 = c.field_1
and a.field_3=c.field_3
and a.field_2 <> {a.field_2 from upper query}
Please suggest the required alteration.
Thanks in advance

Each select in a SQL union has no knowledge of the others. So, you simply have to explicitly write out the entire query again, in your case either as a NOT EXISTS or a NOT IN. As an example, you can see the entire query copied as a derived table in a NOT EXISTS clause:
SELECT a.*, b.*, c.*
FROM tableA a,
tableB b,
tableC c
where b.field_1 = c.field_1
and a.field_2 = c.field_2
union
SELECT a.*, b.*, c.*
FROM tableA a,
tableB b,
tableC c
where b.field_1 = c.field_1
and a.field_3=c.field_3
and not exists (
select 1
from (
SELECT a.*, b.*, c.*
FROM tableA a,
tableB b,
tableC c
where b.field_1 = c.field_1
and a.field_2 = c.field_2
) x
where a.field_2 = x.field_2
)
If your RDBMS supports CTEs you can abstract the query into a CTE and not repeat yourself. Note you should probably also be using JOIN syntax if your RDBMS supports it, and you may have column name collisions with the * selector that you'll have to resolve.

Related

Invalid identifier when using left outer join in Oracle

I wrote a query with Left outer join in oracle.But I execute the query I get ORA-00904: "b"."GROSS_DISCOUNT_AMOUNT": invalid identifier error.TableB contains net_discount_number and gross_discount_amount columns.
select
a.GSMNO GSMNO,
a.NET_AMOUNT net,
a.GROSS_AMOUNT gross,
sum(b.net_discount_amount) net_discount, sum(b.gross_discount_amount) gross_discount,
a.code code, a.seq_no
from tableA a
LEFT OUTER JOIN
(select id, code, seq_no, sum(gross_amount) gross_amount, sum(net_discount_amount), sum(gross_discount_amount) from tableB
group by id, code, seq_no)
b ON a.id = b.id and NVL(a.code,b.code) = NVL(b.code,-99) and
NVL(a._seq_no,-99) = NVL(b.seq_no,-99)
and a.gross_amount = b.gross_amount
where a.tvNo like '123% and gsmno ='1111111111'
group by
a.GSMNO,
a.NET_AMOUNT,
a.GROSS_AMOUNT,
a.code, a.seq_no
You haven't specified aliases for aggregate sums, it should be like this:
select
a.GSMNO GSMNO,
a.NET_AMOUNT net,
a.GROSS_AMOUNT gross,
sum(b.net_discount_amount) net_discount, sum(b.gross_discount_amount) gross_discount,
a.code code, a.seq_no
from tableA a
LEFT OUTER JOIN
(select id, code, seq_no,
sum(gross_amount) gross_amount,
sum(net_discount_amount) net_discount_amount,
sum(gross_discount_amount) gross_discount_amount
from tableB
group by id, code, seq_no)
b ON a.id = b.id and NVL(a.code,b.code) = NVL(b.code,-99) and
NVL(a._seq_no,-99) = NVL(b.seq_no,-99)
and a.gross_amount = b.gross_amount
where a.tvNo like '123% and gsmno ='1111111111'
group by
a.GSMNO,
a.NET_AMOUNT,
a.GROSS_AMOUNT,
a.code, a.seq_no

Query to retrieve rows with no data even if not satisfying the where clause condition in Oracle

I have a query two tables - TableA , TableB
Query :
select a.name, count(b.code)
from tableA a
join tableA b on b.id = a.id
where a.name = ('AA','BB','WWW')
group by a.name;
The data is available only for AA so it displays the result as
AA 5
But i want to display the data as :
AA 5
BB 0
WWW 0
You can collect expected names into separate table/subquery and then perform a left join with your data tables like
with exp_names as (
select 'AA' name from dual
union all
select 'BB' from dual
union all
select 'WWW' from dual
)
select en.name, count(b.code)
from exp_names en
left join tableA a on en.name = a.name
left join tableB b on b.id = a.id
group by en.name;
fiddle

Oracle sql derived table - optional aliasing

I came across a client's query yesterday, it is something like:
select count(*) as countall,
person,
location
from (select custid,
min("Date") as theDate,
person,
data.location
from data join
customer on customer.customerid = custid
where status = 1
and custid <> -1
group by custid,
person,
data.location) --[NO ALIAS]
group by person,location
I don't have a lot of hours in Oracle, but in MS SQL this would not fly, to my knowledge. Any time I have used a derived table it throws an error, so to encounter scenarios such as this piques my interest. I couldn't find anything to explain it on the interwebs, hopefully somebody can explain the scenarios where aliasing for derived tables is optional and when it is not.
You only need to alias, when you are referencing a column that is not uniquely defined. This means that the column exists in more than one table/derived table. A reference could be in the select statement, or a join. If all columns are unique, then you do not need an alias.
I prefer to alias all of the time for clarity, and because it helps with Intellisense in PL/SQL.
--ALIAS needed, because the 'a' column referenced is not unique
--this will throw an error
select a, a, b, c
from (select 'A1' as a, 'B1' as b, 'C1' as c from dual),
(select 'A2' as a from dual);
--this will not throw an error
select t1.a, t2.a, b,c
from (select 'A1' as a, 'B1' as b, 'C1' as c from dual) t1,
(select 'A2' as a from dual) t2;
;
--ALIAS not needed for join, because all referenced columns are unique
select a, b, c, d, e, f
from (select 'A' as a, 'B' as b, 'C' as c from dual)
join (select 'D' as d, 'E' as e, 'F' as f from dual)
on a = d;
--ALIAS needed for join, because the 'x' column referenced is not unique
--this will throw an error
select a
from (select 'A' as a, 'B' as b, 'C' as c, 'X' as x from dual)
join (select 'D' as d, 'E' as e, 'F' as f, 'X' as x from dual)
on x = x;
--this will not throw an error
select a
from (select 'A' as a, 'B' as b, 'C' as c, 'X' as x from dual) t1
join (select 'D' as d, 'E' as e, 'F' as f, 'X' as x from dual) t2
on t1.x = t2.x;
In this instance, you are selecting all columns from your subquery and hence the subquery was written with no alias .
If you were to join this subquery with another table or perhaps another subquery, you would want to alias so that you can reference the join columns using the defined alias.

Order by position

Lets say we have two tables
TableA (A1,A2) , TableB(B1,B2)
Is there any difference (in therms of performance, memory usage ) between the two queries (only order by clause positions are different) below in oracle
Select Y.*, ROWNUM rNum FROM (
select * from
TableA a join TableB b on a.A1 = b.B1
Where a.A2 = 'SomeVal'
Order by b.B2
) A
Select Y.*, ROWNUM rNum FROM (
select * from
TableA a join TableB b on a.A1 = b.B1
Where a.A2 = 'SomeVal'
) A
Order by B2
Yes -- in the latter the rownum is assigned prior to the rows being ordered, and in the former the rownum is assigned after the rows are ordered.
So the first query's rownums might read as, "1,2,3,4,5 ...", whereas the second query's rownums might read, "33,3,5,45,1 ..."

How to select values from row with maximum date for multiple id matches

I'm not sure my title makes the question I am asking very clear. I am using an SQL Developer to query an Oracle database. I have contructed the query below which is able to pull the values I require for one specific ID. I need a query that will pull the same values but for multiple ids. I will need to run the same query on a monthly basis for a varying set of 20-50 ids. The database contains 80,000+ ids so I do not want to pull everything if I can avoid it. Is this possible?
SELECT b.id, a.final_grade, a.final_score
FROM db.table1 a, db.table2 b
where a.survey_id=b.survey_id
and b.id = '1796'
and a.created_dt = (select max (a.created_dt) from db.table1 a, db.table2 b
where a.survey_id=b.survey_id and b.cp_id = '1796')
thanks a lot for your help
Easiest way is to use ROW_NUMBER() and a WITH clause.
with data as
SELECT
b.id,
a.final_grade,
a.final_score,
ROW_NUMBER OVER (PARTITION BY b.id, order by a.created_dt desc) rn
FROM
db.table1 a
INNER JOIN db.table2 b
ON a.survey_id=b.survey_id
where
b.id in (<Comma seperated list of ids>)
)
SELECT * FROM DATA WHERE rn = 1
Note: if there are ties for created_dt for a given id an arbitrary row will be selected. If you instead want ties to be displayed replace ROW_NUMBER with RANK()
I think that this is what your looking for or at least this is what i got with your explanation:
SELECT b.id, a.final_grade, a.final_score
FROM db.table1 a, db.table2 b
where a.survey_id=b.survey_id
and b.id IN (<SELECT query with your list of ids>)
and a.created_dt **IN** (select max (a.created_dt) from db.table1 a, db.table2 b
where a.survey_id=b.survey_id and b.cp_id = b.id )
SELECT b.id, a.final_grade, a.final_score
FROM db.table1 a, db.table2 outerb
where a.survey_id=outerb.survey_id
and outerb.id IN (<SELECT query with your list of ids>)
and a.created_dt = (select max (a.created_dt) from db.table1 a, db.table2 b
where a.survey_id=b.survey_id and b.cp_id = outerb.id )
Is that what you are looking for? Question is not clear!

Resources