【问题标题】:SQL: table design for ship/invoice address and SELECT CONCAT issueSQL:发货/发票地址和SELECT CONCAT问题的表设计
【发布时间】:2010-12-13 19:19:10
【问题描述】:

我有一个以这种方式设计的简单customers 表(我只报告一些字段,即与此问题有关的字段):

+ ----------- + --------------- + ---------------- +
+ 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 为空的行意味着我们还必须使用客户的发票地址进行发货。


第一个问题:这是一个足够好的设计吗,还是应该在所有nullship_address 字段中填写发票地址(即使相同)并且不要留下null

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

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

查询 MySQL 数据库。

谢谢,

【问题讨论】:

    标签: mysql sql database-design street-address invoice


    【解决方案1】:

    我认为架构很好。如果您使用的是 ms sql server,您可以使用 coalesce,如下所示:

    select coalesce(ship_address,invoice_address) as address 
    from customers
    

    coalesce 基本上采用一个项目列表,并显示列表中不为空的第一个项目。

    【讨论】:

    • 您的回答非常适合我的问题并且有效,+1。我选择 Joe Stefanelli 的答案是因为它也有效,而且更完整,也很好地回答了我的第一个问题。
    【解决方案2】:

    客户和地址之间存在一对多的关系,因此我会将地址提取到带有“类型”的单独表中以区分它们。我会考虑将地址本身分解为单独的属性。或者,您甚至可以为有效的城市/州/国家添加参考表。

    至于查询此结构中的数据,假设始终存在 1 个地址,并且您以所需的顺序(即 Invoice=1,Shipping=2)创建 AddressType 记录:

    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
    

    【讨论】:

    • 嗯,这些是使 SO 真正成为一个独特的学习场所的答案类型。这个设计很棒,唯一的副作用是对客户(带有地址)的简单 SELECT 将始终需要 JOIN。但是对于生产和期待当数据库变得庞大时,这绝对是正确的道路。
    • 实际上客户 - 地址是一个 n:m 关系,因为同一个地址也可能用于多个客户(即同一公司内的不同员工,我使用相同的公司地址作为发货地址) ,但据我了解,CustomerAddressXref 表也可以处理这个问题。顺便说一句:我已经拆分了 City、State、.. 文件,只是为了简单起见,我没有在问题中写出来。
    • 如果客户更改地址会发生什么?客户以前的发票地址不应出于历史目的而更改……那该怎么办?
    【解决方案3】:

    这样就可以了

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

    【讨论】:

    • 哦,我看到你在 MySQL 中寻找查询?我最初看不到 MySQL 标记,我认为它是针对 MS SQl 的。如果表达式值(左侧的值)为 NULL,则 MS SQL ISNULL 函数用于设置替换值,即在您的情况下,如果 ship_address 为 null,那么它返回 invoice_address 的值。而在 MySQL 中 ISNULL 函数是用于 NULL 值检查的,对吧?
    【解决方案4】:

    您应该将收货地址留空,因为复制发票地址会导致冗余。

    关于查询:

    SELECT invoice_address
    from table 
    where ship_address IS Null
    
    UNION
    
    SELECT ship_address 
    from table 
    where ship_address IS NOT NULL
    

    【讨论】:

    • 这正是 'ISNULL' 的作用。
    猜你喜欢
    • 1970-01-01
    • 2011-09-11
    • 2014-02-11
    • 2011-02-10
    • 1970-01-01
    • 2020-04-10
    • 2013-09-17
    • 1970-01-01
    相关资源
    最近更新 更多