How to select a value that can come from two different tables? - sql

First, SQL is not my strength. So I need help with the following problem. I'll simplify the table contents to describe the problem.
Let's start with three tables : table1 with columns id_1 and value, table2 with columns id_2 and value, and table3 with columns id_3 and value. As you'll notice, a field value appears in all three tables, while ids have different column names. Modifying column names is not an option because they are used by Java legacy code.
I need to set table3.value using table1.value or table2.value according to the fields table1.id_1, table2.id_2 and table3.id_3.
My last attempt, which describes what I try to do, is the following:
UPDATE table3
SET value=(IF ((SELECT COUNT(\*) FROM table1 t1 WHERE t1.id_1=id_3) > 0)
SELECT value FROM table1 t1 WHERE t1.id_1=id_3
ELSE IF ((SELECT COUNT(\*) FROM table2 t2 WHERE t2.id_2=id_3)) > 0)
SELECT value FROM table2 t2 WHERE t2.id_2=id_3)
Here are some informations about the tables and the update.
This update will be included in an XML file used by Liquibase.
It must work with Oracle or SQL Server.
An id from table3.id_3 can be found at most once in table1.id_1 or in table2.id_2, but not in both tables simultaneously.
If table3.id_3 is not found in table1.id_1 nor in table2.id_2, table3.value remains null.
As you can imagine, my last attempt failed. In that case, the IF command was not recognized during the Liquibase update. If anyone has any ideas how to deal with this, I'd appreciate. Thanks in advance.

I don't know Oracle very well, but a SQL Server approach would be the following using COALESCE() and OUTER JOINs.
Update T3
Set Value = Coalesce(T1.Value, T2.Value)
From Table3 T3
Left Join Table2 T2 On T3.Id_3 = T2.Id_2
Left Join Table1 T1 On T3.Id_3 = T1.Id_1
The COALESCE() will return the first non-NULL value from the LEFT JOIN to tables 1 and 2, and if a record was not found in either, it would be set to NULL.

It is Siyual's UPDATE written with MERGE operator.
MERGE into table_1
USING (
SELECT COALESCE(t2.value, t3.value) as value, t1.id_1 as id
FROM table_1 t1, table_2 t2, table_3 t3
WHERE t2.id_2 = t3.id_3 and t1.id_1 = t2.id_2
) t on (table_1.id_1 = t.id)
WHEN MATCHED THEN
UPDATE SET table_1.value = t.value
This should work in Oracle.

In Oracle
UPDATE table3 t
SET value=COALESCE((SELECT value FROM table1 t1 WHERE t1.id_1=t.id_3),
(SELECT value FROM table2 t2 WHERE t2.id_2=t.id_3))

Given your assumption #3, you can use union all to put together tables 1 and 2 without running the risk of duplicating information (at least for the id's of interest). So a simple merge solution like the one below should work (in all DB products that implement the merge operation).
merge into table3
using (
select id_2 as id, value from table2
union all
select id_3, value from table 3
) t
on table3.id_3 = t.id
when matched
then update set table3.value = t.value;
You may want to test the various solutions and see which is most effective for your specific tables.
(Note: merge should be more efficient than the update solution using coalesce, at least when relatively few of the id's in table3 have a match in the other tables. This is because the update solution will re-insert NULL where NULL was already stored when there is no match. The merge solution avoids this unnecessary activity.)

Related

Merge into Table1 using table2, table3 on (multiple conditions)? Missing syntax

I have table1, table2 and table3,
they have a join condition that relates between them.
suppose it is the (ID) column.
So the question is,
in the case of using the merge statement, is it possible
to construct the syntax to be like this:
Merge into Table1
using table2 , table3
on (table1.ID = Table2.ID , Table2.ID = Table.ID)
when match then
update --(definitly table1)
where
table1.something between table2.something and table2.something -- whatever :)
when not match then
do_nothing --I think I should type NULL here
if this syntax is wrong, how should I call two tables and using them to update a row in table1?
how should I call two tables and using them to update a row in table1?
This can be achieved in several ways in Oracle :
correlated subquery
inline view
merge query
The following code gives a raw, commented example of the third solution (merge statement). As you did not show us your exact SQL attempt and the structure of your tables, you will have to adapt this to your exact use case :
MERGE INTO table1 target
-- prepare the dataset to use during the UPDATE
USING (
SELECT
-- following fields will be available in the UPDATE
t1.id,
t2.foo,
t3.bar
FROM
-- JOIN conditions between the 3 tables
table1 t1
INNER JOIN table2 t2 on t2.id = t1.id
INNER JOIN table3 t3 on t3.id = t1.id
WHERE
-- WHERE clause (if needed)
t1.zoo = 'blah'
) source
-- search records to UPDATE
ON (target.id = source.id)
WHEN MATCHED THEN
UPDATE SET
-- UPDATE table1 fieds
target.value1 = source.foo,
target.value2 = source.foo
;
Note : while this query makes use of the Oracle MERGE statement, it conceptually does not implement a real merge operation. The concept of a merge is an update/insert query, whereas this query only does an update, and ignores the insert part. Still, this is one of the simplest way to perform such a correlated update in Oracle...

I am trying to update a column of a table of a database from a column of different table of different database

update table1
set table1.col1=(select t2.c2 as X from t2#dblink)
where t1.c2=(select t3.c3,t3.c4,t3.c5 from t3#dblink)
but i am getting
ORA-01427: single-row subquery returns more than one row
can someone help me out with this.
As you were told, sample data would help, as well as posting consistent information (you are updating TABLE1 and, later, use T1 which is ... what?).
Anyway, something like this might give you an idea:
update table1 t1 set
t1.c1 = (select t2.c2
from t2#dblink t2
where t2.some_column = t1.some_column --> you miss this
)
where t1.cs in (select t3.c3 from t3#dblink union
select t3.c4 from t3#dblink union
select t3.c5 from t3#dblink
);
The Problem:
Your subquery is returning multiple records and you are checking equality with a single value.
value1 <> {v2,v3,v4,v5,....}
you need to use the in clause (with a union if you intend to compare t1,cs with multiple columns on t2)

Deleting rows in Access based on rows in another table [duplicate]

I can't seem to ever remember this query!
I want to delete all rows in table1 whose ID's are the same as in Table2.
So:
DELETE table1 t1
WHERE t1.ID = t2.ID
I know I can do a WHERE ID IN (SELECT ID FROM table2) but I want to do this query using a JOIN if possible.
DELETE t1
FROM Table1 t1
JOIN Table2 t2 ON t1.ID = t2.ID;
I always use the alias in the delete statement as it prevents the accidental
DELETE Table1
caused when failing to highlight the whole query before running it.
DELETE Table1
FROM Table1
INNER JOIN Table2 ON Table1.ID = Table2.ID
There is no solution in ANSI SQL to use joins in deletes, AFAIK.
DELETE FROM Table1
WHERE Table1.id IN (SELECT Table2.id FROM Table2)
Later edit
Other solution (sometimes performing faster):
DELETE FROM Table1
WHERE EXISTS( SELECT 1 FROM Table2 Where Table1.id = Table2.id)
PostgreSQL implementation would be:
DELETE FROM t1
USING t2
WHERE t1.id = t2.id;
Try this:
DELETE Table1
FROM Table1 t1, Table2 t2
WHERE t1.ID = t2.ID;
or
DELETE Table1
FROM Table1 t1 INNER JOIN Table2 t2 ON t1.ID = t2.ID;
I think that you might get a little more performance if you tried this
DELETE FROM Table1
WHERE EXISTS (
SELECT 1
FROM Table2
WHERE Table1.ID = Table2.ID
)
This will delete all rows in Table1 that match the criteria:
DELETE Table1
FROM Table2
WHERE Table1.JoinColumn = Table2.JoinColumn And Table1.SomeStuff = 'SomeStuff'
Found this link useful
Copied from there
Oftentimes, one wants to delete some records from a table based on criteria in another table. How do you delete from one of those tables without removing the records in both table?
DELETE DeletingFromTable
FROM DeletingFromTable INNER JOIN CriteriaTable
ON DeletingFromTable.field_id = CriteriaTable.id
WHERE CriteriaTable.criteria = "value";
The key is that you specify the name of the table to be deleted from as the SELECT. So, the JOIN and WHERE do the selection and limiting, while the DELETE does the deleting. You're not limited to just one table, though. If you have a many-to-many relationship (for instance, Magazines and Subscribers, joined by a Subscription) and you're removing a Subscriber, you need to remove any potential records from the join model as well.
DELETE subscribers, subscriptions
FROM subscribers INNER JOIN subscriptions
ON subscribers.id = subscriptions.subscriber_id
INNER JOIN magazines
ON subscriptions.magazine_id = magazines.id
WHERE subscribers.name='Wes';
Deleting records with a join could also be done with a LEFT JOIN and a WHERE to see if the joined table was NULL, so that you could remove records in one table that didn't have a match (like in preparation for adding a relationship.) Example post to come.
Since the OP does not ask for a specific DB, better use a standard compliant statement.
Only MERGE is in SQL standard for deleting (or updating) rows while joining something on target table.
merge table1 t1
using (
select t2.ID
from table2 t2
) as d
on t1.ID = d.ID
when matched then delete;
MERGE has a stricter semantic, protecting from some error cases which may go unnoticed with DELETE ... FROM. It enforces 'uniqueness' of match : if many rows in the source (the statement inside using) match the same row in the target, the merge must be canceled and an error must be raised by the SQL engine.
To Delete table records based on another table
Delete From Table1 a,Table2 b where a.id=b.id
Or
DELETE FROM Table1
WHERE Table1.id IN (SELECT Table2.id FROM Table2)
Or
DELETE Table1
FROM Table1 t1 INNER JOIN Table2 t2 ON t1.ID = t2.ID;
I often do things like the following made-up example. (This example is from Informix SE running on Linux.)
The point of of this example is to delete all real estate exemption/abatement transaction records -- because the abatement application has a bug -- based on information in the real_estate table.
In this case last_update != nullmeans the account is not closed, and res_exempt != 'p' means the accounts are not personal property (commercial equipment/furnishings).
delete from trans
where yr = '16'
and tran_date = '01/22/2016'
and acct_type = 'r'
and tran_type = 'a'
and bill_no in
(select acct_no from real_estate where last_update is not null
and res_exempt != 'p');
I like this method, because the filtering criteria -- at least for me -- is easier to read while creating the query, and to understand many months from now when I'm looking at it and wondering what I was thinking.
Referencing MSDN T-SQL DELETE (Example D):
DELETE FROM Table1
FROM Tabel1 t1
INNER JOIN Table2 t2 on t1.ID = t2.ID
This is old I know, but just a pointer to anyone using this ass a reference. I have just tried this and if you are using Oracle, JOIN does not work in DELETE statements.
You get a the following message:
ORA-00933: SQL command not properly ended.
While the OP doesn't want to use an 'in' statement, in reply to Ankur Gupta, this was the easiest way I found to delete the records in one table which didn't exist in another table, in a one to many relationship:
DELETE
FROM Table1 as t1
WHERE ID_Number NOT IN
(SELECT ID_Number FROM Table2 as t2)
Worked like a charm in Access 2016, for me.
delete
table1
from
t2
where
table1.ID=t2.ID
Works on mssql

Comparing two datasets SQL SSRS 2005

I have two datasets on two seperate servers. They both pull one column of information each.
I would like to build a report showing the values of the rows that only appear in one of the datasets.
From what I have read, it seems I would like to do this on the SQL side, not the reporting side; I am not sure how to do that.
If someone could shed some light on how that is possible, I would really appreciate it.
You can use the NOT EXISTS clause to get the differences between the two tables.
SELECT
Column
FROM
DatabaseName.SchemaName.Table1
WHERE
NOT EXISTS
(
SELECT
Column
FROM
LinkedServerName.DatabaseName.SchemaName.Table2
WHERE
Table1.Column = Table2.Column --looks at equalities, and doesn't
--include them because of the
--NOT EXISTS clause
)
This will show the rows in Table1 that don't appear in Table2. You can reverse the table names to find the rows in Table2 that don't appear in Table1.
Edit: Made an edit to show what the case would be in the event of linked servers. Also, if you wanted to see all of the rows that are not shared in both tables at the same time, you can try something as in the below.
SELECT
Column, 'Table1' TableName
FROM
DatabaseName.SchemaName.Table1
WHERE
NOT EXISTS
(
SELECT
Column
FROM
LinkedServerName.DatabaseName.SchemaName.Table2
WHERE
Table1.Column = Table2.Column --looks at equalities, and doesn't
--include them because of the
--NOT EXISTS clause
)
UNION
SELECT
Column, 'Table2' TableName
FROM
LinkedServerName.DatabaseName.SchemaName.Table2
WHERE
NOT EXISTS
(
SELECT
Column
FROM
DatabaseName.SchemaName.Table1
WHERE
Table1.Column = Table2.Column
)
You can also use a left join:
select a.* from tableA a
left join tableB b
on a.PrimaryKey = b.ForeignKey
where b.ForeignKey is null
This query will return all records from tableA that do not have corresponding records in tableB.
If you want rows that appear in exactly one data set and you have a matching key on each table, then you can use a full outer join:
select *
from table1 t1 full outer join
table2 t2
on t1.key = t2.key
where t1.key is null and t2.key is not null or
t1.key is not null and t2.key is null
The where condition chooses the rows where exactly one match.
The problem with this query, though, is that you get lots of columns with nulls. One way to fix this is by going through the columns one by one in the SELECT clause.
select coalesce(t1.key, t2.key) as key, . . .
Another way to solve this problem is to use a union with a window function. This version brings together all the rows and counts the number of times that key appears:
select t.*
from (select t.*, count(*) over (partition by key) as keycnt
from ((select 'Table1' as which, t.*
from table1 t
) union all
(select 'Table2' as which, t.*
from table2 t
)
) t
) t
where keycnt = 1
This has the additional column specifying which table the value comes from. It also has an extra column, keycnt, with the value 1. If you have a composite key, you would just replace with the list of columns specifying a match between the two tables.

Delete all rows in a table based on another table

I can't seem to ever remember this query!
I want to delete all rows in table1 whose ID's are the same as in Table2.
So:
DELETE table1 t1
WHERE t1.ID = t2.ID
I know I can do a WHERE ID IN (SELECT ID FROM table2) but I want to do this query using a JOIN if possible.
DELETE t1
FROM Table1 t1
JOIN Table2 t2 ON t1.ID = t2.ID;
I always use the alias in the delete statement as it prevents the accidental
DELETE Table1
caused when failing to highlight the whole query before running it.
DELETE Table1
FROM Table1
INNER JOIN Table2 ON Table1.ID = Table2.ID
There is no solution in ANSI SQL to use joins in deletes, AFAIK.
DELETE FROM Table1
WHERE Table1.id IN (SELECT Table2.id FROM Table2)
Later edit
Other solution (sometimes performing faster):
DELETE FROM Table1
WHERE EXISTS( SELECT 1 FROM Table2 Where Table1.id = Table2.id)
PostgreSQL implementation would be:
DELETE FROM t1
USING t2
WHERE t1.id = t2.id;
Try this:
DELETE Table1
FROM Table1 t1, Table2 t2
WHERE t1.ID = t2.ID;
or
DELETE Table1
FROM Table1 t1 INNER JOIN Table2 t2 ON t1.ID = t2.ID;
I think that you might get a little more performance if you tried this
DELETE FROM Table1
WHERE EXISTS (
SELECT 1
FROM Table2
WHERE Table1.ID = Table2.ID
)
This will delete all rows in Table1 that match the criteria:
DELETE Table1
FROM Table2
WHERE Table1.JoinColumn = Table2.JoinColumn And Table1.SomeStuff = 'SomeStuff'
Found this link useful
Copied from there
Oftentimes, one wants to delete some records from a table based on criteria in another table. How do you delete from one of those tables without removing the records in both table?
DELETE DeletingFromTable
FROM DeletingFromTable INNER JOIN CriteriaTable
ON DeletingFromTable.field_id = CriteriaTable.id
WHERE CriteriaTable.criteria = "value";
The key is that you specify the name of the table to be deleted from as the SELECT. So, the JOIN and WHERE do the selection and limiting, while the DELETE does the deleting. You're not limited to just one table, though. If you have a many-to-many relationship (for instance, Magazines and Subscribers, joined by a Subscription) and you're removing a Subscriber, you need to remove any potential records from the join model as well.
DELETE subscribers, subscriptions
FROM subscribers INNER JOIN subscriptions
ON subscribers.id = subscriptions.subscriber_id
INNER JOIN magazines
ON subscriptions.magazine_id = magazines.id
WHERE subscribers.name='Wes';
Deleting records with a join could also be done with a LEFT JOIN and a WHERE to see if the joined table was NULL, so that you could remove records in one table that didn't have a match (like in preparation for adding a relationship.) Example post to come.
Since the OP does not ask for a specific DB, better use a standard compliant statement.
Only MERGE is in SQL standard for deleting (or updating) rows while joining something on target table.
merge table1 t1
using (
select t2.ID
from table2 t2
) as d
on t1.ID = d.ID
when matched then delete;
MERGE has a stricter semantic, protecting from some error cases which may go unnoticed with DELETE ... FROM. It enforces 'uniqueness' of match : if many rows in the source (the statement inside using) match the same row in the target, the merge must be canceled and an error must be raised by the SQL engine.
To Delete table records based on another table
Delete From Table1 a,Table2 b where a.id=b.id
Or
DELETE FROM Table1
WHERE Table1.id IN (SELECT Table2.id FROM Table2)
Or
DELETE Table1
FROM Table1 t1 INNER JOIN Table2 t2 ON t1.ID = t2.ID;
I often do things like the following made-up example. (This example is from Informix SE running on Linux.)
The point of of this example is to delete all real estate exemption/abatement transaction records -- because the abatement application has a bug -- based on information in the real_estate table.
In this case last_update != nullmeans the account is not closed, and res_exempt != 'p' means the accounts are not personal property (commercial equipment/furnishings).
delete from trans
where yr = '16'
and tran_date = '01/22/2016'
and acct_type = 'r'
and tran_type = 'a'
and bill_no in
(select acct_no from real_estate where last_update is not null
and res_exempt != 'p');
I like this method, because the filtering criteria -- at least for me -- is easier to read while creating the query, and to understand many months from now when I'm looking at it and wondering what I was thinking.
Referencing MSDN T-SQL DELETE (Example D):
DELETE FROM Table1
FROM Tabel1 t1
INNER JOIN Table2 t2 on t1.ID = t2.ID
This is old I know, but just a pointer to anyone using this ass a reference. I have just tried this and if you are using Oracle, JOIN does not work in DELETE statements.
You get a the following message:
ORA-00933: SQL command not properly ended.
While the OP doesn't want to use an 'in' statement, in reply to Ankur Gupta, this was the easiest way I found to delete the records in one table which didn't exist in another table, in a one to many relationship:
DELETE
FROM Table1 as t1
WHERE ID_Number NOT IN
(SELECT ID_Number FROM Table2 as t2)
Worked like a charm in Access 2016, for me.
delete
table1
from
t2
where
table1.ID=t2.ID
Works on mssql