I have a multi-table setup to handle online purchase transactions. The main table I'm getting data from is a purchase activity table. It contains ShipAcctID, which connects it to an addresses table, and AcctID, which connects it to a users table - sort of. The AcctID field is a reference to the user's account ID, which is stored in the users table, but what I need to return is their shipping address, which is connected in the addresses table via the customer_id field.
To try to clear that up, here's what the tables actually look like.
Purchases table
ID | PurchAmt | AcctID | ShipAddrID
================================================
1 | 30.99 | 25 | 420
2 | 45.22 | 31 | 209
Users table
ID | Name
=================================
25 | Anastasia Beaverhausen
31 | Charles Beaverhausen
45 | Bennie Beaverhausen
Addresses table
ID | customer_id | name | address
==========================================================================
300 | 25 | Anastasia Beaverhausen | 123 Park Avenue
209 | 31 | Charles Beaverhausen | 500 5th Avenue
420 | 45 | Bennie Beaverhausen | 500 North Michigan Avenue
What I need to do is return something like this:
PurchaseID | PurchAmt | billname |billAddress |shipName | shipaddress
====================================================================================================================================
1 | 30.99 | Anastasia Beaverhausen |123 Park Avenue |Bennie Beaverhausen |500 North Michigan Avenue
So I need to get the billaddress by joining purchases to addresses via the purchases.AcctID = addresses.customer_id relationship; then get the shipaddress by joining purchases directly to addresses via the purchases.ShipAddrID = addresses.id relationship. It makes sense in my head, anyway. But when I run the query, I get multiple rows per purchase ID, like this:
PurchActvtyID | billName | billAddress1 |shipName | shipAddress1
==================================================================================================================================
1535 | Anastasia Beaverhausen | 123 Park Avenue |Bennie Beaverhausen | 500 North Michigan Avenue
1535 | Bennie Beaverhausen | 500 North Michigan Avenue | Bennie Beaverhausen | 500 North Michigan Avenue
Can anyone explain why this is happening? I'm sure it's probably something to do with which kind of join to use, but I can't seem to get the correct results no matter which kind I try. Here's my query:
SELECT p.PurchActvtyID, a1.name AS billName, a1.address1 AS billAddress1, a2.name AS shipName, a2.address1 AS shipAddress1
FROM arrc_PurchaseActivity p
LEFT OUTER JOIN jos_customers_addresses a1 ON p.AcctID = a1.customer_id
LEFT OUTER JOIN jos_customers_addresses a2 ON p.ShipAddrID = a2.id
ORDER BY p.PurchActvtyID ASC
EDITS
results of Stephen's query:
PurchActvtyID | billName开发者_JAVA百科 | shipName | billAddress | shipAddress
========================================================================================
1535 | Esther Strom | Esther Strom |123 Park Avenue | 500 North Michigan Avenue
1535 | Esther Strom | Esther Strom |500 North Michigan Avenue |500 North Michigan Avenue
The reason for the name being different from what I showed in my example of desired outcome is that your query is pulling the name from the users table, which isn't accurate - the user name isn't necessarily the same as the billing or shipping name asssociated with a given user. This is why I need to pull those values from the addresses table, not the users table.
Although there aren't duplicates as such, you can have multiple addresses for a single customer ID - this is what appears to be happening in the example, as a single purchase (1535) is returning multiple billing addresses (both 123 Park Avenue and 500 North Michigan Avenue).
Normally, a customer could have many billing addresses (over time), although there is normally only one billing address per transaction. I therefore suggest adding a BillAddrID field to arrc_PurchaseActivity (if it doesn't already have one), and changing the linkage to jos_customers_addresses alias a1 to be p.BillAddrID = a2.id
.
Alternatively, you may want (or already have) only one billing address per customer, in which case you should add a billing address ID field to your customer table (users, in the question), and then change the query to link from the purchase table to the customer table, and then from the customer's billing address ID to the address table, to return a single billing address for the transaction.
EDIT, following comments:
The following query should resolve the issue of multiple addresses being returned on the billing alias:
SELECT p.PurchActvtyID, a1.name AS billName, a1.address1 AS billAddress1, a2.name AS shipName, a2.address1 AS shipAddress1
FROM arrc_PurchaseActivity p
LEFT OUTER JOIN jos_customers_addresses a1 ON p.AcctID = a1.customer_id and a1.billing = 1
LEFT OUTER JOIN jos_customers_addresses a2 ON p.ShipAddrID = a2.id
ORDER BY p.PurchActvtyID ASC
To create the output you want you only need two tables:
Purchases table
Addresses table
However, you need to join to the Addresses table twice:
Once for the Billing Address
Once for the Shipping Address
SELECT
t1.ID as PurchaseID,
t1.PurchAmt as PurchAmt,
t2.name as billname,
t2.address as billaddress,
t3.name as shipname,
t3.address as shipaddress
FROM Purchases t1
INNER JOIN Addresses t2
ON t1.AcctID
= t2.customer_id
INNER JOIN Addresses t3
ON t1.ShipAddrID
= t3.ID
The 1st INNER JOIN links to the billing information
The 2nd INNER JOIN links to the shipping information
I did get an answer to this on experts-exchange. All I needed to do was use a group by clause. So my query now looks like this:
SELECT p.PurchActvtyID, a1.name AS billName, a1.address1 AS billAddress1, a2.name AS shipName, a2.address1 AS shipAddress1
FROM arrc_PurchaseActivity p
LEFT OUTER JOIN jos_customers_addresses a1 ON p.AcctID = a1.customer_id
LEFT OUTER JOIN jos_customers_addresses a2 ON p.ShipAddrID = a2.id
GROUP BY p.PurchActvtyID
ORDER BY p.PurchActvtyID ASC
I don't think there's a reason to join the same table twice based on your criteria...
Try:
SELECT p.PurchActvtyID, a1.name AS billName, a1.address1 AS billAddress1, a1.name AS shipName, a1.address1 AS shipAddress1
FROM arrc_PurchaseActivity p
LEFT OUTER JOIN jos_customers_addresses a1 ON p.AcctID = a1.customer_id AND p.ShipAddrID = a1.id
ORDER BY p.PurchActvtyID ASC
Note - I work with SQL Server, I'm assuming syntax will work with MySQL.
Edit:
I suspect it's happening because you are doing two left outer joins to the same table on different criteria.
精彩评论