Update target table only if its not null - sql

I have a scenario, where we want to update 40 columns in oracle table. source is another oracle table.
They want to igonore the value of the column if it have null !!
example:
col1 col2 col3
1 null b
2 null 3
target table :
col1 col2 col3
1 a null
2 b null
after updted.
col1 col2 col3
1 a b
2 b 3
note : we have to upate only if its not null ..
any advise is appreciated.

update target_table tt
set (col1, col2, col3) = ( select nvl(st.col1,tt.col1),
nvl(st.col2,tt.col2),
nvl(st.col3,tt.col3)
from source_table st where st.primary_key = tt.primary_key )
where exists ( select null
from source_table st
where st.primary_key = tt.primary_key
and (st.col1 is not null
or st.col2 is not null
or st.col3 is not null) );
Obviously you have to determine what the primary key is. I used "primary_key" only as an instructive guide.

Try
MERGE INTO TARGET_TABLE t
USING SOURCE_TABLE s
ON (s.COL1 = t.COL1)
WHEN MATCHED THEN
UPDATE SET t.COL2 = NVL(t.COL2, s.COL2)
t.COL3 = NVL(t.COL3, s.COL3);
I'm assuming here the COL1 is the column to use to find matching rows in TARGET_TABLE and SOURCE_TABLE.
Share and enjoy.

Related

Does Oracle MERGE Handles Table Join Automatically?

I am new to ORACLE MERGE Command.
I intend to insert a row into a target table based on a source table data.
The source table has Foreign Key Relation to Target Table. Column1 and Column2 in source table must exist to allow a row with those values in Target Table.
My Merge query looks like this.
MERGE into TARGET_TABLE target
USING (
Select column1, column2 from SOURCE_TABLE where column3='somevalue'
) source
ON (
source.column1 is null or target.column4='anotherValue'
)
WHEN NOT MATCHED THEN INSERT (
target.column1,
target.column2,
target.column3,
target.column4
) VALUES (
source.column1,
source.column2,
'somevalue3',
'anotherValue'
)
It inserts one row and only when it finds that source.column1 is existing for the source.column3 value of 'somevalue' ie not null and,
there is no row in target table whose column1, column2 and column 4 have following values respectively
Same value of column1 in source table when column3 is 'someValue'
Same value of column2 in source table when column3 is 'someValue'
'anotherValue'
I need an explanation as to why it matches Point1 and Point2 above even though my MATCH conditions in 'ON' clause does not include them.
When I coded this I expected multiple rows to NOT MATCH the condition since there are many rows in target table where column4 does not has value anotherValue.
ATTEMPT TO ELABORATE # 1
TABLE 1 (SOURCE)
COL1 COL2 COL3
a1 a2 a3
TABLE 2 (TARGET)
COL1 COL2 COL3 COL4
No row
DESIRED Behavior:
Insert a row in TABLE 2
if source table has a row where COL3 = 'a3' and
if there is no row in target with col1 = a1 and col2 = a2 and col4 = b4
Data to be inserted in Target table is: col1 = a1, col2 = a2 and col4 = b4
OBSERVED BEHAVIOR
Matches the desired behavior above which surprised me. I wondered that I need to have an ON CLAUSE Like this
ON (
source.column1 is null or source.column1 != target.column1 or source.column2 != target.column2 or target.column4 = 'anotherValue'
)
Based on DEMorgan's law:
NOT (A and B) = NOT A or NOT B;
NOT (A OR B ) = NOT A and NOT B

SQL: Select the minimum value from multiple columns with null values

I have a table like this one
ID Col1 Col2 Col3
-- ---- ---- ----
1 7 NULL 12
2 2 46 NULL
3 NULL NULL NULL
4 245 1 792
I wanted a query that yields the following result
ID Col1 Col2 Col3 MIN
-- ---- ---- ---- ---
1 7 NULL 12 7
2 2 46 NULL 2
3 NULL NULL NULL NULL
4 245 1 792 1
I mean, I wanted a column containing the minimum values out of Col1, Col2, and Col 3 for each row ignoring NULL values. In a previous question (What's the best way to select the minimum value from multiple columns?) there is an answer for non NULL values. I need a query as efficient as possible for a huge table.
Select Id,
Case When Col1 < Col2 And Col1 < Col3 Then Col1
When Col2 < Col1 And Col2 < Col3 Then Col2
Else Col3
End As MIN
From YourTableNameHere
Assuming you can define some "max" value (I'll use 9999 here) that your real values will never exceed:
Select Id,
Case When Col1 < COALESCE(Col2, 9999)
And Col1 < COALESCE(Col3, 9999) Then Col1
When Col2 < COALESCE(Col1, 9999)
And Col2 < COALESCE(Col3, 9999) Then Col2
Else Col3
End As MIN
From YourTableNameHere;
You didn't specify which version of Teradata you're using. If you're using version 14+ then you can use least.
Unfortunately least will return null if any of its arguments are null. From the docs:
LEAST supports 1-10 numeric values.
If numeric_value is the data type of the first argument, the return
data type is numeric. The remaining arguments in the input list must
be the same or compatible types. If either input parameter is NULL,
NULL is returned.
But you can get around that by using coalesce as Joe did in his answer.
select id,
least(coalesce(col1,9999),coalesce(col2,9999),coalesce(col3,9999))
from mytable
This might work:
Select id, Col1, Col2, Col3, least(Col1, Col2, Col3) as MIN From YourTableNameHere
in this way you don't need to check for nulls, just use min and a subquery
select tbl.id,tbl.col1,tbl.col2,tbl.col3,
(select min(t.col)
from (
select col1 as col from tbl_name t where t.id=tbl.id
union all
select col2 as col from tbl_name t where t.id=tbl.id
union all
select col3 as col from tbl_name t where t.id=tbl.id
)t)
from tbl_name tbl
Output:
1 7 NULL 12 7
2 2 46 NULL 2
3 NULL NULL NULL NULL
4 245 1 792 1
Just modify your query with coalesce():
Select Id,
(Case When Col1 <= coalesce(Col2, col3, col1) And
Col1 <= coalesce(Col3, col2, col1)
Then Col1
When Col2 <= coalesce(Col1, col3, col2) And
Col2 <= coalesce(Col3, col1, col2)
Then Col2
Else Col3
End) As MIN
From YourTableNameHere;
This doesn't require inventing a "magic" number or over-complicating the logic.
I found this solution to be more efficient than using multiple case statement clauses, which can get extremely lengthy when evaluating data from several columns across one row.
Also, I can't take credit for this solution as I found it on some website a year or so ago. Today I needed a refresh on this logic, and I couldn't find it anywhere. I found my old code and decided to share it in this forum now.
Creating your test table:
create table #testTable(ID int, Col1 int, Col2 int, Col3 int)
Insert into #testTable values(1,7,null,12)
Insert into #testTable values(2,2,46,null)
Insert into #testTable values(3,null,null,null)
Insert into #testTable values(4,245,1,792)
Finding min value in row data:
Select ID, Col1, Col2, Col3 ,(SELECT Min(v) FROM ( VALUES (Col1), (Col2), (Col3) ) AS value(v)) [MIN] from #testTable order by ID

SQL Server Select a row for where a column value does not exists

I have a table as
COl1____COL2____COL3
1_________1_____val1
1_________2_____val2
1_________3_____val3
2_________1_____val1
2_________2_____val2
2_________3_____val3
3_________1_____val1
3_________2_____val2
3_________4_____val4
No I want to have unique values from COL1 such that it should only show me COL1 value that does not have a value "3" under COL2
i.e. I want a query to return me
Result
3
Any help is much appreciated
SELECT col1
FROM YourTable
EXCEPT
SELECT col1
FROM YourTable
WHERE col2 = 3
Or
SELECT col1
FROM YourTable
GROUP BY col1
HAVING MAX(CASE
WHEN Col2 = 3 THEN 1
ELSE 0
END) = 0
select col1
from Tab
where col1 not in (select col1 from tab where col2 = 3)

Messing with 'when not matched' in SQL (how to merge properly)

I'm creating several tables and merging data from them into one. These tables have similar columns col1 and col2 but the values in these columns can be different, ex. col1 on row 1 from tab1 may have "0" and col1 from tab2 may have on the same row in col1 "1". ONLY in this case I need to update the value from tab1 in col1 on the row 1. Take a look at the following example:
BEFORE MERGING
tab1:
id col1 col2
1 0 0
2 0 1
3 0 0
AFTER MERGING WITH tab2
tab2: tab1:
id col1 col2 id col1 col2
1 1 0 ---> 1 1 0
2 0 0 2 0 1
3 0 0 3 0 0
For that purpose I use the following query:
merge into tab1 st
using (select id, col1, col2 from tab2) ss
ON (st.id=ss.id)
when matched then
update set st.col1 = ss.col1,
st.col2 = ss.col2
where ss.col1 != 0 or ss.col2 != 0
when not matched then
insert (st.id, st.col1, st.col2)
values (ss.id, ss.col1, ss.col2)
;
I'm just learning sql so only now I noticed that this query is not correct. It can overwrite the "1" value in the tab1 with "0" coming from tab2. Help me to improve this query please, I'm stuck.
You can use a CASE expression when setting the values to control which value gets assigned. Try something like:
merge into tab1 st
using (select id, col1, col2 from tab2) ss
ON (st.id=ss.id)
when matched then
update set st.col1 = CASE WHEN st.col1 = 0 THEN ss.col1 ELSE st.col1 END,
st.col2 = CASE WHEN st.col2 = 0 THEN ss.col2 ELSE st.col2 END
where ss.col1 != 0 or ss.col2 != 0
when not matched then
insert (st.id, st.col1, st.col2)
values (ss.id, ss.col1, ss.col2)
;
Thus in the WHEN MATCHED situation, if the value from tab1 (st) is zero you change it to the value from tab2 (ss), otherwise you just set the value from tabl1 to itself.
Share and enjoy.
You should update with the max of {ss.coln, st.coln}. For example, using GREATEST:
MERGE INTO tab1 st
USING (SELECT id, col1, col2 FROM tab2) ss
ON (st.id = ss.id)
WHEN MATCHED THEN
UPDATE
SET st.col1 = greatest(ss.col1, st.col1),
st.col2 = greatest(ss.col2, st.col2)
WHERE ss.col1 > st.col1
OR ss.col2 > st.col2
WHEN NOT MATCHED THEN
INSERT (st.id, st.col1, st.col2)
VALUES (ss.id, ss.col1, ss.col2);

how to select col1 value x and copy to new row with col1 value y,if run query again,should not copy again

how to copy rows to same table where select column1 value = 55 and to new row with column 1 value = 56, if we run query second time, it should not copy the old lines again
You could add a where clause to prevent a duplicate insert using not exists:
insert YourTable
(col1, col2, col3, ...)
select 56 -- New value
, col2
, col3
, ...
from YourTable
where col1 = 55 -- Old value
and not exists
(
select *
from YourTable
where col1 = 56 -- New value
)