【问题标题】:SELECT product from subclass: How many queries do I need?从子类中选择产品:我需要多少查询?
【发布时间】:2010-05-20 16:42:24
【问题描述】:

我正在构建一个类似于here 描述的数据库,其中我有不同类型的产品,每种类型都有自己的属性。

为方便起见,我报告了一个简短的版本

product_type
============
product_type_id INT
product_type_name VARCHAR

product
=======
product_id INT
product_name VARCHAR
product_type_id INT -> Foreign key to product_type.product_type_id
... (common attributes to all product) 

magazine
========
magazine_id INT
title VARCHAR
product_id INT -> Foreign key to product.product_id
... (magazine-specific attributes)

web_site
========
web_site_id INT
name VARCHAR
product_id INT -> Foreign key to product.product_id
... (web-site specific attributes)

这样我就不需要为不同产品类型的每个属性创建一个包含一列的巨大表(其中大部分将是 NULL)

我如何SELECTproduct.product_id 的产品并查看其所有属性? 我是否必须先进行查询以了解我正在处理的产品类型,然后通过一些逻辑对正确的表进行另一个查询JOIN?或者有没有办法把所有东西结合在一起? (如果,当我检索有关 product_id 的信息时,有很多 NULL,此时就可以了)。

谢谢

【问题讨论】:

    标签: sql mysql database-design


    【解决方案1】:

    设计不错。很好地避免了实体属性值陷阱。

    您只需按照您的建议进行连接,但我认为不需要两个查询。我什至不认为 product_type 表是必需的。

    SELECT * FROM product p
    LEFT JOIN magazine m
    ON m.product_id = p.product_id
    LEFT JOIN web_site w
    ON w.product_id = p.product_id
    

    在上述查询中,对于杂志,m.product_id 不为空,对于网站,w.product_id 不为空。

    仅限杂志:

    SELECT * FROM product p
    JOIN magazine m
    ON m.product_id = p.product_id
    

    仅限网站:

    SELECT * FROM product p
    JOIN web_site w
    ON w.product_id = p.product_id
    

    您最大的问题是关于获取列名?您可能正在编写这些代码,或者您使用反射来获取它们。大多数数据库访问层都提供反射。

    【讨论】:

      【解决方案2】:

      您可以在一个查询中完成所有操作,几列将保持为空:

      SELECT
        t.product_type_name,
        t.product_type_id 
        p.product_id,
        p.product_name,
        p.[common attributes to all products...],
        m.*,
        w.*
      FROM
        product p
        INNER JOIN product_type t ON t.product_type_id = p.product_type_id
        LEFT  JOIN magazine     m ON m.product_id      = p.product_id
        LEFT  JOIN web_site     w ON w.product_id      = p.product_id
      WHERE
        p.product_id = ?
      

      在您的应用中使用product_type_id 来确定在任何特定情况下您对结果集中的哪些列感兴趣。

      就性能而言,这应该运行得非常快(外键、索引);它为任何产品类型生成一致的结果集。

      我建议不要使用 .* 并明确列出每个列名,这样更便携、更易于维护且不易出错。

      【讨论】:

      • 另外,使用 w.* 和 m.* 将重新包含您可能已经包含的常用列。
      • 谢谢!有用。我对 SQL 很陌生,我对 LEFT JOIN 的存在感到困惑。现在我明白了!但是正确的方法大概是这样: LEFT JOIN magazine m ON m.product_id = p.product_id LEFT JOIN web_site w ON w.product_id = p.product_id 因为product_id在product表中是唯一的,所以在所有子表中也是唯一的,所以不需要 magazine_id 或 web_site_id。同样,我认为不需要 product_type 表。我可以在产品表中添加一个属性
      • @Stefano:1)我加入了反对product_type,因为它在那里。 2)关于连接,您是正确的,我使用了错误的列名。现在已经纠正了。 3) 为什么你有两个属性来唯一标识一本杂志(magazine_idproduct_id,很明显)?这种设置对我来说毫无意义。 product_id 在产品类型中是唯一的,因此每个产品类型中不需要另一个唯一 ID。
      • 同意。我复制了原始问题中的设计。后来才发现列和表太多了
      【解决方案3】:

      为什么不制作AttributeDefinition 表和ProductAttribute 表?大致如下:

      AttributeDefinition
          Id
          Description
      
      ProductAttribute
          AttributeDefinitionId
          ProductId
          Value
      

      那么,无论你处理的是哪种产品,你都知道你可以通过简单地查询ProductAttribute表来获得所有的属性。而且您不必在每次需要具有自定义属性的新产品时都添加新的特定表。

      【讨论】:

        【解决方案4】:

        讨厌的联合全部,每种类型都有明确的列,如果它们不适用则为 NULL(大大简化):

        SELECT ID, ProductType, m.Name as MagazineName, m.Pages as MagazinePages, 
                                NULL as WebSiteName, NULL as WebSiteURL
                 FROM Magazines m
        UNION ALL
        SELECT ID, ProductType, NULL as MagazineName, NULL as MagazinePages, 
                                w.Name as WebSiteName, w.URL as WebSiteURL
                 FROM WebSites w
        

        会产生如下输出:

        ID   Type       MagazineName   MagazinePages   WebSiteName   WebSiteURL
        1    Magazine   Time           100             NULL          NULL
        2    Magazine   Newsweek       80              NULL          NULL
        3    Website    NULL           NULL            Yahoo         www.yahoo.com
        4    Website    NULL           NULL            Google        www.google.com
        

        【讨论】:

          猜你喜欢
          • 2015-02-15
          • 1970-01-01
          • 2010-11-23
          • 1970-01-01
          • 1970-01-01
          • 2017-10-30
          • 2015-02-19
          • 1970-01-01
          • 2023-03-28
          相关资源
          最近更新 更多