2015-05-21 153 views
1

我需要幫助將此SQL轉換爲ActiveRecord查詢。對Rails和SQL的相同查詢返回不同的結果

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 

但這返回on 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" 
... 

,這就是我想要的。在數據庫控制檯上它可以工作,但在Rails上它卻不行。 :(

+0

這裏是工作的查詢的例子:http://sqlfiddle.com/#!9/7a6d1/1/0。這同樣不適用於Rails .. –

+0

猜測它是外部左連接和左連接產生的行爲。看看:http://stackoverflow.com/questions/8025429/how-can-i-do-a-left-outer-join-using-rails-activerecord另請看:http://www.codeproject.com/文章/ 33052/Visual-Representation of SQL-Joins一種方法可能是在獲取記錄後刪除位置並進行過濾,具體取決於記錄集大小 – Mircea

+0

使用或不使用OUTER的查詢都會在數據庫上生成所需的輸出安慰。看起來問題在於AR如何通過散列來改變它。 –

回答

0

這似乎是在Rails中的一個錯誤。如果你用group從改變你的線路:

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

到:!

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

它的工作原理NB,你應該使用以逗號分隔的兩個字符串

必須在Rails從SQL呈現結果時認爲該組只有一個如果它在一個字符串中,儘管它構建了一個正確的SQL查詢。你知道如何使用它

=> {["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避免 「硬編碼」 表名,你可以用這個!

cust = Customer.arel_table 
prod = ProductCategory.arel_table 
TotalSales.joins(:customer).includes(:product_category). 
    where(cust[:organization_id].eq(1)). 
    group(cust[:external_id], prod[:external_id]). 
    maximum(:start_date) 
0

包括= LEFT JOIN

,當你想你不應該使用includes(othertable)您的查詢以某種方式取決於othertable,因爲includes它具有不同的語義。

With包括你只是說ActiveRecord,你打算從很快得到的對象,所以它應該優化它。但它是面向對象的。在您的示例中獲得TotalSales對象。

連接是一個關係數據庫的事情,其中​​表的列可以混合。我們通常不會在物體世界中做這樣的事情。那爲什麼這往往變得困難。

如果你需要一個左連接,你需要告訴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

相關問題