![](/img/trans.png)
[英]How do you get Rails has_many through relations to work with has_many conditions?
[英]how do I do a join with a polymorphic has_many 'through'?
我具有以下数据结构(简化),该数据结构在购买表(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.amount)排序的类别。 如何使用联接和聚合函数做到这一点?
我为此做了一个sqlfiddle:
多态ID与数据库中的继承结构相似,因为要查询所有多态ID,通常都必须使用并集。
但是,如果您的Books / Shirts / DVDs表没有公共列,则在它们之间进行查询绝对没有任何意义。 如果它们确实具有公共列,那么将其拉入作为其他产品基础的父产品表中可能更有意义。
例如,如果您想要每种产品的总销售额,则只需
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表”
这是一个如何使用临时表实现此目的的示例。 原理是创建一个“临时”表,并在运行查询时在所需的结构中以所需的数据填充该表 。 您可以修改数据,并在最后将其返回,然后在连接关闭时销毁表。
无论如何-您可以像结合新的唯一标识,产品ID,产品类型,产品名称和类别ID的架构那样设置临时表。 然后,在表,DVD和衬衫表中的所有记录之间使用联合 查询填充表以适应该格式:
-- 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.001秒-它将很好地扩展。 我会为此设置一个小提琴,但是SQLFiddle似乎不太支持临时表。 只需在本地服务器上同时运行CREATE和SELECT语句即可查看。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.