How to insert type when join 2 table with scd informatica - informatica-powercenter

I have 2 source tables:
table A: table B:
A_id || A_code B_id || B_code
----- ------- ----- -------
2 t2 1 t1
3 t3 2 t2
4 t4 3 t3
I want to join 2 table use Slowly change dimension
target table:
tgt_id || tgt_code || is_table A || is_table B
----- ------------ ----------- -----------
1 t1 0 x
2 t2 x x
3 t3 x x
4 t4 x 0
I can't check type 'is_table A ' and 'is_table B' when join table.

If I understand correctly, you need to do a full outer join (in SQ or Joiner) on A_id=B_id. Then you can derive the target fields in an expression transformation by doing some null checking as follows:
tgt_id: IIF(ISNULL(A_id),B_id, A_id)
tgt_code: IIF(ISNULL(A_code), B_code, A_code)
is_table_A: IIF(ISNULL(A_id),'0','x')
is_table_B: IIF(ISULL(B_id), '0', 'x')

Related

Oracle: How functional table works in cross join?

I explored technique to unfold comma separated list in column into rows:
with tbl as (
select 1 id, 'a,b' lst from dual
union all select 2 id, 'c' lst from dual
union all select 3 id, 'e,f,g' lst from dual)
select
tbl.ID
, regexp_substr(tbl.lst, '[^,]+', 1, lvl.column_value) elem
, lvl.column_value lvl
from
tbl
, table(cast(multiset(
select level from dual
connect by level <= regexp_count(tbl.lst, ',')+1) as sys.odcinumberlist)) lvl;
Result is:
ID ELEM LVL
1 a 1
1 b 2
2 c 1
3 e 1
3 f 2
3 g 3
As you can see LVL depends on value of regexp_count, so second functional table in cross join is parametrized by first table.
How is it working? How is it called? Can I paramertize third table based on two preceding in cross join and so forth?
Is parametrization limited to cross join or can be applied in join syntax too?
Reference: Splitting string into multiple rows in Oracle
From the documentation:
LATERAL
Specify LATERAL to designate subquery as a lateral inline
view. Within a lateral inline view, you can specify tables that appear
to the left of the lateral inline view in the FROM clause of a query.
You can specify this left correlation anywhere within subquery (such
as the SELECT, FROM, and WHERE clauses) and at any nesting level.
-- a variation of the query in your question ...
select
dt.id
, dt.list
, regexp_substr( dt.list, '[^,]+', 1, dt2.lvl ) elements
, dt2.lvl
from (
select 1 id, 'a,b' list from dual union all
select 2, 'c' from dual union all
select 3, 'e,f,g' from dual
) dt, lateral (
select level lvl from dual
connect by level <= regexp_count(dt.list, ',') + 1
) dt2
;
-- output
ID LIST ELEMENTS LVL
1 a,b a 1
1 a,b b 2
2 c c 1
3 e,f,g e 1
3 e,f,g f 2
3 e,f,g g 3
Example with 3 tables:
--drop table t1 ;
--drop table t2 ;
--drop table t3 ;
-- tables/data
create table t1
as
select 1 id, 'a' letter from dual union all
select 2, 'b' from dual union all
select 3, 'c' from dual ;
create table t2
as
select 1 id, 'd' letter from dual union all
select 2, 'e' from dual union all
select 3, 'f' from dual ;
create table t3
as
select 1 id, 'g' letter from dual union all
select 2, 'h' from dual union all
select 3, 'i' from dual ;
-- query
select *
from
t1
, lateral ( select letter from t2 where id = t1.id ) t2
, lateral ( select letter from t3 where id = t2.id )
;
-- output
ID LETTER LETTER LETTER
1 a d g
2 b e h
3 c f i
Also (using the same tables)
-- reference t1 <- t2,
-- reference t1 and t2 <- t3
select *
from
t1
, lateral ( select letter from t2 where id = t1.id ) t2
, lateral ( select letter || t1.letter from t3 where id = t2.id )
;
-- output
ID LETTER LETTER LETTER||T1.LETTER
1 a d ga
2 b e hb
3 c f ic
Whereas a "standard" cross join would give us ...
select *
from
t1 cross join t2 cross join t3
;
ID LETTER ID LETTER ID LETTER
1 a 1 d 1 g
1 a 1 d 2 h
1 a 1 d 3 i
1 a 2 e 1 g
1 a 2 e 2 h
1 a 2 e 3 i
...
-- 27 rows
Related topics: CROSS APPLY (see documentation and examples here).

Select an included values

I'm using Oracle SQL and i need help with a query. Hope it's not too much easy one. I did't find an answer for it in Google.
I have a table that need to be aggregated by ID column and then to select only the records that two values are included in a certain table (and both of them).
Table for example
ID | Value
1 | Y
1 | N
2 | N
2 | N
2 | Y
3 | Y
3 | Y
4 | Y
5 | Y
5 | N
5 | Y
5 | N
The output table need to include only the IDs that both Y and N are included in Value table. Output:
ID
1
2
5
Another solution that groups by the ID and uses HAVING to return only those with > 1 DISTINCT values:
with v_data(id, value) as (
select 1, 'Y' from dual union all
select 1, 'N' from dual union all
select 2, 'Y' from dual)
select id
from v_data
group by id
having count(distinct value) > 1
select distinct a.id
from your_table a inner join your_table b on a.id = b.id and a.value != b.value;

Build dynamic query in oracle

Could you help me building a query as below?
TABLE_A
id brand color size model yn_buy
1 A blue M A -
2 A grey X C -
3 B red X B -
4 C blue S C -
TABLE_B
brand critery
A color=grey and size=X
B color=red
C size=M
I want to build a query to update table A and the answer should be:
TABLE_A
id brand color size model yn_buy
1 A blue M A N
2 A grey X C Y
3 B red X B Y
4 C blue S C N
As you can see the data on the column "critery" should be the decisor to buy or not
I'd like to use a single merge, like the following
merge into TABLE_A a
using
(
select id, brand, CASE WHEN critery THEN 'Y' ELSE 'N' END yn_buy
TABLE_A a
left join TABLE_B b ON a.brand = b.brand
) b
ON (a.id = b.id)
WHEN MATCHED THEN UPDATE set a.yn_buy = b.yn_buy
Is it possible to do something like this? maybe using execute immediate, some kind of bind...?
thank you
If I don't miss something in your particular case you don't need dynamic SQL - you can simply change TABLE_B structure and use static MERGE (because I don't know how complex your criteria can be this is just an illustration):
SQL> create table table_a (id, brand, color, size#, model#, tn_buy) as
2 select 1, 'A', 'blue', 'M', 'A', cast(null as varchar2(3)) from dual union all
3 select 2, 'A', 'grey', 'X', 'C', cast(null as varchar2(3)) from dual union all
4 select 3, 'B', 'red', 'X', 'B', cast(null as varchar2(3)) from dual union all
5 select 4, 'C', 'blue', 'S', 'C', cast(null as varchar2(3)) from dual
6 /
Table screated.
SQL> create table TABLE_B (brand, color, size#)
2 as
3 select 'A', 'grey', 'X' from dual union all
4 select 'B', 'red', null from dual union all
5 select 'C', null, 'M' from dual
6 /
Table created.
SQL> merge into TABLE_A a USING (
2 select a.id, a.brand, CASE
3 WHEN a.color = nvl(a.color, a.color) and a.size# = nvl(b.size#,a.size#)
4 THEN 'Y' ELSE 'N' END yn_buy FROM
5 TABLE_A a
6 left join TABLE_B b ON a.brand = b.brand
7 ) b
8 ON (a.id = b.id)
9 WHEN MATCHED THEN UPDATE set a.yn_buy = b.yn_buy
10 /
4 rows merged.
SQL> select * from table_a order by id;
ID B COLO S M YN_
---------- - ---- - - ---
1 A blue M A N
2 A grey X C Y
3 B red X B Y
4 C blue S C N
But of your criteria are difficult enough to be implemented using simple static condition, then you can use dynamic SQL:
SQL> create table TABLE_B1 (brand, criteria)
2 as
3 select 'A', q'[color='grey' and size# in ('X','M')]' from dual union all
4 select 'B', q'[color = 'red']' from dual union all
5 select 'C', q'[size#='M']' from dual
6 /
Table created.
SQL> update table_a set yn_buy = null;
4 rows updated.
SQL> commit;
Committed.
SQL> begin
2 for cur in (select brand, criteria from table_b1) loop
3 execute immediate
4 'update table_a set yn_buy = case when '||cur.criteria||
5 q'[ then 'Y' else 'N' end where brand = :1]' using cur.brand;
6 end loop;
7 end;
8 /
PL/SQL procedure completed.
SQL> select * from table_a;
ID B COLO S M YN_
---------- - ---- - - ---
1 A blue M A N
2 A grey X C Y
3 B red X B Y
4 C blue S C N

CONNECT BY for two tables with two JOINS

I have 3 tables:
two with hierarchical structures
(like "dimensions" of recursive type of hierarchy);
one with summing data (like "facts" with X column).
They are here:
DIM1 (ID1, PARENT2, NAME1)
DIM2 (ID2, PARENT2, NAME2)
FACTS (ID1, ID2, X)
Example of DIM1 table:
-- 1 0 DIM1
---- 2 1 DIM1-A
------ 3 2 DIM1-A-A
-------- 4 3 DIM1-A-A-A
-------- 5 3 DIM1-A-A-B
------ 6 2 DIM1-A-B
-------- 7 6 DIM1-A-B-A
-------- 8 6 DIM1-A-B-B
------ 9 2 DIM1-A-C
---- 10 1 DIM1-B
------ 11 10 DIM1-B-C
------ 12 10 DIM1-B-D
---- 13 1 DIM1-C
Example of DIM2 table:
-- 1 0 DIM2
---- 2 1 DIM2-A
------ 3 2 DIM2-A-A
-------- 4 3 DIM2-A-A-A
-------- 5 3 DIM2-A-A-B
-------- 6 3 DIM2-A-B-C
------ 7 2 DIM2-A-B
---- 8 1 DIM2-B
---- 9 1 DIM2-C
Example of FACTS table:
1 1 100
1 2 30
1 3 500
-- ................
13 9 200
And I would like to create the only SELECT where I will specify the parent for DIM1 (for example ID1=2 for DIM1-A) and parent for DIM2 (for example ID2=2 for DIM2-A) and SELECT will generate a report like this:
Name_of_1 Name_of_2 Sum_of_X
--------- --------- ----------
DIM1-A-A DIM2-A-A (some sum)
DIM1-A-A DIM2-A-B (some sum)
DIM1-A-B DIM2-A-A (some sum)
DIM1-A-B DIM2-A-B (some sum)
DIM1-A-C DIM2-A-A (some sum)
DIM1-A-C DIM2-A-B (some sum)
I would like to use CONNECT BY phrase, START WITH phrase, SUM phrase, GROUP BY phrase, and OUTER or INNER (?) JOIN. I need no other extensions of Oracle 10.2.
In other words: only with "classic" SQL and
only Oracle extensions for hierarchy queries.
Is it possible?
I tried some experiments with question in
Mixing together Connect by, inner join and sum with Oracle
(where is a very nice solution but only for one
dimension table ("Tasks"), but I need to JOIN two dimension tables to one facts table), but I was not successful.
"Some sum" is not very descriptive, so I don't see why do you need CONNECT BY at all.
SELECT dim1.name, dim2.name, x
FROM (
SELECT id1, id2, SUM(x) AS x
FROM facts
GROUP BY
id1, id2
) f
JOIN dim1
ON dim1.id = f.id1
JOIN dim2
ON dim2.id = f.id2
I think what you're trying to do is get the sum of the value in the facts table for all of the children of the specified rows grouped by the topmost children. This would mean that in your example above, the results for the first row would be the sum any intersections of (DIM1-A-A, DIM1-A-A-A, DIM1-A-A-B) and (DIM2-A-A, DIM2-A-A-A, DIM2-A-A-B, DIM3-A-A-C) found in the FACTS table. With that assumption, I have come to the following solution:
SELECT root_name1, root_name2, SUM(X)
FROM ( SELECT CONNECT_BY_ROOT(name1) AS root_name,
id1
FROM dim1
CONNECT BY parent1 = PRIOR id1
START WITH parent1 = 2) d1
CROSS JOIN
( SELECT CONNECT_BY_ROOT(name2) AS root_name,
id2
FROM dim2
CONNECT BY parent2 = PRIOR id2
START WITH parent2 = 2) d2
LEFT OUTER JOIN
facts
ON d1.id1 = facts.id1
AND d2.id2 = facts.id2
GROUP BY root_name1, root_name2
(This also assumes that the columns of FACTS are named ID1, ID2, and X.)

Fix numbering of many item groups in table

I have a table with these columns
create table demo (
ID integer not null,
INDEX integer not null,
DATA varchar2(10)
)
Example data:
ID INDEX DATA
1 1 A
1 3 B
2 1 C
2 1 D
2 5 E
I want:
ID INDEX DATA
1 1 A
1 2 B -- 3 -> 2
2 1 C or D -- 1 -> 1 or 2
2 2 D or C -- 1 -> 2 or 1
2 3 E -- 5 -> 3 (closing the gap)
Is there a way to renumber the INDEX per ID using a single SQL update? Note that the order of items should be preserved (i.e. the item "E" should still be after the items "C" and "D" but the order of "C" and "D" doesn't really matter.
The goal is to be able to create a primary key over ID and INDEX.
If that matters, I'm on Oracle 10g.
MERGE
INTO demo d
USING (
SELECT rowid AS rid, ROW_NUMBER() OVER (PARTITION BY id ORDER BY index) AS rn
FROM demo
) d2
ON (d.rowid = d2.rid)
WHEN MATCHED THEN
UPDATE
SET index = rn

Resources