Merge statement help in oracle - sql

I am using merge for the 1 st time ... I went through existing questions but couldn't get proper help.
Please help me with the below need,
I have a table "table_a" with 3 columns A, B and C. C is a new column added combination of column A and B are unique, to be specific column B is a list of sub codes taken from table_b and configured against the entity in column A.
I need to update column C with a hard coded value for the existing A and B combinations and if some subcode missing from table_b in table_a I need to insert the rows for the same in table_a.
eg. table_a
A B C
= = =
p x
p y
table_b
M
=
x
y
z
After execution of query
table_a
A B C
= = =
p x 1 -- updated with column C
p y 1 -- updated with column C
p z 1 -- new row inserted for the row in table_b
Kindly let me know if anything is not clear.

MERGE INTO table_A a
USING table_b b
ON(a.b = b.m)
WHEN MATCHED THEN
UPDATE SET a.c = 1
WHEN NOT MATCHED THEN
INSERT (a, b, c)
VALUES ('P', b.m, 1)
Note : The insert has two hardcode values for column a and column c as 'P' and 1 respectively.

If you don't want to hard-code the inserted values you can use an in-line view to generate all the expected combinations and merge against that.
merge into table_a a
using (
select t.a, b.m, 1 as c
from (select distinct a from table_a) t
cross join table_b b
) b
on (a.b = b.m)
when matched then
update set a.c = b.c
when not matched then
insert (a, b, c) values (b.a, b.m, b.c);
The using clause does a cross-join of all (distinct) table_a.a values against all table_b.m values, to give all possible combinations. (Which seems to be what you want; you haven't shown any other link between the two). I've also included the fixed value 1 in that view.
Then the merge either sets c for the rows the matching values that already exit in table_a, or inserts a new row using the values from the in-line view.
SQL Fiddle.
You might be able to get your unique a values from some other look-up table, which would be better than hitting table_a twice, but that depends on your real data model.

Related

How can I put values of a single column in a temporary table with a select statement?

I have a table with data in 2 columns. The problem is that the values in the two columns represent a table with multiple columns, where the x and y-axis are in column 1 and the values in column 2.
This is a really basic select with simple joins.
What I want to get is a simple table with the x and y-axis from column one and the values from the rows from column 2. The rows have unique id's.
This is my db table:https://imgur.com/qlwfQ7b and this is the result I'm looking for:https://imgur.com/2hbkXEr
select a.id, a.col2 as XVal, b.col2 as YVal
from table as a
INNER JOIN table as b
on a.id = b.id AND
a.col1 = 'X' AND
b.col1 = 'Y'
In effect, you self join the table on the ID. In the "left hand side" (table a), you filter to just the column 1 being X, and in the right hand side (table b) column 1 being Y.

How to get more column values along with distinct column in the Oracle database?

How to get more columns along with distinct column values in Oracle ?
select DISTINCT cname
from customer
where code is not null;
I need cname, cvalue, cdate with distinct cname
Your question does not really make sense. DISTINCT does not affect columns, it eliminates duplicate rows. So if you have:
a b c
a b c
d b c
Using DISTINCT gives you:
a b c
d b c
You're going to have to be more specific in the output you're getting and what you want.

Mapping an attribute in nvarchar to another column with int data type

I have this as legacy and it seems impossible to solve it in T-SQL ... (?).
I need to map one column of table A to another column of Table B, THIS mapping is done using a parametrization table. All 3 tables are in the same server, in the same application. The staging table is an intermediate table to receive external data, and then it will feed the final table clean, after the mapping.
Table_a (staging table)
ID NAME rack object
-----------------------------
1 x y zz:zz1
2 x y zz:zz2
table_b (clean table - BEFORE the mapping)
ID Name rack object
--------------------------
230 x y null
245 x y null
I want to achieve the next table_b after mapping.
Table_b (clean table - final table after mapping)
ID Name rack object
---------------------------
230 x y 10
245 x y 11
How to relate both tables if the Ids are different for the same Name/Rack. for example, table A has id 1 for name/Rack as x and y. The same case for the table B is under id 230.
table_parametrization
Id nameObject
---------------
10 zz:zz1
11 zz:zz2
The column object in table_a is of nvarchar type, and column object in table_b is of int type.
I do not even know how to achieve it in T-SQL.
I'm making some wild assumptions here, but I'll walk you through it.
If the connection between table_a and table_b is tenuous, and there are possible duplicate (name,rack) pairs, you might want to do the updates one at a time.
First, take the contents of your staging table and put them into a temp table. We're going to be deleting rows from the temp table during this process, so you probably don't want to do this directly with table_a. Once you have that, we're going to loop through the records with a WHILE loops, and update table_b one record at a time.
DECLARE #A_ID INT
WHILE EXISTS (SELECT TOP 1 1 FROM #table_a)
BEGIN
--Get one ID value at a time
SELECT TOP 1 #A_ID = id
FROM #table_a
--the CTE gets the first record from table_b that needs an [object] value set
;WITH Top1B AS
(
SELECT TOP 1 b.id, objectId = p.id
FROM #table_b b
INNER JOIN #table_a a ON a.[name] = b.[name] AND a.rack = b.rack
INNER JOIN #table_param p ON p.nameObject = a.object
WHERE a.id = #A_ID
AND b.object IS NULL
)
UPDATE b
SET b.[object] = tb.objectId
FROM Top1B tb
INNER JOIN #table_b b ON b.id = tb.id
--remove the record from the staging table
DELETE #table_a
WHERE id = #A_ID
END
Assuming that your table_b.ID attribute is an IDENTITY, and are automatically generated, you need to JOIN table_a to table_parameterization using the object. You'll get the values to insert into B using something like this:
SELECT
a.Name,
a.rack,
p.ID
FROM table_a_staging a
INNER JOIN table_parametrization p ON
a.object = p.nameObject

Oracle SQL to subtract 2 values from different table joins

I am trying to subtract sequences MN_SEQ from Table C generated based on join with other tables.
Here is the problem.
Query 1 -
Select M_Seq from Table C, Table A, Table B where C.date_sk=A.MTH_END_DT
and B.Loan_seq=A.Loan_seq
Query 2 -
Select M_Seq from Table C, Table B where C.date_sk=B.ORIG_DT
I have to get difference between 2 M_SEQ generated from the result set of query 1 and Query 2.
Below is what i tried, but I am getting error.
select mn_seq -mn_seq from
((select mn_seq from Table C, Table A, Table B where B.MTH_END_DT=C.DATE_SK and B.LOAN_SEQ=A.LOAN_SEQ)a,
(select mn_seq from Table C , Table B where B.ORIG_DT=C.DATE_SK
)b)
T
Kindly provide inputs . I am not sure if this is the right way to do it. I tried just using "-" between queries but didnt work. Thanks!
Try this..
SELECT (SELECT mn_seq
FROM TABLE c, TABLE a, TABLE b
WHERE b.mth_end_dt = c.date_sk
AND b.loan_seq = a.loan_seq) -
(SELECT mn_seq FROM TABLE c, TABLE b WHERE b.orig_dt = c.date_sk)
FROM dual
I assume both the mn_seq are NUMBER and also your WHERE clause returns only one record in each of the inner queries.

SQL Insert into table A from table B based off table C

I have an empty table that I would like to fill with rows from a second table, based off a third table, Ill call them A,B,C respectively.
Table C has ID numbers that match ID numbers for rows in Table B. For every ID in table C, I want to add the corresponding row from table B into Table A.
This is what I have, and I am getting an error saying that I cannot use the last statement.
INSERT INTO TABLEA
SELECT * FROM TABLEB
WHERE ID FROM TABLEB = ID FROM TABLEC;
DSNT408I SQLCODE = -199, ERROR: ILLEGAL USE OF KEYWORD FROM. TOKEN ( . AT
MICROSECONDS MICROSECOND SECONDS SECOND MINUTES MINUTE WAS EXPECTED
DSNT418I SQLSTATE = 42601 SQLSTATE RETURN CODE
Any help would be appreciated.
INSERT INTO TableA
SELECT B.*
FROM TableB AS B
JOIN TableC AS C ON B.ID = C.ID
Or possibly that will give you too many duplicates (if there are multiple rows in C that match a given row in B), in which case you might need:
INSERT INTO TableA
SELECT B.*
FROM TableB AS B
WHERE B.ID IN (SELECT C.ID FROM TableC AS C)
Or:
INSERT INTO TableA
SELECT DISTINCT B.*
FROM TableB AS B
JOIN TableC AS C ON B.ID = C.ID
Both of those give you one row in A for each row in B that matches one or more rows in C.
How would I add a WHEN clause to this? Let's say Table C has another column called VALUE, and I want to add all the ID numbers that have a value of 'x' or greater. How would I do that, I tried adding JOIN TableC AS C ON B.ID = C.ID AND C.VALUE > 5 but I still got all the values from TABLE C.
Working with the first query (fixing the others being left as an 'exercise for the reader'), then what I think you should be doing is just:
INSERT INTO TableA
SELECT B.*
FROM TableB AS B
JOIN TableC AS C ON B.ID = C.ID
WHERE C.Value > 5
The optimizer should translate that to an equivalent expression:
INSERT INTO TableA
SELECT B.*
FROM TableB AS B
JOIN TableC AS C ON B.ID = C.ID AND C.Value > 5
I'm not clear from your comment whether you somehow added a second reference to TableC in the one query, or you modified your query as shown in this second example. If you were not using LEFT JOIN anywhere, then adding the AND C.Value > 5 term to the ON clause or as a WHERE clause should have yielded the correct data.
When debugging this sort of problem, it is worth noting that this INSERT statement has a perfectly good SELECT statement in it that you can run on its own to review what is going to be added to TableA. You might want to augment the select-list to include (at least) C.ID and C.Value just to make sure nothing is going haywire.