2017-07-09 55 views
1

目前,對於使用不同的參數重複搜索,我有這樣的ActiveRecord查詢生成:大廈的ActiveRecord/SQL查詢

current_user.documents.order(:updated_at).reverse_order.includes(:groups,:rules) 

現在,平時我釘在一個where子句來此執行此搜索。但是,我現在需要通過jsonb字段搜索所有具有特定值的行,如鍵值對中一樣。我已經能夠做一個類似的東西在我的SQL,這種語法(數據字段只會正好有兩個級別的嵌套):

SELECT 
    * 
FROM 
    (SELECT 
     * 
    FROM 
     (SELECT 
      * 
     FROM 
      documents 
     ) A, 
     jsonb_each(A.data) 
    ) B, 
    jsonb_each_text(B.value) ASC C 
WHERE 
    C.value = '30'; 

不過,我想利用當前的ActiveRecord搜索使這個查詢(其中包括組/規則急切加載)。

我與使用逗號,我的理解是一個隱含的加盟,這是明確連接之前執行的掙扎,所以當我嘗試這樣:

select * from documents B join (select * from jsonb_each(B.data)) as A on true; 
ERROR: invalid reference to FROM-clause entry for table "b" 
LINE 1: ...* from documents B join (select * from jsonb_each(B.data)) a... 
                 ^
HINT: There is an entry for table "b", but it cannot be referenced from this part of the query. 

但我不不瞭解如何引用完成的「表」,即在創建聯接調用之前創建的ActiveRecord查詢,以及使用隱式聯接的逗號語法來工作。

另外,我是一個SQL業餘愛好者,所以如果你看到一些改進或其他方式來做到這一點,請告訴。

編輯:文件表的說明:

enter image description here

             Table "public.documents" 
Column  |   Type    |      Modifiers      | Storage | Stats target | Description 
------------+-----------------------------+--------------------------------------------------------+----------+--------------+------------- 
id   | integer      | not null default nextval('documents_id_seq'::regclass) | plain |    | 
document_id | character varying   |              | extended |    | 
name  | character varying   |              | extended |    | 
size  | integer      |              | plain |    | 
last_updated| timestamp without time zone |              | plain |    | 
user_id  | integer      |              | plain |    | 
created_at | timestamp without time zone |              | plain |    | 
updated_at | timestamp without time zone |              | plain |    | 
kind  | character varying   |              | extended |    | 
uid   | character varying   |              | extended |    | 
access_token_id | integer      |              | plain |    | 
data  | jsonb      | not null default '{}'::jsonb       | extended |    | 

指標: 「documents_pkey」 主鍵,B樹(ID) ```

樣品行,首先將匹配搜索'30'(數據是最後一個字段):

2104 | 24419693037           | LsitHandsBackwards.jpg     |  |       |  1 | 2017-06-25 21:45:49.121686 | 2017-07-01 21:32:37.624184 | box   | 221607127   |    15 | {"owner": {"born": "to make history", "price": 30}} 
2177 | /all-drive/uml flows/typicaluseractivity.svg   | TypicalUserActivity.svg     | 12375 | 2014-08-11 02:21:14  |  1 | 2017-07-07 14:00:11.487455 | 2017-07-07 14:00:11.487455 | dropbox  | 325694961   |    20 | {"owner": {}} 
+0

你可以發表你的表和一些樣本數據的定義嗎? – joanolo

+0

@joanolo我添加了一些信息。我也可以發佈小組/規則說明,但我認爲這不會有太大的幫助。 – abcde13

+0

圖像很棒......但文字更好,因爲我們可以複製和播放它。 – joanolo

回答

2

您可以使用一個類似於你已經顯示的查詢:

SELECT 
    d.id, d.data 
FROM 
    documents AS d 
    INNER JOIN json_each(d.data) AS x ON TRUE 
    INNER JOIN json_each(x.value) AS y ON TRUE 
WHERE 
    cast(y.value as text) = '30'; 

假設你的數據將是下列操作之一:

INSERT INTO documents 
    (data) 
VALUES 
    ('{"owner": {"born": "to make history", "price": 30}}'), 
    ('{"owner": {}}'), 
    ('{"owner": {"born": "to make history", "price": 50}, "seller": {"worth": 30}}') 
; 

你會得到的結果是:

 
id | data                   
-: | :--------------------------------------------------------------------------- 
1 | {"owner": {"born": "to make history", "price": 30}}       
3 | {"owner": {"born": "to make history", "price": 50}, "seller": {"worth": 30}} 

你可以在查看它(連同一些一步一步看的數據)dbfiddle here

+0

謝謝@joanolo。最後一個問題是如何把你的sql查詢,並把它放在我原來的查詢頂部的「連接」和「where」方法鏈。我得到的查詢和錯誤是:'current_user.documents.order(:updated_at).reverse_order.includes(:groups,:rules).joins(「INNER JOIN jsonb_each(documents。數據)AS x on TRUE INNER JOIN jsonb_each_text(x.value)AS y on true「)。其中(」value = 30「) PG :: AmbiguousColumn:ERROR:列引用」值「不明確 LINE 1:.. .S y on true WHERE「documents」。「user_id」= $ 1 AND(value = 30 ...'。內部連接是否需要別名列? – abcde13

+0

對不起,但我不太瞭解ActiveRecord *將把你的查詢轉換成我提出的查詢,無論如何,你的* where * condition *應該是*'cast(y.value as text)='30'''''''由'json_each'返回的值是鍵入'json',並且你想把它變成'30',這意味着你必須投它它 – joanolo

+0

我明白了 首先,我的完整查詢如下: 'current_user.documents.order(: ():INNER JOIN jsonb_each(documents.data)AS x on TRUE INNER JOIN LATERAL(select value as v(update_at).reverse_order.includes(:groups,:rules).joins來自jsonb_each_text(x.value))AS y on true「)。其中(」v ='30'「)' 'LATERAL'允許我引用先前的'INNER JOIN'來構建一個查詢。 其次,@joanolo'jsonb_each_text'接受json並將其返回到文本類型中,以便不需要轉換。但是,這兩種形式都是正確的。 感謝您的幫助@joanolo! – abcde13