Railsでモードを明確にしようとしています。
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への変換はオプションではありません。回避策はありますか?
この理由は、PostgreSQL(9.3まで)でjson
に定義された等値演算子がない(つまり、_val1::json = val2::json
_は常にこの例外をスローする)ためです。9.4では、 jsonb
タイプ。
回避策の1つは、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グループ内の行の望ましい優先順位を決定する追加の式が含まれます。
申し訳ありませんが、この回答には遅れていますが、他の人の助けになるかもしれません。
クエリを理解すると、profiles
への多対多結合(アクセスするintegrations
を決定するために使用しているため)がprofiles
で重複する可能性があります。
そのため、新しいGROUP BY
機能を使用できます 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
アプローチでできます。幸せな日々! :)
PG 9.4を使用する場合、JSONではなくJSONBを使用すると、この問題が解決されます例:
-- 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がJSONBカラムでDISTINCTを暗示することに成功した一方で、JSONカラムでは失敗したことがわかります。
以下も試して、実際に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"、 "a": "1"}'が '{"a": "1"、 "b": "2"}'として挿入されたことに注意してください。記録:
select distinct * from t2;
3 | {"a": "1", "b": "2"}
2 | {"key": "value"}
1 | {"name": "value"}
残念ながら、postgres json
は等式を実装していませんが、jsonb
は実装しています。したがって、json
列をjsonb
に移行すると、問題なく動作するはずです。