I have this situation in Oracle while trying to do a select from 2 tables:
Table1
-------------
Col1 Col2
-------------
1 abc
2 aa
3 lab
4 mm
5 nn
6 kk
7 pp
Table 2
-----------
Col1 Col2
----------
4 xxx
7 yyy
(null) zzz
I want all rows including (null) zzz of Table2 in my select.
What I am doing is -
SELECT column1, column2,….FROM Table1, Table2 Where table1.col1 = Table2.col1(+)
But it does not give me the row with NULL value in Table2.
I tried putting OR conditions with left outer join on col1 but it does not work.
SELECT column1, column2,…. FROM Table1, Table2 Where table1.col1 = Table2.col1(+) OR Table2.Col1 IS NULL
This is expected output:
Col1 Table1.Col2 Table2.Col2
--------------------------------
1 abc (null)
2 aa (null)
3 lab (null)
4 mm xxx
5 nn (null)
6 kk (null)
7 pp yyy
(null) (null) zzz
Its seems what you want is a FULL OUTER JOIN
SQL Fiddle
Query 1:
SELECT
t1.COl1
,t1.col2
,t2.col2
FROM Table1 t1
FULL OUTER JOIN Table2 t2 ON
( t1.col1 = t2.col1 )
ORDER BY Col1
Results:
| COL1 | COL2 | COL2 |
|--------|--------|--------|
| 1 | abc | (null) |
| 2 | aa | (null) |
| 3 | lab | (null) |
| 4 | mm | xxx |
| 5 | nn | (null) |
| 6 | kk | (null) |
| 7 | pp | yyy |
| (null) | (null) | zzz |
An important advice to you is to get rid of (+) outer join notation and use ANSI .. JOIN ON syntax.
Related
I m trying to replicate this sql syntax in Vertica, but it returns "ERROR: Subqueries in the ON clause are not supported".
The aim is to join two tables, table1 and table2, on column and date, if a.date = b.date or the closest but lesser b.date.
Any hint?
SELECT *
FROM table1 a
LEFT JOIN table2 b
ON a.column = b.column
AND b.Date = (SELECT MAX (b2.Date)
FROM table2 b2
WHERE a.column = b2.column
AND b2.Date <= a.Date)
Vertica has something handier for that: the event series join. With that, you can OUTER JOIN two tables so that they match the same or the immediately preceding value of the join column of the other table. The predicate is INTERPOLATE PREVIOUS VALUE instead of an equi-predicate.
Here's an example with the oil pressure curve and the engine rpm curve with the timestamp matching only once.
DROP TABLE IF EXISTS oilpressure;
CREATE TABLE oilpressure (
op_vid,op_ts,op_psi
) AS (
SELECT 42,TIMESTAMP '2020-04-01 07:00:00', 25.356
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:12', 35.124
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:23', 47.056
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:34', 45.225
)
;
DROP TABLE IF EXISTS revspeed;
CREATE TABLE revspeed (
rs_vid,rs_ts,rpm
) AS (
SELECT 42,TIMESTAMP '2020-04-01 07:00:00', 2201
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:10', 3508
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:20', 6504
UNION ALL SELECT 42,TIMESTAMP '2020-04-01 07:00:30', 6608
)
;
-- without
\pset null '(null)'
SELECT *
FROM oilpressure
LEFT OUTER JOIN revspeed
ON op_vid=rs_vid AND op_ts=rs_ts ;
-- out Null display is "(null)".
-- out op_vid | op_ts | op_psi | rs_vid | rs_ts | rpm
-- out --------+---------------------+--------+--------+---------------------+--------
-- out 42 | 2020-04-01 07:00:00 | 25.356 | 42 | 2020-04-01 07:00:00 | 2201
-- out 42 | 2020-04-01 07:00:12 | 35.124 | (null) | (null) | (null)
-- out 42 | 2020-04-01 07:00:23 | 47.056 | (null) | (null) | (null)
-- out 42 | 2020-04-01 07:00:34 | 45.225 | (null) | (null) | (null)
-- with
SELECT *
FROM oilpressure
LEFT OUTER JOIN revspeed
ON op_vid=rs_vid AND rs_ts INTERPOLATE PREVIOUS VALUE op_ts;
-- out op_vid | op_ts | op_psi | rs_vid | rs_ts | rpm
-- out --------+---------------------+--------+--------+---------------------+------
-- out 42 | 2020-04-01 07:00:00 | 25.356 | 42 | 2020-04-01 07:00:00 | 2201
-- out 42 | 2020-04-01 07:00:12 | 35.124 | 42 | 2020-04-01 07:00:10 | 3508
-- out 42 | 2020-04-01 07:00:23 | 47.056 | 42 | 2020-04-01 07:00:20 | 6504
-- out 42 | 2020-04-01 07:00:34 | 45.225 | 42 | 2020-04-01 07:00:30 | 6608
Hi I have the following table and I want to update the rows with same group where if the pervious row that have count zero have value I want to populate the other one with it if the row that needs to be populated was null otherwise no changes will be done.
Table 1 before update:
Group | Count | Name | lastName |
Grp1 | 0 | tyler | calark |
Grp1 | 1 | lara | jason |
Grp1 | 2 | null | spark |
Table 1 after update:
Group | Count | Name | lastName |
Grp1 | 0 | tyler | calark |
Grp1 | 1 | lara | jason |
Grp1 | 2 | tyler | spark |
This is how I understood it.
Before:
SQL> select * From test;
CGROUP CCOUNT NAME LAST_NAME
---------- ---------- ---------- ----------
D1 0 tyler clark
D1 1 jason lara
D1 2 spark
Update:
SQL> update test a set
2 a.name = (select b.name
3 from test b
4 where b.cgroup = a.cgroup
5 and b.ccount = 0
6 )
7 where a.name is null;
1 row updated.
After:
SQL> select * From test;
CGROUP CCOUNT NAME LAST_NAME
---------- ---------- ---------- ----------
D1 0 tyler clark
D1 1 jason lara
D1 2 tyler spark
SQL>
I have two tables:
Table 1:
+-----------+-----------+------------------+
| ID | Value | other |
+-----------+-----------+------------------+
| 123456 | 5 | 12 |
| 987654 | 7 | 15 |
| 456789 | 6 | 22 |
+-----------+-----------+------------------+
Table 2:
+-----------+-----------+------------------+
| ID | Type | other |
+-----------+-----------+------------------+
| 123456 | 00 | 2 |
| 123456 | 01 | 6 |
| 123456 | 02 | 4 |
| 987654 | 00 | 7 |
| 987654 | 01 | 8 |
| 456789 | 00 | 6 |
| 456789 | 01 | 16 |
+-----------+-----------+------------------+
Now I perform the inner join:
SELECT
table1.ID, table2.TYPE, table1.value, table2.other
FROM
table1 INNER JOIN table2 ON table1.ID = table2.ID
Here the SQLfiddle
Result Table:
+-----------+-----------+---------+------------------+
| ID | Type | Value | other |
+-----------+-----------+---------+------------------+
| 123456 | 00 | 5 | 2 |
| 123456 | 01 | 5 | 6 |
| 123456 | 02 | 5 | 4 |
| 987654 | 00 | 7 | 7 |
| 987654 | 01 | 7 | 8 |
| 456789 | 00 | 6 | 6 |
| 456789 | 01 | 6 | 16 |
+-----------+-----------+---------+------------------+
This is totally what I expected but not what I need.
Because if I now want to get the Value per ID the Value gets doubled or tripled for the first cause.
Desired Table:
+-----------+-----------+---------+------------------+
| ID | Type | Value | other |
+-----------+-----------+---------+------------------+
| 123456 | 00 | 5 | 2 |
| 123456 | 01 | - | 6 |
| 123456 | 02 | - | 4 |
| 987654 | 00 | 7 | 7 |
| 987654 | 01 | - | 8 |
| 456789 | 00 | 6 | 6 |
| 456789 | 01 | - | 16 |
+-----------+-----------+---------+------------------+
I tried to achieve a similar output by counting the rows per id and dividing the sum of Value by that count but it did not seem to work and is not the desired output.
Also, I tried grouping but this did not seem to achieve the desired output.
One thing to mention is that the DB I am working with is an ORACLE SQL DB.
How about this:
select table1.id
, table2.type
, case
when row_number() over (partition by table1.id order by table2.type) = 1
then table1.value
end as "VALUE"
, table2.other
from table1
join table2 on table1.id = table2.id
order by 1, 2;
(This is Oracle SQL syntax. Your SQL Fiddle (thanks!) was set to MySQL, which as far as I know doesn't have analytic functions like row_number().)
A way to get the result.
select t1.ID,
t2.type,
t1.value,
t2.other
from table1 t1 inner join table2 t2
ON t1.ID = t2.ID
inner join (select ID, min(type) mv
from table2
group by id) m
on t2.id = m.id
and t2.type = m.mv
union all
select t1.ID,
t2type,
null,
t2.other
from table1 t1 inner join table2 t2
ON t1.ID = t2.ID
and not exists (
select 1 from (
select ID, min(type) mv
from table2
group by id) m
where t2.id = m.id
and t2.type = m.mv
)
order by id,type
You can use a CASE block to display NULL for which it is NOT equal to MIN value of type
SELECT table1.ID,
table2.TYPE,
CASE
WHEN table2.TYPE =
MIN (table2.TYPE)
OVER (PARTITION BY table1.id ORDER BY table2.TYPE)
THEN
Table1.VALUE
END
VALUE,
table2.other
FROM table1 INNER JOIN table2 ON table1.ID = table2.ID;
Why do we use a (+) operator in the where clause for instance emp_name(+) IS NOT NULL, emp_name IS NOT NULL AND emp_name(+) IS NOT NULL is the same
Because removing the (+) from the column you're checking is not null turns the join from an outer join into what is effectively an inner join. Leaving the (+) in tells oracle to get all rows from the "main" table, and then match any rows from the outer joined table where that column is not null.
See the below for an example of why the "extra" (+) is needed:
with t1 as (select 1 id, 'a' val from dual union all
select 2 id, 'b' val from dual union all
select 3 id, 'c' val from dual),
t2 as (select 1 id, null val from dual union all
select 3 id, 'd' val from dual)
select *
from t1,
t2
where t1.id = t2.id (+)
and t2.val (+) is not null
order by t1.id;
ID VAL ID_1 VAL_1
---------- --- ---------- -----
1 a
2 b
3 c 3 d
with t1 as (select 1 id, 'a' val from dual union all
select 2 id, 'b' val from dual union all
select 3 id, 'c' val from dual),
t2 as (select 1 id, null val from dual union all
select 3 id, 'd' val from dual)
select *
from t1,
t2
where t1.id = t2.id (+)
and t2.val is not null
order by t1.id;
ID VAL ID_1 VAL_1
---------- --- ---------- -----
3 c 3 d
You can see the difference easier if you convert the query to the ANSI join syntax:
with t1 as (select 1 id, 'a' val from dual union all
select 2 id, 'b' val from dual union all
select 3 id, 'c' val from dual),
t2 as (select 1 id, null val from dual union all
select 3 id, 'd' val from dual)
select *
from t1
left outer join t2 on (t1.id = t2.id and t2.val is not null)
order by t1.id;
ID VAL ID_1 VAL_1
---------- --- ---------- -----
1 a
2 b
3 c 3 d
with t1 as (select 1 id, 'a' val from dual union all
select 2 id, 'b' val from dual union all
select 3 id, 'c' val from dual),
t2 as (select 1 id, null val from dual union all
select 3 id, 'd' val from dual)
select *
from t1
left outer join t2 on (t1.id = t2.id)
where t2.val is not null
order by t1.id;
ID VAL ID_1 VAL_1
---------- --- ---------- -----
3 c 3 d
In other words, it's the difference between the "col is not null" predicate being a part of the outer join condition, or a filter in the where clause.
You'll note as well that having the "t2.val is not null" in the where clause has the effect of turning the outer join into an inner join, despite the fact that you've requested an outer join:
with t1 as (select 1 id, 'a' val from dual union all
select 2 id, 'b' val from dual union all
select 3 id, 'c' val from dual),
t2 as (select 1 id, null val from dual union all
select 3 id, 'd' val from dual)
select *
from t1
left outer join t2 on (t1.id = t2.id)
--where t2.val is not null
order by t1.id;
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time | OMem | 1Mem | O/1/M |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 12 (100)| | | | |
| 1 | SORT ORDER BY | | 3 | 33 | 12 (17)| 00:00:01 | 2048 | 2048 | 1/0/0|
|* 2 | HASH JOIN OUTER| | 3 | 33 | 11 (10)| 00:00:01 | 1156K| 1156K| 1/0/0|
| 3 | VIEW | | 3 | 18 | 6 (0)| 00:00:01 | | | |
| 4 | UNION-ALL | | | | | | | | |
| 5 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | |
| 6 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | |
| 7 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | |
| 8 | VIEW | | 2 | 10 | 4 (0)| 00:00:01 | | | |
| 9 | UNION-ALL | | | | | | | | |
| 10 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | |
| 11 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | |
-----------------------------------------------------------------------------------------------------
with t1 as (select 1 id, 'a' val from dual union all
select 2 id, 'b' val from dual union all
select 3 id, 'c' val from dual),
t2 as (select 1 id, null val from dual union all
select 3 id, 'd' val from dual)
select *
from t1
left outer join t2 on (t1.id = t2.id)
where t2.val is not null
order by t1.id;
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time | OMem | 1Mem | O/1/M |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 10 (100)| | | | |
| 1 | SORT ORDER BY | | 1 | 11 | 10 (20)| 00:00:01 | 2048 | 2048 | 3/0/0|
|* 2 | HASH JOIN | | 1 | 11 | 9 (12)| 00:00:01 | 1156K| 1156K| 3/0/0|
| 3 | VIEW | | 2 | 10 | 2 (0)| 00:00:01 | | | |
| 4 | UNION-ALL | | | | | | | | |
|* 5 | FILTER | | | | | | | | |
| 6 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | |
| 7 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | |
| 8 | VIEW | | 3 | 18 | 6 (0)| 00:00:01 | | | |
| 9 | UNION-ALL | | | | | | | | |
| 10 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | |
| 11 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | |
| 12 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | |
-----------------------------------------------------------------------------------------------------
Note the change from HASH JOIN OUTER to HASH JOIN in the row with id = 2 in the 2nd explain plan.
I have the following two tables:
TableOne
========
Id1|ColA1|ColB1|ColC1|ColD1|ColE1
--------------------------------
1| AFoo|BFoo |CFoo | DFoo| EFoo
2| AFoo|BBar |CFoo | DFoo| EFoo
TableTwo
========
Id2|ColA2|ColB2|ColC2
---------------------
11| 1 |ABC |NOP |
12| 1 |ABC |QRS |
13| 1 |DEF |TUV |
14| 1 |DEF |WXY |
15| 1 |DEF |FGH |
16| 2 |ABC |NOP |
I run the following query:
select t1.*, t2.*
from TableOne t1
inner join TableTwo t2 on t2.ColA2=t1.Id1
where t1.ColA1='AFoo'
and get the following result:
Result
======
Id1|ColA1|ColB1|ColC1|ColD1|ColE1|Id2|ColA2|ColB2|ColC2
-------------------------------------------------------
1| AFoo|BFoo |CFoo | DFoo| EFoo| 11| 1 | ABC | NOP
1| AFoo|BFoo |CFoo | DFoo| EFoo| 12| 1 | ABC | QRS
1| AFoo|BFoo |CFoo | DFoo| EFoo| 13| 1 | DEF | TUV
1| AFoo|BFoo |CFoo | DFoo| EFoo| 14| 1 | DEF | WXY
1| AFoo|BFoo |CFoo | DFoo| EFoo| 15| 1 | DEF | FGH
2| AFoo|BBar |CFoo | DFoo| EFoo| 16| 2 | ABC | NOP
What I really want returned is:
Desired Result
======
Id1|MaxDup
----------------------------------------
1| 3 (This is because there are 3 DEF records)
2| 1 (This is because there is 1 ABC record)
So, I am trying to track the maximum number of occurrences in ColB2 which appears for each TableOne row. In the example above, the ID1 of 1 has two ABC records and three DEF records associated with it. Since there are more DEF records than ABC records, I want the count of DEF records returned.
Can anybody provide a working example that can demonstrate this?
Try this one (I haven't tested it):
with t2 as (
select ColA2, ColB2, count(*) cnt
from TableTwo
group by ColA2, ColB2
)
select t1.Id1,
( select max(cnt) MaxDup
from t2
where t2.ColA2=t1.Id1)
from TableOne t1
Here is a result based on your test data.
SQL> select
cola2
, cnt as maxDup
from (
select
cola2
, colb2
, cnt
, rank() over (partition by cola2 order by cnt desc ) cnt_rnk
from (
select cola2
, colb2
, count(*) as cnt
from TableTwo
group by cola2, colb2
)
)
where cnt_rnk = 1
/
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
COLA MAXDUP
---- ----------
1 3
2 1
SQL>
The innermost query counts the duplicate. The middle query ranks the counts of duplicates. The outermost query filters for the combo with the highest count:
Maybe this one?
SELECT t2.id2 id, count(t2.ColB2) MaxDup
FROM TableTwo t2
WHERE EXISTS(
SELECT * FROM TableOne t1
WHERE t1.id1 = t2.id2
AND t1.ColA1='AFoo')
AND rownum < 2
GROUP BY t2.id2, t2.ColB2
ORDER BY MaxDup desc;
It's SQL Server code, but I think it can be safely transferred to Oracle:
select id1,cola1,colb1,colc1,cold1,cole1,max(dup) as dup2 from (
select t1.id1, t1.cola1, t1.colb1, t1.colc1,t1.cold1,t1.cole1, t2.colb2,count(*) as dup
from t1
inner join t2 on t2.cola2=t1.Id1
where t1.cola1='Afoo'
group by t1.id1, t1.cola1, t1.colb1, t1.colc1,t1.cold1,t1.cole1, t2.colb2)
tab
group by id1,cola1,colb1,colc1,cold1,cole1
It works on Sql Server, and by enveloping in a subquery you can extract only id1 and dup2. Tried expanding your dataset, it works.