SQL: table design for ship/invoice address and SELECT CONCAT issue
-
09-10-2019 - |
Pergunta
I have a simple customers
table designed this way (I report only some fields, the ones regarding this qeustions):
+ ----------- + --------------- + ---------------- +
+ customer_id + invoice_address + ship_address +
+ ----------- + --------------- + ---------------- +
+ 33 + 234, Walnut Ave + null +
+ ----------- + --------------- + ---------------- +
+ 47 + 66, Smart Ave + null +
+ ----------- + --------------- + ---------------- +
+ 47 + 4, Cool Ave + 45, Dark Street +
+ ----------- + --------------- + ---------------- +
Rows with null ship_address means we must use customer's invoice address also for shipping.
1st question: is this a good enough design, or should all the null
ship_address
fields be filled with the invoice address (even if identical) and not left null
.
2nd question: keeping such a design (even in case it's bad design), how do I create a SELECT query (if it's possible) that returns always one single address for each row: the ship_address
when NOT null
, otherwise just the invoice_address
, something like:
SELECT CONCAT_IF_SHIP_ADDRESS_NOT_NULL_OTHERWISE_USE_ONLY_SHIP_ADDRESS(invoice_address, ship_address) AS address FROM customers;
Query for MySQL DB.
Thanks,
Solução
You have a 1-to-many relationship between customers and addresses, so I'd pull address out into a separate table with a "type" to distinguish between them. I'd consider breaking the address itself into separate attributes. Optionally, you could even add reference tables for valid cities/states/countries.
As for querying the data in this structure, assuming 1 address always exists and you create AddressType records in the desired order (i.e., Invoice=1, Shipping=2):
select c.CustomerID, a.AddressLine1, a.AddressLine2, a.AddressLine3,
a.City, a.State, a.PostalCode, a.Country
from Customer c
inner join (select MIN(cax.AddressTypeID) as MinAddressTypeID
from CustomerAddressXref cax
where cax.CustomerID = c.CustomerID
group by cax.CustomerID) mincax
inner join CustomerAddressXref cax
on c.CustomerID = cax.CustomerID
and mincax.MinAddressTypeID = cax.AddressTypeID
inner join Address a
on cax.AddressID = a.AddressID
Outras dicas
i think the schema is fine. if you're using ms sql server you can use coalesce, like this:
select coalesce(ship_address,invoice_address) as address
from customers
coalesce basically takes a list of items, and displays the first item in the list that is not null.
This will do
SELECT customer_id, ISNULL(ship_address,invoice_address) AS address
FROM customers
You should leave the ship address null as copying invoice address will lead to redundancy.
As for the query:
SELECT invoice_address
from table
where ship_address IS Null
UNION
SELECT ship_address
from table
where ship_address IS NOT NULL