简体   繁体   中英

How do I combine multiple rows with matching ID's into separate columns in SQL?

I'm not too experienced with SQL, so not sure if a similar question has already been answered (I'm sure there is, but I'm way out of my depth here). I used to be great at SQL many years back, but it's been so long that mind is foggy.

I'm migrating customers from one CMS to a different CMS.

Site A = Old CMS Site B = New CMS

In Site A's database, we have a table "p20kx_users" which contains the basic info - unique ID, username and email.

We then have a table "p20kx_virtuemart_userinfos" which contains in essence, two sets of data; shipping addresses and billing addresses.

In the "p20kx_virtuemart_userinfos" table, some users have just one row (the billing address), however most users have two rows (shipping AND billing addresses). There is a column in the "p20kx_virtuemart_userinfos" table named "address_type" that determines whether the row is Billing (BT) or Shipping (ST). There are also instances where users have neither, so that row shows up as NULL.

I've written a basic query that appears to retrieve all of the details I need, however I'm looking for a way so that the shipping and billing addresses appear on one row, in separate columns, so that I can export the results of the query directly to CSV and import to Site B.

Here's my query (I'm running this via PHPMyAdmin on a MariaDB 10.2 DB):

SELECT
p20kx_users.id,
p20kx_users.name,
p20kx_users.username,
p20kx_users.email,
p20kx_virtuemart_userinfos.address_type,
p20kx_virtuemart_userinfos.company,
p20kx_virtuemart_userinfos.title,
p20kx_virtuemart_userinfos.first_name,
p20kx_virtuemart_userinfos.last_name,
p20kx_virtuemart_userinfos.phone_1,
p20kx_virtuemart_userinfos.phone_2,
p20kx_virtuemart_userinfos.address_1,
p20kx_virtuemart_userinfos.address_2,
p20kx_virtuemart_userinfos.city,
p20kx_virtuemart_userinfos.zip
FROM p20kx_users
LEFT JOIN p20kx_virtuemart_userinfos
ON p20kx_users.id=p20kx_virtuemart_userinfos.virtuemart_user_id

I've had a good old google, and attempted the below which returns one result with mixed up details from other users.

SELECT
p20kx_users.id,
p20kx_users.name,
p20kx_users.username,
p20kx_users.email,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'BT' THEN p20kx_virtuemart_userinfos.company ELSE NULL END) Billing_Company,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'BT' THEN p20kx_virtuemart_userinfos.title ELSE NULL END) Billing_Title,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'BT' THEN p20kx_virtuemart_userinfos.first_name ELSE NULL END) Billing_Fname,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'BT' THEN p20kx_virtuemart_userinfos.last_name ELSE NULL END) Billing_LName, 
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'BT' THEN p20kx_virtuemart_userinfos.phone_1 ELSE NULL END) Billing_Phone1,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'BT' THEN p20kx_virtuemart_userinfos.phone_2 ELSE NULL END) Billing_Phone2,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'BT' THEN p20kx_virtuemart_userinfos.address_1 ELSE NULL END) Billing_Add1,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'BT' THEN p20kx_virtuemart_userinfos.address_2 ELSE NULL END) Billing_Add2,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'BT' THEN p20kx_virtuemart_userinfos.city ELSE NULL END) Billing_City,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'BT' THEN p20kx_virtuemart_userinfos.zip ELSE NULL END) Billing_Zip,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'ST' THEN p20kx_virtuemart_userinfos.company ELSE NULL END) Shipping_Company,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'ST' THEN p20kx_virtuemart_userinfos.title ELSE NULL END) Shipping_Title,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'ST' THEN p20kx_virtuemart_userinfos.first_name ELSE NULL END) Shipping_Fname,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'ST' THEN p20kx_virtuemart_userinfos.last_name ELSE NULL END) Shipping_LName, 
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'ST' THEN p20kx_virtuemart_userinfos.phone_1 ELSE NULL END) Shipping_Phone1,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'ST' THEN p20kx_virtuemart_userinfos.phone_2 ELSE NULL END) Shipping_Phone2,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'ST' THEN p20kx_virtuemart_userinfos.address_1 ELSE NULL END) Shipping_Add1,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'ST' THEN p20kx_virtuemart_userinfos.address_2 ELSE NULL END) Shipping_Add2,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'ST' THEN p20kx_virtuemart_userinfos.city ELSE NULL END) Shipping_City,
MAX(CASE WHEN p20kx_virtuemart_userinfos.address_type = 'ST' THEN p20kx_virtuemart_userinfos.zip ELSE NULL END) Shipping_Zip
FROM p20kx_users
LEFT JOIN p20kx_virtuemart_userinfos
ON p20kx_users.id=p20kx_virtuemart_userinfos.virtuemart_user_id

Can someone tell me where I am going wrong, and how I should address this - I've spent half a day looking at this. The longer I look, the more confused I get.

Your query is close. You need a GROUP BY :

SELECT u.id, u.name, u.username, u.email,
       MAX(CASE WHEN ui.address_type = 'BT' THEN ui.company END) as Billing_Company,
       . . .
FROM p20kx_users u LEFT JOIN
     p20kx_virtuemart_userinfos ui
     ON u.id = ui.virtuemart_user_id
GROUP BY u.id, u.name, u.username, u.email;

I also introduced table aliases, so the query is easier to write and to read. And I removed the ELSE NULL , because that is redundant.

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