Update multiple rows in a table from another table when condition exists - sql

I have two tables.
Table1 contains companies whose locations are georeferenced with lat/lng coordinates in a column called the_geom
Table2 also contain the same companies from Table1, not georeferenced, along with hundreds of other companies whose addresses are georeferenced.
All I need to do is insert the_geom lat/lng values from Table1 companies into their corresponding entries in Table 2. The common denominator on which these inserts can be based on is the address column.
Simple question, I am sure, but I rarely use SQL.

Assuming that by
insert "the_geom" lat/lng values
you actually mean to UPDATE existing rows in table2:
UPDATE table2 t2
SET the_geom = t1.the_geom
FROM table1 t1
WHERE t2.address = t1.address
AND t2.the_geom IS DISTINCT FROM t1.the_geom; -- avoid empty updates
Related answer:
How do I (or can I) SELECT DISTINCT on multiple columns?
Also assuming that the address column has UNIQUE values.
Details for UPDATE in the manual.

I had a similar problem, but when I tried the solutions mentioned above, I got an error like
Incorrect syntax near 't2'
The code that worked for me is:
UPDATE table2
SET the_geom = t1.the_geom
FROM table1 as t1
WHERE table2.address = t1.address AND table2.the_geom <> t1.the_geom
I know that my answer is 5 years late, but I hope this will help someone like me, who couldn't find this solution.

If you are a mysql user(like me) and if the above script is not working, here is the mysql equivalent.
UPDATE table2 t2, table1 t1
SET the_geom = t1.the_geom
WHERE t2.address = t1.address
AND t2.the_geom <> t1.the_geom; -- avoid empty updates
All credits to the OP.

Related

Avoid multiple SELECT while updating a table's column relatively to another table's one

I am quite a newbie with SQL queries but I need to modify a column of a table relatively to the column of another table. For now I have the following query working:
UPDATE table1
SET date1=(
SELECT last_day(max(date2))+1
FROM table2
WHERE id=123
)
WHERE id=123
AND date1=to_date('31/12/9999', 'dd/mm/yyyy');
The problem with this structure is that, I suppose, the SELECT query will be executed for every line of the table1. So I tried to create another query but this one has a syntax error somewhere after the FROM keyword:
UPDATE t1
SET t1.date1=last_day(max(t2.date2))+1
FROM table1 t1
INNER JOIN table2 t2
ON t1.id=t2.id
WHERE t1.id=123
AND t1.date1=to_date('31/12/9999', 'dd/mm/yyyy');
AND besides that I don't even know if this one is faster than the first one...
Do you have any idea how I can handle this issue?
Thanks a lot!
Kind regards,
Julien
The first code you wrote is fine. It won't be executed for every line of the table1 as you fear. It will do the following:
it will run the subquery to find a value you want to use in your UPDATE statement, searching through table2, but as you have stated the exact id from
the table, it should be as fast as possible, as long as you have
created an index on that (I guess a primary key) column
it will run the outer query, finding the single row you want to update. As before, it should be as fast as possible as you have stated the exact id, as long as there is an index on that column
To summarize, If those ID's are unique, both your subquery and your query should return only one row and it should execute as fast as possible. If you think that execution is not fast enough (at least that it takes longer than the amount of data would justify) check if those columns have unique values and if they have unique indexes on them.
In fact, it would be best to add those indexes regardless of this problem, if they do not exist and if these columns have unique values, as it would drastically improve all of the performances on these tables that search through these id columns.
Please try to use MERGE
MERGE INTO (
SELECT id,
date1
FROM table1
WHERE date1 = to_date('31/12/9999', 'dd/mm/yyyy')
AND id = 123
) t1
USING (
SELECT id,
last_day(max(date2))+1 max_date
FROM table2
WHERE id=123
GROUP BY id
) t2 ON (t1.id = t2.id)
WHEN MATCHED THEN
UPDATE SET t1.date1 = t2.max_date
;

insert into from where condition on both tables

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.

SQL Query - Select Value from T1 where second value fully met in T2

I can do this in an ugly stored procedure with temp tables and whatnot, but I know an experienced developer could do this SO much more elegantly than what I've come up with. In fact, I'd kind of rather not have to call the sproc at all, but just have one query that gives me what I need.
I'm working with two tables:
T1 BillingDirectivesNeeded
T2 BillingDirectives.
T1 Has two fields relevant to this task -
PKey
WBS1.
There will be many PKeys associated with each WBS1.
T2 has only one field of interest
PKey.
The task I'm trying to address is geting a list of WBS1s from T1 that have ALL of their needed directives in T2 before I enable their import.
We want to import a WBS1 ONLY when all of the PKeys for that WBS1 are found in T2. If not, I'll just leave them grayed out.
I've tried a dozen different ways to get this to happen over the last few hours, and I seem to have a mental block. The pseudo-code would look something like this:
select T1.WBS1 from BillingDirectiveNeeded T1
where [all the T1.PKeys for T1.WBS1 can be found in BillingDirectives T2]
You can try using a Where Exists clause:
Select T1.WBS1
From BillingDirectiveNeeded T1
Where Exists
(
Select 1
From BillingDirectives T2
Where T2.PKey = T1.PKey
)
select DISTINCT T1.WBS1 from BillingDirectiveNeeded T1 where T1.PKey in (SELECT T2.PKey FROM BillingDirectives T2)

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.

Select proper columns from JOIN statement

I have two tables: table1, table2. Table1 has 10 columns, table2 has 2 columns.
SELECT * FROM table1 AS T1 INNER JOIN table2 AS T2 ON T1.ID = T2.ID
I want to select all columns from table1 and only 1 column from table2. Is it possible to do that without enumerating all columns from table1 ?
Yes, you can do the following:
SELECT t1.*, t2.my_col FROM table1 AS T1 INNER JOIN table2 AS T2 ON T1.ID = T2.ID
Even though you can do the t1.*, t2.col1 thing, I would not recommend it in production code.
I would never ever use a SELECT * in production - why?
you're telling SQL Server to get all columns - do you really, really need all of them?
by not specifying the column names, SQL Server has to go figure that out itself - it has to consult the data dictionary to find out what columns are present which does cost a little bit of performance
most importantly: you don't know what you're getting back. Suddenly, the table changes, another column or two are added. If you have any code which relies on e.g. the sequence or the number of columns in the table without explicitly checking for that, your code can brake
My recommendation for production code: always (no exceptions!) specify exactly those columns you really need - and even if you need all of them, spell it out explicitly. Less surprises, less bugs to hunt for, if anything ever changes in the underlying table.
Use table1.* in place of all columns of table1 ;)