2010-12-13 29 views
1

我有一个简单customers表设计成这样(我只报告某些领域,那些对此qeustions):SQL:表设计船舶/发票地址和SELECT CONCAT问题

+ ----------- + --------------- + ---------------- + 
+ customer_id + invoice_address + ship_address  + 
+ ----------- + --------------- + ---------------- + 
+ 33   + 234, Walnut Ave + null    + 
+ ----------- + --------------- + ---------------- + 
+ 47   + 66, Smart Ave + null    + 
+ ----------- + --------------- + ---------------- + 
+ 47   + 4, Cool Ave  + 45, Dark Street + 
+ ----------- + --------------- + ---------------- + 

行与空ship_address表示我们还必须使用客户的发票地址来发货。


1号问题:这是一个足够好的设计,还是应该全部nullship_address领域充满发票地址(即使是相同的),并没有离开null

第二个问题:保持这样的设计(即使在情况下,它是很糟糕的设计),如何创建一个SELECT查询(如果可能的话),对每一行返回总是一个单地址:ship_address当不null,否则只是invoice_address,类似于:

SELECT CONCAT_IF_SHIP_ADDRESS_NOT_NULL_OTHERWISE_USE_ONLY_SHIP_ADDRESS(invoice_address, ship_address) AS address FROM customers; 

查询MySQL DB。

谢谢,

回答

2

你的客户和地址之间存在1对多的关系,所以我会拉动地址到一个单独的表一中“类型”来区分它们。我会考虑将地址本身分成不同的属性。或者,您甚至可以为有效的城市/州/国家添加参考表。

alt text

至于在本结构查询数据,假设1个地址总是存在,则创建所需的顺序地址类型的记录(即,发票= 1,海运= 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 
+0

那么这些答案就是让SO真正成为一个独特的学习场所。这种设计非常棒,唯一的副作用是对客户的简单SELECT(带地址)将始终需要JOIN。但是对于产品的生产和期待,当数据库可能变得巨大时,这绝对是正确的道路。 – 2010-12-16 17:36:29

+0

实际上客户 - 地址是一个n:m关系导致相同的地址也可能适用于多个客户(即同一公司内的不同员工,我使用与船名地址相同的公司地址),但从我了解CustomerAddressXref桌子也可以处理这个。顺便说一句:我已经拆分了城市,州,..档案,我只是没有在问题中写出来,以保持简单。 – 2010-12-16 17:36:59

+0

如果客户更改地址,会发生什么情况?客户以前的发票地址不应该为了历史目的而更改......那么应该怎么做? – greaterKing 2014-10-05 03:39:17

2

我认为模式是好的。如果你使用的MS SQL Server可以使用聚结,像这样:

select coalesce(ship_address,invoice_address) as address 
from customers 

聚结基本上采用的项目清单,并在非空列表中显示的第一个项目。

+1

这就像一个魅力! COALESE也在MySQL中。 – 2010-12-16 17:15:42

+0

你的回答非常适合我的问题和作品+1。我选择Joe Stefanelli的答案是因为它也可以工作,它更完整,对我的第一个问题也有很好的答案。 – 2010-12-16 17:38:52

1

这将做

SELECT customer_id, ISNULL(ship_address,invoice_address) AS address 
FROM customers 
+0

这个答案是完全错误的。 – 2010-12-16 17:14:12

+0

哦,我看到你在寻找MySQL中的查询吗?我最初看到MySQL标签,我认为它是用于MS SQl。如果表达式值(左边的值)为NULL,MS SQL ISNULL函数用于设置替换值,即在您的情况下,如果ship_address为null,那么它返回invoice_address的值。而在MySQL中,ISNULL函数用于NULL值检查,对吗? – wizzardz 2010-12-17 08:31:34

1

你应该离开船地址null作为复制发票地址会导致冗余。

至于查询:

SELECT invoice_address 
from table 
where ship_address IS Null 

UNION 

SELECT ship_address 
from table 
where ship_address IS NOT NULL 
+0

如果ship_address为null,那么只需读取发票 – Programmer 2010-12-13 19:30:20

+0

就是'ISNULL'所做的。 – wizzardz 2010-12-13 19:36:14