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

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);

Related

Update rows with previous rows

I have a table with a column 'id' which is autoincrement. In some records i have zero values. I want to update them by their previous rows (here previous means id - 1) .
How can i do that?
This query returns those records with zero values:
SELECT * FROM myTable
WHERE col1 = 0
which returns:
id col1 col2 ..... coln
15 0 0 0
23 0 0 0
You could use a correlated subquery:
update mytable t
set col1 = (select t1.col1 from mytable t1 where t1.id = t.id - 1)
where col1 = 0

Get record with a field egal to a specific value else with null

I want in SQL : if a field is equal to a specific value, I want this record if not I want the record with this field equal to null.
I can try to that:
SELECT TOP 1 COL1, COL2, COL3
FROM TABLE1 WHERE (COL2 = MY_SPECIFIC_VALUE OR COL2 IS NULL) AND COL3 = '42'
AND COL1 = 3
But, what is the result returned? The smallest id? Or it is not specified?
Assuming that this is the real question:
If a field is equal to a specific value, I want this record if not I want the record with this field equal to null.
You can do this as:
SELECT TOP 1 COL1, COL2, COL3
FROM TABLE1
WHERE (COL2 = MY_SPECIFIC_VALUE or COL2 IS NULL) AND
COL3 = '42' AND COL1 = 3
ORDER BY (CASE WHEN COL2 = MY_SPECIFIC_VALUE THEN 1 ELSE 2 END);

Update target table only if its not null

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.

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)

Find records with column containing specific values

I think my question really boils down do doing a sql IN on multiple values.
Here's a SQL Fiddle of what I have so far.
So long story short, I have Cases that have multiple Types.
I need to filter Cases containing certain Types
Say I have 6 rows (col1,col2)... (1,2),(1,3)(1,4),(2,3),(2,4),(2,5)
How do I select only Cases that have 2, AND 3 AND 4 in col2?
2,3,4 is just a use case. It could be just about any combination (the SQL Fiddle has a couple tables that determine this).
Try:
select [CaseId]
from CaseTypes
where [TypeID] in (2,3,4)
group by [CaseId]
having count(distinct [TypeID]) = 3
(SQLFiddle here)
Couple of things you might try:
Using Derived Tables:
SELECT a.col1
FROM (SELECT col1 FROM Cases WHERE col2 = 2) a
INNER JOIN (SELECT col1 FROM Cases WHERE col2 = 3) b ON a.col1 = b.col1
INNER JOIN (SELECT col1 FROM Cases WHERE col2 = 4) c ON a.col1 = c.col1
Using Aggregation:
SELECT col1
FROM Cases
GROUP BY col1
HAVING
SUM(CASE col2 WHEN 2 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE col2 WHEN 3 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE col2 WHEN 4 THEN 1 ELSE 0 END) > 0
is this a bit closer?
SELECT * from CaseTypes CT
INNER JOIN TypeBillable TB ON CT.TypeId = TB.TypeId
where CT.CaseId in
(
select CaseID from CaseTypes
PIVOT (count (TypeId) for TypeId in ([2],[3],[4])) as x
where [2] > 0 and [3] > 0 and [4] > 0
)