How to fill same value with child row - oracle

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

Related

Merge concept in 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)

Insert data to table from another table containing null values and replace null values with the original table 1 values

I want to match first column of both table and insert table 2 values to table 1 . But if Table 2 values are null leave table 1 vlaues as it is .I am using Hive to dothis .Please help.
You need to use coalesce to get non null value to populate b column and case statement to make decision to populate c column.
Example:
hive> select t1.a,
coalesce(t2.y,t1.b)b,
case when t2.y is null then t1.c
else t2.z
end as c
from table1 t1 left join table2 t2 on t1.a=t2.x;
+----+-----+----+--+
| a | b | c |
+----+-----+----+--+
| a | xx | 5 |
| b | bb | 2 |
| c | zz | 7 |
| d | dd | 4 |
+----+-----+----+--+

oracle - querying NULL values in unpivot query

I want to fetch records from oracle DB where column value is NULL. Also i am using unpivot in my query. Somehow NULL values are not getting selected because of unpivot keyword. Can you please help me about how to get rows for the same when using unpivot.
EDIT:
SELECT a.emp_id, a.emp_dept, b.emp_location
FROM employee a,
location b UNPIVOT (emp_id
FOR dummy_id
IN (emp_id AS 'EMP_ID', last_date AS 'LAST_DATE'))
WHERE emp_id = 123 AND b.emp_loc_id = 'india' AND b.location IS NULL;
Use UNPIVOT INCLUDE NULLS:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE test ( id, a, b, c, d ) AS
SELECT 1, 1, 2, 3, 4 FROM DUAL UNION ALL
SELECT 2, 1, NULL, 3, NULL FROM DUAL;
Query 1:
SELECT *
FROM test
UNPIVOT INCLUDE NULLS ( value FOR name IN ( a, b, c, d ) )
Results:
| ID | NAME | VALUE |
|----|------|--------|
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | C | 3 |
| 1 | D | 4 |
| 2 | A | 1 |
| 2 | B | (null) |
| 2 | C | 3 |
| 2 | D | (null) |

join order step by step in oracle

I have a trouble with below query.I want to join columns in step.
For example a.code first b.name1 if not match then join name2 etc.But i cant handle the query.
SELECT * FROM TABLE A
LEFT JOIN TABLE B
ON A.CODE = B.NAME1
OR A.CODE = B.NAME2
OR UPPER(B.NAME3) = UPPER(A.NAME)
Thanks
edit
with sample below,
if TABLEB.CODE = TABLEA.NAME1 match then dont want to look OR TABLEB.CODE = TABLEA.NAME2.
And if not matching any TABLEB.CODE = TABLEA.NAME1 then step by step match the columns on that order.
WITH TABLEA AS (SELECT 13445 AS ID,'A' AS TYPE,'DFSF' AS NAME1 , 'PCK' AS NAME2 FROM DUAL
UNION ALL
SELECT 13445 AS ID,'A' AS TYPE,'PCK' AS NAME1 , 'PCK' AS NAME2 FROM DUAL),
TABLEB AS (SELECT 56544 AS ID, 'PCK' AS CODE, 'PCK' AS FRST_NM FROM DUAL)
SELECT * FROM TABLEA
LEFT JOIN TABLEB
ON TABLEB.CODE = TABLEA.NAME1
OR TABLEB.CODE = TABLEA.NAME2
OR UPPER(TABLEB.FRST_NM) = UPPER(TABLEA.NAME2)
I believe your query will do what you want. There is no step by step in join conditions if you have already mentioned OR. So if either of the condition match, the rows will be matched. So if A.CODE <> B.NAME1 but A.CODE = B.NAME2, they will match. If both are true, then also they will match. I create a CTE with sample data to see the output. It will return 3 rows for 3 matches.
WITH TBL(SEQ,CODE,NAME,NAME1,NAME2,NAME3) AS
(
SELECT 1,'A1','B','A1','D','E' FROM DUAL UNION ALL -- as A.CODE(A1)=B.NAME1, it will match
SELECT 2, 'B2','B','D','B2','F' FROM DUAL UNION ALL --as A.CODE (B2) <> B.NAME1 , it will match for B.NAME2
SELECT 3, 'G','H1','D','A','H1' FROM DUAL UNION ALL --match for UPPER(B.NAME3) = UPPER(A.NAME)
SELECT 4,'P4','Q4','R4','S4','T4' FROM DUAL
)
SELECT * FROM TBL A
LEFT JOIN TBL B
ON (A.CODE = B.NAME1
OR A.CODE = B.NAME2
OR UPPER(B.NAME3) = UPPER(A.NAME)
)
Column SEQ is just to see what rows are returning.
Output
+-----+------+------+-------+-------+-------+-------+--------+--------+---------+---------+---------+
| SEQ | CODE | NAME | NAME1 | NAME2 | NAME3 | SEQ_1 | CODE_1 | NAME_1 | NAME1_1 | NAME2_1 | NAME3_1 |
+-----+------+------+-------+-------+-------+-------+--------+--------+---------+---------+---------+
| 1 | A1 | B | A1 | D | E | 1 | A1 | B | A1 | D | E |
| 2 | B2 | B | D | B2 | F | 2 | B2 | B | D | B2 | F |
| 3 | G | H1 | D | A | H1 | 3 | G | H1 | D | A | H1 |
| 4 | P4 | Q4 | R4 | S4 | T4 | | | | | | |
+-----+------+------+-------+-------+-------+-------+--------+--------+---------+---------+---------+

How to create a calculated column by comparing string values from another column in Tibco spot fire

can some one please help me to create a calculated
column as explained below?
consider the table
col1 | col2 | col3
1 | x | ER
1 | x | IG
1 | x | C
1 | y | ER
1 | y | ER
2 | y | IG
2 | y | C
2 | y | ER
2 | z | ER
2 | z | IG
I need a calculated column which says 'success' if there exists at least one 'C' on col3 for group of col1 and col2, else 'fail'.
so my new table must look like:
col1 | col2 | col3 | calculated_col
1 | x | ER | success
1 | x | IG | success
1 | x | C | success
1 | y | ER | fail
1 | y | ER | fail
2 | y | IG | success
2 | y | C | success
2 | y | ER | success
2 | z | ER | fail
2 | z | IG | fail
that is:
for the combination of 1 and 'x' from col1 and col2 respectively there is at leat one 'c' at col3, so expression result is 'success'
for the combination of 1 and 'y' from col1 and col2 respectively there is no 'c' at col3, so the expression result is 'fail'
for the combination of 2 and 'y' from col1 and col2 respectively there is at least one 'c' at col3, so expression result is 'success'
for the combination of 2 and 'z' from col1 and col2 respectively there is no 'c' at col3, so the expression result is 'fail'
you can use the Intersect OVER function to gather values in cells according to a hierarchy you define (in this case, col1>col2).
the following expression produces your desired results:
If(
Find("C", UniqueConcatenate([col3]) OVER (Intersect([col1], [col2]))) > 0,
"success","fail"
)
it's not particularly robust, however: if you have any other values in col3 that contain "C", this expression will evaluate to "success"!

Resources