我有以下数据结构(简化),其中包含购买表(MySql)中的多态关联
Purchases
product_type (this refers to a table, book, dvd, shirt,...)
product_id (this refers to the product's id in the table in product_type)
amount
Books
category_id
DVDs
category_id
Shirts
category_id
Categories
name
我想从数据库中选择类别,按总销售额(purchases.ountount)排序。如何使用连接和聚合函数执行此操作?
我为此做了一个方便的小说:
答案 0 :(得分:0)
多态ID与数据库中的继承结构类似,因为要查询所有这些,通常必须使用联合。
但是,如果您的书籍/衬衫/ DVD表没有公共列,那么查询它们是完全没有意义的。如果他们确实有共同的列,那么将它拉出到父Product表中可能更有意义,该表作为其他列的基础。
例如,如果您想要每个产品的总销售额,那么您只需
Select sum(amount), product_id -- or product_type if you wanted sales per type
From Purchases
Group By product_id -- product_type
您可以提取以下产品标题:
Select sum(p.amount), p.product_id, b.Title
From Purchases p
Inner Join Books b on b.category_id = p.product_id
Group By product_id
Union
Select sum(p.amount), p.product_id, s.Title
From Purchases p
Inner Join Shirts s on s.category_id = p.product_id
Group By product_id
可能可能更先进行联合,然后再进行组合。
我对继承层次结构的体验是,你应该尽一切可能避免工会。它们很难查询,导致非DRY查询,并且表现不佳。这意味着将诸如Title之类的共性转换为适当的规范化结构,以避免必须跨具体/派生类型进行查询。这基本上是Wrikken在评论中提到的“通常,更好的方法是使用共享信息类型的Products表”
答案 1 :(得分:0)
以下是使用temporary tables如何实现此目标的示例。原则是您create a "temporary" table并在运行查询时在所需的结构中填充所需的数据。您可以修改数据,并在结束时将其返回,然后在连接关闭时销毁该表。
无论如何 - 您可以设置临时表,就像使用新的唯一,产品ID,产品类型,产品名称和类别ID的架构一样。然后,您在书籍,dvds和衬衫表中的所有记录之间使用union query填充表格,以符合以下格式:
-- delete the temp table in case it's still there
DROP TEMPORARY TABLE IF EXISTS all_products;
-- create your new temp table
CREATE TEMPORARY TABLE IF NOT EXISTS all_products (
new_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
product_id INT(11) NOT NULL,
product_type VARCHAR(50) NOT NULL,
product_name VARCHAR(128) NOT NULL,
category_id INT(11) NOT NULL
) AS (
-- populate it with unioned queries
SELECT * FROM (
(SELECT NULL AS new_id, id AS product_id, 'book' AS product_type, `name` AS product_name, category_id FROM books)
UNION ALL
(SELECT NULL AS new_id, id AS product_id, 'dvd' AS product_type, `name` AS product_name, category_id FROM dvds)
UNION ALL
(SELECT NULL AS new_id, id AS product_id, 'shirt' AS product_type, `name` AS product_name, category_id FROM shirts)
) AS temp -- an alias is required - doesn't matter what it is
);
现在您可以像往常一样访问此表中的数据。使用临时表的好处是你不必改变你的数据库结构 - 在你的情况下,它可能不是理想的设置它的方式,但做这样的事情可以帮助你在不改变数据的情况下有效地选择数据。
要选择数据,您可以使用如下查询:
SELECT
purchase.*,
product.product_name,
category.name
FROM purchases AS purchase
-- get your product info from the temp table
INNER JOIN all_products AS product
ON (product.product_id = purchase.product_id AND product.product_type = purchase.product_type)
-- get the category name
INNER JOIN categories AS category
ON (category.id = product.category_id)
您说您想按金额等订购结果。根据需要在上面的查询中添加条件和订购。
示例输出:
id product_id product_type amount product_name name
1 1 book 10 how to educational
2 1 dvd 10 video how to educational
3 1 shirt 10 tshirt clothes
这些实际上可以非常有效地运行,例如在我的本地服务器上运行它在0.001s内执行 - 它将非常好地扩展。我会为你设置一个小提琴,但SQLFiddle似乎并不能很好地支持临时表。只需在本地服务器上同时运行CREATE和SELECT语句即可查看。