Rails和SQL上的相同查询返回不同的结果

时间:2015-05-21 18:38:11

标签: ruby-on-rails ruby postgresql ruby-on-rails-4 activerecord

我需要帮助将此SQL转换为ActiveRecord查询。

SELECT 
  MAX(total_sales.start_date) AS maximum_start_date,
  customers.external_id, product_categories.external_id AS product_category_id
FROM
  total_sales
INNER JOIN 
  customers
ON
  customers.id = total_sales.customer_id
LEFT JOIN
  product_categories
ON
  product_categories.id = total_sales.product_category_id
WHERE 
  (customers.organization_id = 1)
GROUP BY
  customers.external_id,
  product_categories.external_id

我试过

TotalSales.joins(:customer).includes(:product_category).
  where("customers.organization_id = ?", 1).
  group("customers.external_id, product_categories.external_id").
  maximum(:start_date)

它几乎生成了我想要的查询。这就是它产生的结果:

SELECT
  MAX("total_sales"."start_date") AS maximum_start_date, 
  customers.external_id, product_categories.external_id AS customers_external_id_product_categories_external_id
FROM
  "total_sales"
INNER JOIN "customers" ON
  "customers"."id" = "total_sales"."customer_id"
LEFT OUTER JOIN "product_categories" ON
  "product_categories"."id" = "total_sales"."product_category_id" 
WHERE
  (customers.organization_id = 1)
GROUP BY
  customers.external_id, product_categories.external_id

但这会在Rails上返回:

=> {"DIA"=>Wed, 01 Jan 2014, "MES"=>Wed, 01 Jan 2014, nil=>Wed, 01 Jan 2014}

如果我在DB控制台上运行该查询,则返回

"2014-01-01";"CLIENTE.1";"DIA"
"2014-01-01";"CLIENTE.1";"MES"
"2014-01-01";"CLIENTE.1";""
"2014-01-01";"CLIENTE.10";"DIA"
"2014-01-01";"CLIENTE.10";"MES"
"2014-01-01";"CLIENTE.10";""
"2014-01-01";"CLIENTE.100";"DIA"
"2014-01-01";"CLIENTE.100";"MES"
...

这就是我想要的。在DB控制台上它可以工作,但在Rails上却没有。 :(

2 个答案:

答案 0 :(得分:0)

这似乎是Rails中的一个错误。如果您使用std::make_pair({a,c,e}, {g,f,e})来改变您的行:

group

为:

group("customers.external_id, product_categories.external_id").

它有效。 NB!你应该使用两个用逗号分隔的字符串。

当Rails从SQL呈现结果时,它必须认为该组只有一个字段(如果它在一个字符串中),尽管它构建了正确的SQL查询。

您将获得此结果:

group("customers.external_id", "product_categories.external_id").

我假设您知道如何使用它。

一点提示,使用=> {["CLIENTE.1", "DIA"]=>Wed, 01 Jan 2014, ["CLIENTE.1", "MES"]=>Wed, 01 Jan 2014, ["CLIENTE.1", nil]=>Wed, 01 Jan 2014, ["CLIENTE.10", "DIA"]=>Wed, 01 Jan 2014, ["CLIENTE.10", "MES"]=>Wed, 01 Jan 2014, ["CLIENTE.10", nil]=>Wed, 01 Jan 2014, ...} 来避免“硬代码”表名,你可以使用这个:

Arel

答案 1 :(得分:0)

包括!= LEFT JOIN

如果您希望查询以某种方式依赖于includes(othertable),则不应使用othertable,因为includes它具有不同的语义。

对于包含你只是说ActiveRecord,你打算尽快从对象中获取对象,所以它应该优化它。但它是面向对象的。您的示例中会得到TotalSales个对象。

join是一个关系数据库的东西,可以混合表的列。我们通常不会在对象世界中做这样的事情。这就是为什么这经常变得困难。

如果你需要左连接,你需要告诉rails。根据rails指南,您需要使用SQL片段。

TotalSales.joins('LEFT OUTER JOIN product_categories ON product_categories.id = total_sales.product_category_id')
...

另见我对这个问题的回答: Rails 4 Relation is not being sorted: 'has_many' association w/ default scope, 'includes' and 'order' chained together