2014-05-07 30 views
32

試圖在使用rails的模式上做不同的處理。不同於Postgresql JSON數據列

2.1.1 :450 > u.profiles.select("profiles.*").distinct 


Profile Load (0.9ms) SELECT DISTINCT profiles.* FROM "profiles" INNER JOIN "integration_profiles" ON "profiles"."id" = "integration_profiles"."profile_id" INNER JOIN "integrations" ON "integration_profiles"."integration_id" = "integrations"."id" WHERE "integrations"."user_id" = $1 [["user_id", 2]] 
PG::UndefinedFunction: ERROR: could not identify an equality operator for type json 
LINE 1: SELECT DISTINCT profiles.* FROM "profiles" INNER JOIN "integ... 
         ^
: SELECT DISTINCT profiles.* FROM "profiles" INNER JOIN "integration_profiles" ON "profiles"."id" = "integration_profiles"."profile_id" INNER JOIN "integrations" ON "integration_profiles"."integration_id" = "integrations"."id" WHERE "integrations"."user_id" = $1 
ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR: could not identify an equality operator for type json 
LINE 1: SELECT DISTINCT profiles.* FROM "profiles" INNER JOIN "integ... 
         ^
: SELECT DISTINCT profiles.* FROM "profiles" INNER JOIN "integration_profiles" ON "profiles"."id" = "integration_profiles"."profile_id" INNER JOIN "integrations" ON "integration_profiles"."integration_id" = "integrations"."id" WHERE "integrations"."user_id" = $1 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/rack-mini-profiler-0.9.1/lib/patches/sql_patches.rb:109:in `prepare' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/rack-mini-profiler-0.9.1/lib/patches/sql_patches.rb:109:in `prepare' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/connection_adapters/postgresql_adapter.rb:834:in `prepare_statement' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/connection_adapters/postgresql_adapter.rb:795:in `exec_cache' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/connection_adapters/postgresql/database_statements.rb:139:in `block in exec_query' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/connection_adapters/abstract_adapter.rb:442:in `block in log' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activesupport-4.0.4/lib/active_support/notifications/instrumenter.rb:20:in `instrument' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/connection_adapters/abstract_adapter.rb:437:in `log' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/connection_adapters/postgresql/database_statements.rb:137:in `exec_query' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/connection_adapters/postgresql_adapter.rb:908:in `select' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/connection_adapters/abstract/database_statements.rb:32:in `select_all' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/connection_adapters/abstract/query_cache.rb:63:in `select_all' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/querying.rb:36:in `find_by_sql' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/relation.rb:585:in `exec_queries' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/association_relation.rb:15:in `exec_queries' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/relation.rb:471:in `load' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/relation.rb:220:in `to_a' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/activerecord-4.0.4/lib/active_record/relation.rb:573:in `inspect' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/railties-4.0.4/lib/rails/commands/console.rb:90:in `start' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/railties-4.0.4/lib/rails/commands/console.rb:9:in `start' 
    from /Users/mmahalwy/.rvm/gems/ruby-2.1.1/gems/railties-4.0.4/lib/rails/commands.rb:62:in `<top (required)>' 
    from bin/rails:4:in `require' 
    from bin/rails:4:in `<main>'2.1.1 :451 > 

得到一個錯誤PG::UndefinedFunction: ERROR: could not identify an equality operator for type json

轉換爲Hstore是不是在這種情況下,我的選擇。任何解決方法?

回答

42

這背後的原因是,在PostgreSQL的(高達9.3)沒有用於json沒有定義相等操作符(即val1::json = val2::json總會拋出此異常) - 在9.4會有一個用於jsonb類型。

一種解決方法是,您可以將您的json字段投射到text。但是這不會涵蓋所有JSON平衡。 f.ex. {"a":1,"b":2}應該等於{"b":2,"a":1},但如果鑄造爲text,則不會相同。

另一個解決方法是(如果你有該表的主鍵 - 這應該是)你可以使用DISTINCT ON (<expressions>) form

u.profiles.select("DISTINCT ON (profiles.id) profiles.*") 

注意:一個已知的警告爲DISTINCT ON

DISTINCT ON表達式必須匹配最左邊的ORDER BY表達式。 ORDER BY子句通常包含額外的表達式,這些表達式決定了每個DISTINCT ON組內行的期望優先級。

+0

我實際上結束了做的DISTINCT ON profiles.id。這對我來說是最好的解決方案 –

+0

如何在選擇語句中將您的json作爲文本進行投射? – ionescho

+1

@ionescho我相信你現在已經找到了這個,但':: text'應該這樣做。 – fzzfzzfzz

4

對不起,我遲到了這個答案,但它可能會幫助別人。

根據我的理解,只有profiles因爲多對多連接integrations(您用來確定要訪問哪個profiles)才能獲得重複項。

正因爲如此,你可以使用一個新GROUP BY功能as of 9.1

當GROUP BY存在,它是不是有效的SELECT列表中的表達式是指未分組列除了聚集函數或者內未分組的列在功能上依賴於分組列,因爲否則會有多個可能的值返回未分組列。如果分組列(或其子集)是包含未分組列的表的主鍵,則存在函數依賴關係。

所以你的情況,你可以讓Ruby創建查詢(對不起,我不知道的Ruby語法你使用)...

SELECT profiles.* 
FROM "profiles" 
    INNER JOIN "integration_profiles" ON "profiles"."id" = "integration_profiles"."profile_id" 
    INNER JOIN "integrations" ON "integration_profiles"."integration_id" = "integrations"."id" 
WHERE "integrations"."user_id" = $1 
GROUP BY "profiles"."id" 

我只取出DISTINCT從您的SELECT條款和添加GROUP BY

僅通過參考GROUP BY中的id,您可以充分利用該新功能,因爲所有其餘的profiles列都對該ID主鍵具有「功能上的依賴性」。

不知何故,奇妙的是避免了需要Postgres的做對因列平等檢查(即在這種情況下,你json列)。

DISTINCT ON解決方案也很棒,在你的情況下顯然是足夠的,但你不能像array_agg那樣使用聚合函數。你可以用這個GROUP BY方法。快樂的時光! :)

1

如果使用PG 9.4,使用JSONB而不是JSON解決了這個問題 例子:

-- JSON datatype test 

create table t1 (id int, val json); 
insert into t1 (id,val) values (1,'{"name":"value"}'); 
insert into t1 (id,val) values (1,'{"name":"value"}'); 
insert into t1 (id,val) values (2,'{"key":"value"}'); 
select * from t1 order by id; 
select distinct * from t1 order by id; 

-- JSONB datatype test 

create table t2 (id int, val jsonb); 
insert into t2 (id,val) values (1,'{"name":"value"}'); 
insert into t2 (id,val) values (1,'{"name":"value"}'); 
insert into t2 (id,val) values (2,'{"key":"value"}'); 

select * from t2 order by id; 

select distinct * from t2 order by id; 

Result of running the above script : 

CREATE TABLE 
INSERT 0 1 
INSERT 0 1 
INSERT 0 1 
1 | {"name":"value"} 
1 | {"name":"value"} 
2 | {"key":"value"} 

ERROR: could not identify an equality operator for type json 
LINE 1: select distinct * from t1 order by id; 
        ^
CREATE TABLE 
INSERT 0 1 
INSERT 0 1 
INSERT 0 1 
1 | {"name": "value"} 
1 | {"name": "value"} 
2 | {"key": "value"} 

1 | {"name": "value"} 
2 | {"key": "value"} 

正如你可以看到PG成功,而失敗的一個JSON意味着DISTINCT上JSONB列 專欄!

嘗試也下面,看看在JSONB實際鍵進行排序:

insert into t2 values (3, '{"a":"1", "b":"2"}'); 
insert into t2 values (3, '{"b":"2", "a":"1"}'); 
select * from t2; 

1 | {"name": "value"} 
1 | {"name": "value"} 
2 | {"key": "value"} 
3 | {"a": "1", "b": "2"} 
3 | {"a": "1", "b": "2"} 

注意, '{ 「B」: 「2」, 「一個」: 「1」}' 被插入作爲'{ 「一」: 「1」, 「b」: 「2」}' 爲此PG標識爲相同的記錄:

select distinct * from t2; 
3 | {"a": "1", "b": "2"} 
2 | {"key": "value"} 
1 | {"name": "value"} 
相關問題