Oracle Update Statement clarification required - sql

I am updating a table based on values from another table using the Serial Number field as the common field to look up values. However from below 2 queries i get two different results. Can some one explain why the two outputs are different? Should not the update statement update 47200 records?
UPDATE TBL_SERIAL_NUMBER_MASTER A
SET (A.name) = (SELECT B.name
FROM TBL_DEVICE_LOCALITY B
WHERE A.SERIAL_NUMBER = B.SERIAL_NUMBER AND ROWNUM <=1 )
WHERE EXISTS ( SELECT 1
FROM TBL_DEVICE_LOCALITY
WHERE SERIAL_NUMBER = A.SERIAL_NUMBER
AND TBL_ODIN_DEVICE_LOCALITY.HOST_NAME IS NOT NULL );
Results int: 35,311 rows updated.
select count(*)
from TBL_SERIAL_NUMBER_MASTER A, TBL_DEVICE_LOCALITY B
WHERE A.SERIAL_NUMBER = B.SERIAL_NUMBER AND B.HOST_NAME IS NOT NULL;
Returns: Count = 47200

First, you should learn to use proper explicit JOIN syntax. So, the second query should be:
select count(*)
from TBL_SERIAL_NUMBER_MASTER A JOIN
TBL_DEVICE_LOCALITY B
ON A.SERIAL_NUMBER = B.SERIAL_NUMBER
where B.HOST_NAME IS NOT NULL;
You are getting the results you see because the two queries are not the same. Your results suggests that SERIAL_NUMBER is not unique in the B table, so the JOIN is multiplying rows. On the other hand, the UPDATE is updating rows in A, regardless of the number of matches in B.
To compare like to like, use:
select count(*)
from TBL_SERIAL_NUMBER_MASTER A JOIN
TBL_DEVICE_LOCALITY B
ON A.SERIAL_NUMBER = B.SERIAL_NUMBER
where exists (select 1
from TBL_DEVICE_LOCALITY B
where B.SERIAL_NUMBER = A.SERIAL_NUMBER AND
B.HOST_NAME IS NOT NULL
);
Or, if you have a unique/primary key column in A, then you can use:
select count(distinct A.??)
from TBL_SERIAL_NUMBER_MASTER A JOIN
TBL_DEVICE_LOCALITY B
ON A.SERIAL_NUMBER = B.SERIAL_NUMBER
where B.HOST_NAME IS NOT NULL;
Where ?? is the unique/primary key column.

Related

Update column in Oracle table with value from another table with duplicates

I am trying to update the column (REPT_IND) from table A to the value in table B where A.ID = B.ID and some conditions in table B.
There are some duplicates in table B, but nonetheless the REPT_IND is the same and I still need the value.
How can I do this on Oracle? Any tips are appreciated thank you!
The Following code has the Error:
ORA-01427: single-row subquery returns more than one row
Code:
UPDATE A
SET REPT_IND= (
SELECT B.REPT_IND
FROM B
INNER JOIN A
ON B.ID = A.ID
where A.ID = B.ID
and B.job_type = 'P'
and B.FT_PT is not null
);
You can try also merge statement:
merge into a
using (
select a.id,max(b.rept_ind) rept_ind
from a left join b on a.id=b.id
where b.job_type = 'p'
and b.ft_pt is not null
) b
on (a.id=b.id)
when matched then update
set a.rept_ind=b.rept_ind;
Or if you do not want to set a.rept_ind to null if there is no relevant rows in b:
merge into a
using (
select b.id, max(b.rept_ind) rept_ind
from b
where
b.job_type = 'p'
and b.ft_pt is not null
group by b.id
) b
on (a.id=b.id)
when matched then update
set a.rept_ind=b.rept_ind;
Consider:
update a
set rept_ind= (
select max(b.rept_ind)
from b
where
a.id = b.id
and b.job_type = 'p'
and b.ft_pt is not null
);
There is no need to join table a again in the subquery - a correlation clause is enough. And you can work around possible duplicates by turning on aggregation, which guarantees that only one row will be returned.
You could also use select distinct instead of select max(...) in the subquery. This is somehow more accurate since it does ensure that the multiple rows have the same rept_ind (it they do not, then you would still get the ORA-01427 error).
Just use a correlated subquery . . . and do not repeat the table reference in the subquery:
UPDATE A
SET REPT_IND = (SELECT B.REPT_IND
FROM B
WHERE B.ID = A.ID AND
B.job_type = 'P' AND
B.FT_PT is not null AND
rownum = 1
);

select sql query to merge results

I have a table old_data and a table new_data. I want to write a select statement that gives me
Rows in old_data stay there
New rows in new_data get added to old_data
unique key is id so rows with id in new_data should update existing ones in old_data
I need to write a select statement that would give me old_data updated with new data and new data added to it.
Example:
Table a:
id count
1 2
2 19
3 4
Table b:
id count
2 22
5 7
I need a SELECT statement that gives me
id count
1 2
2 22
3 4
5 7
Based on your desired results:
SELECT
*
FROM
[TableB] AS B
UNION ALL
SELECT
*
FROM
[TableA] AS A
WHERE
A.id NOT IN (SELECT id FROM [TableB])
I think this would work pretty neatly with COALESCE:
SELECT a.id, COALESCE(b.count, a.count)
FROM a
FULL OUTER JOIN b
ON a.id = b.id
Note - if your RDBMS does not contain COALESCE, you can write out the function using CASE as follows:
SELECT a.id,
CASE WHEN b.count IS NULL THEN a.count
ELSE b.count END AS count
FROM ...
You can write a FULL OUTER JOIN as follows:
SELECT *
FROM a
LEFT JOIN b
ON a.id = b.id
UNION ALL
SELECT *
FROM b
LEFT a
ON b.id = a.id
You have to use UPSERT to update old data and add new data in Old_data table and select all rows from Old_data. Check following and let me know what you think about this query
UPDATE [old_data]
SET [count] = B.[count]
FROM [old_data] AS A
INNER JOIN [new_Data] AS B
ON A.[id] = B.[id]
INSERT INTO [old_data]
([id]
,[count])
SELECT A.[id]
,A.[count]
FROM [new_Data] AS A
LEFT JOIN [old_data] AS B
ON A.[id] = B.[id]
WHERE B.[id] IS NULL
SELECT *
FROM [old_data]

SQL Query is updating with NULL values

I am using Oracle and I am trying to update a table(A) with data from another table(B). Not every field in B has a value so I have a number of NULL entries. When I run the update it says 6000 rows updated. Now there are 6000 rows in table B, however for this query only 14 have data in. When I select count(*) from both tables for this value they both return 14 rows each. Why is it reporting that 6000 rows have been updated?
UPDATE
table1 A
SET
phone_work = (
SELECT B.phone_work
FROM table2 B
WHERE B.id = A.applicant_id)
WHERE EXISTS (
SELECT 1
FROM table2 B
WHERE B.id = A.applicant_id);
I have also tried the following and I get the same result:
UPDATE
table1 A
SET
phone_work = (
SELECT B.phone_work
FROM table2 B
WHERE B.id = A.applicant_id
AND B.phone_work is not null
)
WHERE EXISTS (
SELECT 1
FROM table2 B
WHERE B.id = A.applicant_id);
Why is it reporting the update of 6000 rows? When I change the fields but use the same syntax it reports updating of the exact number of rows I expect e.g. a count of table B has 86 entries in the NAME field and it reports 86 rows updated. It seems that with the phone_work field I am getting every null value being counted as an update.
Perhaps you want to check for the non-NULL value in the exists:
UPDATE table1 A
SET phone_work = (SELECT B.phone_work
FROM table2 B
WHERE B.id = A.applicant_id
)
WHERE EXISTS (SELECT 1
FROM table2 B
WHERE B.id = A.applicant_id AND B.phone_work IS NOT NULL
);
Try this:
UPDATE
(
SELECT A.phone_work Aphone, B.phone_work Bphone
FROM table2 B, table1 A
WHERE B.id = A.applicant_id AND B.phone_work IS NOT NULL
)
SET
Aphone = Bphone;
Source: Oracle SQL: Update a table with data from another table

Hive SQL - Refining JOIN query to ignore Null values

I'm a little new with SQL so bear with me.
I have two tables, each with an ID column. Table A has a column titled role, Table B has a column titled outcome. I want to query these tables to find which rows based on the ID have role = 'PS' and outcome = 'DE'. Here is my code:
SELECT count(*)
FROM A JOIN B
ON (A.id = B.id
AND A.role = 'PS'
AND B.outcome = 'DE')
I've been searching the internet for a way to do this so that it doesn't include rows that have null values for either A.role or B.outcome.
The above code returns lets say 40,100, even though the total number of entries in B where B.outcome = 'DE' is only 40,000. So it is obviously including entries that do not fit my conditions. Is there a way to better refine my query?
Your query already excludes rows with a null value in A.role. After all, null = 'PS' is not true, and you're using an inner join.
There's an easy explanation of how you can retrieve more rows from the join than there are in B. Say you have these rows for A:
A.id A.role
1 'A'
1 'A'
And these rows for B:
B.id B.outcome
1 'A'
1 'A'
Then this query:
select *
from A
join B
on A.id = B.id and A.role = 'A' and B.role = 'A'
will return 4 rows. That's more than there are in table A or B!
So I'd investigate whether id is unique:
select count(*) from A group by id having count(*) > 1
select count(*) from B group by id having count(*) > 1
If these queries return a count greater than zero, id is not unique. Since a join repeats rows for each match, that would explain a large increase in the amount of returned records.

Select 2 Rows from Table when COUNT of another table

Here is the code that I currently have:
SELECT `A`.*
FROM `A`
LEFT JOIN `B` ON `A`.`A_id` = `B`.`value_1`
WHERE `B`.`value_2` IS NULL
AND `B`.`userid` IS NULL
ORDER BY RAND() LIMIT 2
What it currently is supposed to do is select 2 rows from A when the 2 rows A_id being selected are not in value_1 or value_2 in B. And the rows in B are specific to individual users with userid.
What I need to do is make it also so that also checks if there are already N rows in B matching a A_id (either in value_1, or value_2) and userid, and if there are more than N rows, it doesn't select the A row.
The following would handle your first request:
Select ...
From A
Left Join B
On ( B.value_1 = A.A_id Or B.value_2 = A.A_id )
And B.userid = #userid
Where B.<non-nullable column> Is Null
Part of the trick is moving your criteria into the ON clause of the Left Join. I'm not sure how the second part of your request fits with the first part. If there are no rows in B that match on value_1 or value_2 for the given user, then by definition that row count will be zero. Is it that you want it be the situation where there can only be a maximum number of rows in B matching on the given criteria? If so, then I'd write my query like so:
Select ...
From A
Where (
Select Count(*)
From B B2
Where ( B2.value_1 = A.A_id Or B2.value_2 = A.A_id )
And B2.userid = #userid
) <= #MaxItems