简体   繁体   中英

MySQL: update table A based on the data from both A and B tables

Here are two tables. I want to UPDATE (NOT to SELECT) the first table based on the info from both tables.

The first table named somecities :

Name - State - Country - Info1 - Info2
Orlando - FL - US - 123 -AAA
Hrodna - HV - BY - 890 -BBB

The second table named allcities :

Name - State - Country - Info1
Orlando - FL - US - 123
Orlando - KY - US - 456
Orlando - WV - US - 789
Orlando - SW - SA - 333
Hrodna - HV - BY - 890
Minsk - MV - BY - 199

Any pair of (Name, State, Country) from somecities table is in the allcities table, if it matters. So, the allcities table is bigger.

I want to modify somecities this way:

1)take the first row, take Orlando . It is met 4 times in allcities . So, make 4 strings of Orlando instead of one (add 3 rows to somecities).

2) Take the next city (the second and the last one) - Hrodna . Hrodna is met only one time in allcities so we do not add any rows (add zero rows) to somecities .

3) Do it for each row in somecities .

The result of the query is the updated somecities :

Name - State - Country - Info1 - Info2
Orlando - FL -  US     - 123   -  AAA
Orlando - KY -  US     - 456   -  AAA
Orlando - WV -  US     - 789   -  AAA
Orlando - SW -  SA     - 333   -  AAA
Hrodna  - HV -  BY     - 890   -  BBB

PS As you can see, the values in the Info2 are taken from Info2 for the same city.

Can it be done in one query? Two queries as an answer will be accepted as well.

Did I explain it clear?

Thank you.

You need an INSERT query, you could use something like this:

INSERT INTO somecities
SELECT a.*, si.Info2
FROM
  allcities a LEFT JOIN somecities s
  ON a.Name=s.Name AND a.State=s.State AND a.Country=s.Country
  INNER JOIN (SELECT DISTINCT Name, Info2
              FROM somecities) si
  ON a.Name=si.Name
WHERE
  s.Name IS NULL

Please see fiddle here .

This will insert ALL rows from allcities that are not present in somecities (or that have the same name but a different state or country) because I'm using a LEFT JOIN with a WHERE s.Name IS NULL.

Then I'm selection the name of the cities and the Info2 column that are present in somecities, and I'm doing an INNER JOIN on just the Name, in order to return only the rows that are present in somecities at least once.

You can use NOT EXISTS to test for records that are not already in your table, then do a quick join to get the info2 from the existing records:

SQL Fiddle demo

INSERT INTO somecities (Name,State,Country,Info1, Info2)
SELECT data.Name,data.State,data.Country,data.Info1,inf.Info2
FROM (
    SELECT *
    FROM allcities a
    WHERE NOT EXISTS (SELECT * 
                      FROM somecities s 
                      WHERE s.name = a.name
                            AND s.state = a.state
                            AND s.country = a.country
                            AND s.info1 = a.info1
                     )
  ) data
  INNER JOIN (SELECT DISTINCT Name, Info2 FROM somecities) inf
    ON data.name = inf.name;

I personally find it easier to read EXISTS and NOT EXISTS rather than lots of joins but it's a personal preference, take your pick.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM