insert into from where condition on both tables - sql

I want to feed table1 name with table2 name based on the reference I have on my table1 in my table2 (id).
How can I achieve this? something like:
insert into table1 (name)
select name from table2
where table2.id = table1.table2Id;
The where clause is not aware of table1 and cannot apply the condition.

You might use a FROM-clause (with JOINs) in your INSERT..SELECT queries, but also in your UPDATE and/or DELETE queries.
If you want to insert new records into table1 based on data from table2, you may only need to make sure that there will not be attempted to insert data in table1 that might break any constraints.
The WHERE-clause in your example INSERT-query might not be valid in that case, since it seems to assume that there are already matching records in table1. (There might be possible exceptional scenarios that would justify such a query, but I will not elaborate on those scenarios here, since your question does not indicate that that's relevant in your case.)
Example for inserting records in table1 based on (related) data in table1 and table2:
INSERT INTO table1 (name)
SELECT table2.name
FROM table2 JOIN table1 ON table1.[ref] = table2.[ref] --use some sensible relation logic between table1 and table2 here
WHERE ... --check for valid data here
If you want to update existing records in table1 with data from table2, you can probably use an UPDATE query instead of an INSERT-query. Again, you should check that you do not attempt to update data that would break any constraints.
Example for updating records in table1 that match with data in table2:
UPDATE table1
SET name = table2.name
FROM table2
WHERE table2.id = table1.id --or use some other sensible relation logic between table1 and table2 here (together with other validation logic)
You might also use a FROM-clause in your UPDATE query, but it seems you must be careful not to include the target table in that FROM-clause and supply the correct join with the target table records in the WHERE-clause.

Related

sql - what's the faster/better way to refer to columns in a where clause with inner joins?

Say I've got a query like this:
select table1.id, table1.name
from table1
inner join table2 on table1.id = table2.id
where table1.name = "parent" and table2.status = 1
Is it true that, since there's an inner join, I can refer the table2's status column even from table1? Like this:
select table1.id, table1.name
from table1
inner join table2 on table1.id = table2.id
where table1.name = "parent" and table1.status = 1
And if yes, what's the best of the two ways?
If I am not mistaken, you are asking that in an inner join, two fields of the same name, data type and length will be one field in the particular query. Technically that is not the case. Regardless of anything, Table1.Status will refer to Table1 and Table2.Status will refer to Table2's condition/value.
The two queries above CAN product different results from each other.
A good rule on this is that you stick your conditions on the base table, or Table1, in this case. If a field is exclusive to another table, that's when you'll use that Table's field.
No, that's not true. By Inner join what you are doing is say if you have table1 with m rows and table two with n rows then the third SET that will be produced by joining the two tables will have m*n rows based on match condition that you have mentioned in where clause. It's not m+n rows or infact columns of the two tables are not getting merged at database level. status column will remain in the table it has been defined.
Hope that helps!!!
You can see this is not the case if you do
CREATE TABLE table1 (id INT, name VARCHAR);
CREATE TABLE table2 (id INT, status INT);
Now if you run your second query you will get an error because you refer to t1.status, and the status column does not existing in table t1.
If there was a status field in both tables the query would run, but likely would not give the results you want e.g. assume status in table1 was always 1, and in table2 was always 0. Now your first query could never return rows, but your second one certainly could return rows.

How do I write an SQL statement (for DB2) to update a table with these conditions?

Here's what I need to do:
For each row in Table1 where Name is not null or blank, and Table2 has a row with matching Name, replace another column in Table1 with the contents of a column from Table2, and set the name in Table 1 to null.
I can't seem to wrap my head around getting that logic into SQL.
I don't really care if Table2 has multiple rows with matching Names, just grabbing the first one is good enough.
In DB2 you could use the MERGE statement to do the job
MERGE INTO Table1 A
USING Table2 B
on A.name=B.name
WHEN MATCHED
THEN UPDATE SET A.another_column=B.Table2_Column
, A.name=NULL;
In T-Sql
You would use an UPDATE statement with a join criteria that would only impact the matching rows, something like the below:
Update A
set A.another_column=B.Table2_Column
, A.name=NULL
From Table1 A
inner join Table2 B
on A.name=B.name
Where isnull(A.name,'')<>''

Updating an Oracle table with respect to another table

I have two tables.
Lets say:
Table T1 with columns id,ref,a1,b1,c1,d1,e1
Table T2 with columns id,ref,a2,b2,c2,d2,e2
I need to update few columns in T2(a2,c2,e2) with respect to values in T1(a1,c1,e1) where T1.ref = T2.ref, given that ref=<certain value>.
For a particular value of ref column there are many records in each table.
I want to update T2 with respect to T1 for one particular value of ref column. Other records will be untouched.
I am currently doing this by dropping all the rows of T2 and inserting the current rows from T1 where ref=<some value>.
For ex: if the ref value=5
then I do these steps.
1. delete from T2 where ref=5;
2. insert into T2 (a2,c2,e2) select a1,c1,e1 from T1 where T1.ref = 5;
Certainly this is not a good method to synchronize the data between the two table.
Please suggest me an efficient solution to achieve this in Oracle.
I think i missed an important point. Both the tables have one column which clearly identifies each record. So I dont want the records to be in T2 which are not present in T1.
Just to reiterate - for a value of column "ref" both the tables returns multiple records, and each record has an unique identifying column. Those records identified in T1 only needs to be present in T2.
Thanks in Advance!
If you don't have exact matching between each row of T1 and T2 then your method is good enough.
But if you have some kind of matching try to implement your logic with merge:
MERGE INTO t2 b
USING (
SELECT *
FROM t1
WHERE t1.ref = <value>) t1
ON (t2.<key> = t1.<key>)
WHEN MATCHED THEN
UPDATE SET <t2.values> = <t1.values>
WHEN NOT MATCHED THEN
INSERT (<t2columns>)
VALUES (<t1values>);
I guess you want something like:
update t2
set (a2,c2,e2) = (select a1,c1,e1 from t1 where t1.ref = 5)
where t2.ref = 5;
But you would have to make sure the nested query produces only one row.

Update a column of a table with a column of another table in PostgreSQL

I want to copy all the values from one column val1 of a table table1 to one column val2 of another table table2. I tried this command in PostgreSQL:
update table2
set val2 = (select val1 from table1)
But I got this error:
ERROR: more than one row returned by a subquery used as an expression
Is there an alternative to do that?
Your UPDATE query should look like this:
UPDATE table2 t2
SET val2 = t1.val1
FROM table1 t1
WHERE t2.table2_id = t1.table2_id
AND t2.val2 IS DISTINCT FROM t1.val1; -- optional, see below
The way you had it, there was no link between individual rows of the two tables. Every row would be fetched from table1 for every row in table2. This made no sense (in an expensive way) and also triggered the syntax error, because a subquery expression in this place is only allowed to return a single value.
I fixed this by joining the two tables on table2_id. Replace that with your actual join condition.
I rewrote the UPDATE to join in table1 (with the FROM clause) instead of running correlated subqueries, because that is typically faster.
It also prevents that table2.val2 is nullified where no matching row is found in table1. Instead, nothing happens to such rows with this form of the query.
You can add table expressions to the FROM list like you would in a plain SELECT (tables, subqueries, set-returning functions, ...). The manual:
from_item
A table expression allowing columns from other tables to appear in the WHERE condition and update expressions. This uses the same
syntax as the FROM clause of a SELECT statement; for example,
an alias for the table name can be specified. Do not repeat the target
table as a from_item unless you intend a self-join (in which
case it must appear with an alias in the from_item).
The final WHERE clause prevents updates that wouldn't change anything - at almost full cost but no gain (exotic exceptions apply). If both old and new value are guaranteed to be NOT NULL, simplify to:
AND t2.val2 <> t1.val1
See:
How do I (or can I) SELECT DISTINCT on multiple columns?
update table1 set table1_column= table2.column from table2 table2 where table1_id= table2.id
do not use alias name for table1.
tables are table1, table2

Difference between "and" and "where" in joins

Whats the difference between
SELECT DISTINCT field1
FROM table1 cd
JOIN table2
ON cd.Company = table2.Name
and table2.Id IN (2728)
and
SELECT DISTINCT field1
FROM table1 cd
JOIN table2
ON cd.Company = table2.Name
where table2.Id IN (2728)
both return the same result and both have the same explain output
Firstly there is a semantic difference. When you have a join, you are saying that the relationship between the two tables is defined by that condition. So in your first example you are saying that the tables are related by cd.Company = table2.Name AND table2.Id IN (2728). When you use the WHERE clause, you are saying that the relationship is defined by cd.Company = table2.Name and that you only want the rows where the condition table2.Id IN (2728) applies. Even though these give the same answer, it means very different things to a programmer reading your code.
In this case, the WHERE clause is almost certainly what you mean so you should use it.
Secondly there is actually difference in the result in the case that you use a LEFT JOIN instead of an INNER JOIN. If you include the second condition as part of the join, you will still get a result row if the condition fails - you will get values from the left table and nulls for the right table. If you include the condition as part of the WHERE clause and that condition fails, you won't get the row at all.
Here is an example to demonstrate this.
Query 1 (WHERE):
SELECT DISTINCT field1
FROM table1 cd
LEFT JOIN table2
ON cd.Company = table2.Name
WHERE table2.Id IN (2728);
Result:
field1
200
Query 2 (AND):
SELECT DISTINCT field1
FROM table1 cd
LEFT JOIN table2
ON cd.Company = table2.Name
AND table2.Id IN (2728);
Result:
field1
100
200
Test data used:
CREATE TABLE table1 (Company NVARCHAR(100) NOT NULL, Field1 INT NOT NULL);
INSERT INTO table1 (Company, Field1) VALUES
('FooSoft', 100),
('BarSoft', 200);
CREATE TABLE table2 (Id INT NOT NULL, Name NVARCHAR(100) NOT NULL);
INSERT INTO table2 (Id, Name) VALUES
(2727, 'FooSoft'),
(2728, 'BarSoft');
SQL comes from relational algebra.
One way to look at the difference is that JOINs are operations on sets that can produce more records or less records in the result than you had in the original tables. On the other side WHERE will always restrict the number of results.
The rest of the text is extra explanation.
For overview of join types see article again.
When I said that the where condition will always restrict the results, you have to take into account that when we are talking about queries on two (or more) tables you have to somehow pair records from these tables even if there is no JOIN keyword.
So in SQL if the tables are simply separated by a comma, you are actually using a CROSS JOIN (cartesian product) which returns every row from one table for each row in the other.
And since this is a maximum number of combinations of rows from two tables then the results of any WHERE on cross joined tables can be expressed as a JOIN operation.
But hold, there are exceptions to this maximum when you introduce LEFT, RIGHT and FULL OUTER joins.
LEFT JOIN will join records from the left table on a given criteria with records from the right table, BUT if the join criteria, looking at a row from the left table is not satisfied for any records in the right table the LEFT JOIN will still return a record from the left table and in the columns that would come from the right table it will return NULLs (RIGHT JOIN works similarly but from the other side, FULL OUTER works like both at the same time).
Since the default cross join does NOT return those records you can not express these join criteria with WHERE condition and you are forced to use JOIN syntax (oracle was an exception to this with an extension to SQL standard and to = operator, but this was not accepted by other vendors nor the standard).
Also, joins usually, but not always, coincide with existing referential integrity and suggest relationships between entities, but I would not put as much weight into that since the where conditions can do the same (except in the before mentioned case) and to a good RDBMS it will not make a difference where you specify your criteria.
The join is used to reflect the entity relations
the where clause filters down results.
So the join clauses are 'static' (unless the entity relations change), while the where clauses are use-case specific.
There is no difference. "ON" is like a synonym for "WHERE", so t he second kind of reads like:
JOIN table2 WHERE cd.Company = table2.Name AND table2.Id IN (2728)
There is no difference when the query optimisation engine breaks it down to its relevant query operators.