Merge concept in Oracle - oracle

**Before Merge:**
***Source table as SRC***
-------------
| A | B | C |
-------------
| a | b | 10|
| c | d | 20|
| w | x | 30|
| w | y | 40|
| w | z | 50|
-------------
***Target Table as TGT***
--------------
| D | E | F |
--------------
| a | b | null|
| c | e | null|
| w | m | null|
| w | n | null|
| w | o | null|
-------------
***After Merge:***
***Target table as TGT***
-----------
| D | E | F |
------------
| a | b | 10|
| c | e | 20|
| w | m | 50|
-----------
I have mentioned 2 tables above: one as source table and other as target table
I want to merge above two tables and store result in target in oracle
Logic:
1st logic: (find out the matching values of A and to D and B column to E column and only 1 match found)
Ex: A.a = D.a and B.b = E.b then update C column value to F column i.e. F=10
2nd logic: If 1st logic not found then find out the matching values of A column to the D column and B column value don’t match with E column and only 1 match found)
Ex: A.c = D.c then update C column value to F column i.e. F=20
3rd logic: If 1st logic and 2nd logic not found then find out the matching values of A column to the D column and B column value don’t match with E column and multiple matches found) then update the C column value of highest number in F column.
Ex: A.w = D.w -> we have 3 rows, out of those we select the value which has high value i.e. 50 and store this value in F column i.e. F = 50 in one row and remove other two rows
After merging, no. of rows are reduced. How to write a program for this using MERGE concept in oracle

You can use the corelated sub-query as follows:
Update tgt t
Set t.f = (Select Coalesce(Max(case when s.b = t.e then s.c end), Max(s.c))
From src s
Where s.a = t.d)

Related

Delete column and Add column with default value Amplify graphql DynamoDB Appsync

I want to delete the whole column at once if there 1000's of data deleting one by one is time consuming so is there any best way to do it
Deleting this column
And my next question is I need to add new column with default value aftering deleting
i.e :
id | x | y | z
| A | B | C
| A | B | C
| A | B | C
| A | B | C
If above is the the table with thousands of data , I want to delete "z" and add "newColumn" with default value of "D" as below
id | x | y | newColumn
| A | B | D
| A | B | D
| A | B | D
| A | B | D

Lag and Lead to next month

TABLE: HIST
CUSTOMER MONTH PLAN
1 1 A
1 2 B
1 2 C
1 3 D
If I query:
select h.*, lead(plan) over (partition by customer order by month) np from HIST h
I get:
CUSTOMER MONTH PLAN np
1 1 A B
1 2 B C
1 2 C D
1 3 D (null)
But I wanted
CUSTOMER MONTH PLAN np
1 1 A B
1 2 B D
1 2 C D
1 3 D (null)
Reason being, next month to 2 is 3, with D. I'm guessing partition by customer order by month doesn't work the way I thought.
Is there a way to achieve this in Oracle 12c?
One way to do it is to use RANGE partitioning with the MIN analytic function. Like this:
select h.*,
min(plan) over
(partition by customer
order by month
range between 1 following and 1 following) np
from HIST h;
+----------+-------+------+----+
| CUSTOMER | MONTH | PLAN | NP |
+----------+-------+------+----+
| 1 | 1 | A | B |
| 1 | 2 | B | D |
| 1 | 2 | C | D |
| 1 | 3 | D | |
+----------+-------+------+----+
When you use RANGE partitioning, you are telling Oracle to make the windows based on the values of the column you are ordering by rather than making the windows based on the rows.
So, e.g.,
ROWS BETWEEN 1 following and 1 following
... will make a window containing the next row.
RANGE BETWEEN 1 following and 1 following
... will make a window containing all the rows having the next value for month.
UPDATE
If it is possible that some values for MONTH might be skipped for a given customer, you can use this variant:
select h.*,
first_value(plan) over
(partition by customer
order by month
range between 1 following and unbounded following) np
from h
+----------+-------+------+----+
| CUSTOMER | MONTH | PLAN | NP |
+----------+-------+------+----+
| 1 | 1 | A | B |
| 1 | 3 | B | D |
| 1 | 3 | C | D |
| 1 | 4 | D | |
+----------+-------+------+----+
You can use LAG/LEAD twice. The first time to check for duplicate months and to set the value to NULL in those months and the second time use IGNORE NULLS to get the next monthly value.
It has the additional benefit that if months are skipped then it will still find the next value.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE HIST ( CUSTOMER, MONTH, PLAN ) AS
SELECT 1, 1, 'A' FROM DUAL UNION ALL
SELECT 1, 2, 'B' FROM DUAL UNION ALL
SELECT 1, 2, 'C' FROM DUAL UNION ALL
SELECT 1, 3, 'D' FROM DUAL UNION ALL
SELECT 2, 1, 'E' FROM DUAL UNION ALL
SELECT 2, 1, 'F' FROM DUAL UNION ALL
SELECT 2, 3, 'G' FROM DUAL UNION ALL
SELECT 2, 5, 'H' FROM DUAL;
Query 1:
SELECT CUSTOMER,
MONTH,
PLAN,
LEAD( np ) IGNORE NULLS OVER ( PARTITION BY CUSTOMER ORDER BY MONTH, PLAN, ROWNUM ) AS np
FROM (
SELECT h.*,
CASE MONTH
WHEN LAG( MONTH ) OVER ( PARTITION BY CUSTOMER ORDER BY MONTH, PLAN, ROWNUM )
THEN NULL
ELSE PLAN
END AS np
FROM hist h
)
Results:
| CUSTOMER | MONTH | PLAN | NP |
|----------|-------|------|--------|
| 1 | 1 | A | B |
| 1 | 2 | B | D |
| 1 | 2 | C | D |
| 1 | 3 | D | (null) |
| 2 | 1 | E | G |
| 2 | 1 | F | G |
| 2 | 3 | G | H |
| 2 | 5 | H | (null) |
Just so that it is listed here as an option for Oracle 12c (onward), you can use an apply operator for this style of problem
select
h.customer, h.month, h.plan, oa.np
from hist h
outer apply (
select
h2.plan as np
from hist h2
where h.customer = h.customer
and h2.month > h.month
order by month
fetch first 1 rows only
) oa
order by
h.customer, h.month, h.plan
I don't know of any Oracle 12c public fiddles so, an example in SQL Server can be found here: http://sqlfiddle.com/#!18/cd95e/1
| customer | month | plan | np |
|----------|-------|------|--------|
| 1 | 1 | A | C |
| 1 | 2 | B | D |
| 1 | 2 | C | D |
| 1 | 3 | D | (null) |

How to fill same value with child row

In Oracle, i want to fill child to lowest parent value.
that is query and result
query :
SELECT col1,col2 FROM DATA
result :
+-----------+------+
| col1 | col2 |
+-----------+------+
| 001 | a |
| 001001 | b |
| 001002 | c |
| 001003 | d |
| 001003001 | e |
| 001003002 | f |
| 002 | g |
| 003 | h |
| 003001 | i |
| 003002 | j |
+-----------+------+
col1 is key. and child index have parent index.
i want to make this result
+------+------+------+------+
| col1 | col2 | col3 | col4 |
+------+------+------+------+
| a | b | b | b |
| a | c | c | c |
| a | d | e | e |
| a | d | f | f |
| g | g | g | g |
| h | i | i | i |
| h | j | j | j |
+------+------+------+------+
if parent have no child, child columns fill to parent.
how can i make this result?...
thank you.
One way to do this:
select c1, coalesce(c2, c1) c2, coalesce(c3, c2, c1) c3, coalesce(c4, c3, c2, c1) c4
from (select substr(path, 2, 1) c1, substr(path, 4, 1) c2,
substr(path, 6, 1) c3, substr(path, 8, 1) c4
from (select sys_connect_by_path(col2, ' ') path
from data
where connect_by_isleaf = 1
connect by substr(col1, 1, length(prior col1)) = prior col1
and length(prior col1) + 3 = length(col1)
start with length(col1) = 3 ) )
Assuming that values in col2 are 1-char long You can do it like above. Otherwise you have to change substr(path, ..., ...) using instr() or regular expressions.
The inner query is hierarchical where I'm selecting only whole path from leaf rows. Outer queries puts data into particular columns dealing with null values.
If You work on Oracle 11g or above You can probably achieve this in more elegant way using Recursive Subquery Factoring.
Test data and output:
create table data (col1 varchar2(10), col2 varchar2(1));
insert into data values ('001', 'a');
insert into data values ('001001', 'b');
insert into data values ('001002', 'c');
insert into data values ('001003', 'd');
insert into data values ('001003001', 'e');
insert into data values ('001003002', 'f');
insert into data values ('002', 'g');
insert into data values ('003', 'h');
insert into data values ('003001', 'i');
insert into data values ('003002', 'j');
C1 C2 C3 C4
-- -- -- --
a b b b
a c c c
a d e e
a d f f
g g g g
h i i i
h j j j
7 rows selected

hive rows preceding unexpected behavior

Given this ridiculously simple data set:
+--------+-----+
| Bucket | Foo |
+--------+-----+
| 1 | A |
| 1 | B |
| 1 | C |
| 1 | D |
+--------+-----+
I want to see the value of Foo in the previous row:
select
foo,
max(foo) over (partition by bucket order by foo rows between 1 preceding and 1 preceding) as prev_foo
from
...
Which gives me:
+--------+-----+----------+
| Bucket | Foo | Prev_Foo |
+--------+-----+----------+
| 1 | A | A |
| 1 | B | A |
| 1 | C | B |
| 1 | D | C |
+--------+-----+----------+
Why do I get 'A' back for the first row? I would expect it to be be null. It's throwing off calculations where I'm looking for that null. I can work around it by throwing a row_number() in there, but I'd prefer to handle it with fewer calcs.
use the LAG function to get previous row:
LAG(foo) OVER(partition by bucket order by foo) as Prev_Foo

Joining tables with same column names - ORACLE

I am using Oracle.
I am currently working one 2 tables which both have the same column names. Is there any way in which I can combine the 2 tables together as they are?
Simple example to show what I mean:
TABLE 1:
| COLUMN 1 | COLUMN 2 | COLUMN 3 |
----------------------------------------
| a | 1 | w |
| b | 2 | x |
TABLE 2:
| COLUMN 1 | COLUMN 2 | COLUMN 3 |
----------------------------------------
| c | 3 | y |
| d | 4 | z |
RESULT THAT I WANT:
| COLUMN 1 | COLUMN 2 | COLUMN 3 |
----------------------------------------
| a | 1 | w |
| b | 2 | x |
| c | 3 | y |
| d | 4 | z |
Any help would be greatly appreciated. Thank you in advance!
You can use the union set operator to get the result of two queries as a single result set:
select column1, column2, column3
from table1
union all
select column1, column2, column3
from table2
union on its own implicitly removes duplicates; union all preserves them. More info here.
The column names don't need to be the same, you just need the same number of columns with the same datatpes, in the same order.
(This is not what is usually meant by a join, so the title of your question is a bit misleading; I'm basing this on the example data and output you showed.)

Resources