簡體   English   中英

棘手的PostgreSQL連接和順序查詢

[英]Tricky PostgreSQL join and order query

我在PostgreSQL 9.3.6數據庫中有四個表:

  • 部分
  • 字段 (部分的子項)
  • 條目 (部分的子
  • 數據 (條目的子項)

CREATE TABLE section (
  id serial PRIMARY KEY,
  title text,
  "group" integer
);

CREATE TABLE fields (
  id serial PRIMARY KEY,
  title text,
  section integer,
  type text,
  "default" json
);

CREATE TABLE entries (
  id serial PRIMARY KEY,
  section integer
);

CREATE TABLE data (
  id serial PRIMARY KEY,
  data json,
  field integer,
  entry integer
);

我正在嘗試生成一個如下所示的頁面:

section title

          field 1 title  | field 2 title | field 3 title 
entry 1 | data 'as' json | data 1 json   | data 3 json        <-- table
entry 2 | data 'df' json | data 5 json   | data 6 json  
entry 3 | data 'gh' json | data 8 json   | data 9 json  

我現在設置的方式是,每個“數據”都有一個鏈接到的條目,一個對應的字段(該字段具有確定應如何解釋數據的json字段的列),一個json字段,用於存儲不同類型的數據和ID(表中此處為1-9)。

在此示例中,有3個條目和3個字段,並且中間的每個單元都有一個數據段。

之所以這樣設置,是因為一個部分的字段類型和數量可以與另一部分不同,因此數據的數量和類型也不同。

挑戰1:

我正在嘗試以一種可按任何列(該字段的json列的數據內容)排序的方式將表連接在一起。 例如,我希望能夠以相反的順序對字段3(第三列)進行排序,該表將如下所示:

section title

          field 1 title  | field 2 title | field 3 title 
entry 3 | data 'gh' json | data 8 json   | data 9 json  
entry 2 | data 'df' json | data 5 json   | data 6 json  
entry 1 | data 'as' json | data 1 json   | data 3 json        <-- table

如果有更好的方法,我也樂於采用另一種方法。

挑戰2:

每個字段都有一個“默認值”列-理想情況下,當它們的值不是該默認值時,我只需要創建“數據”條目即可。 因此,如果字段2的默認值為'asdf',則該表實際上可能看起來像這樣:

section title

          field 1 title  | field 2 title | field 3 title 
entry 3 | data 'gh' json | data 8 json   | data 9 json  
entry 2 | data 'df' json | 'asdf'        | data 6 json  
entry 1 | data 'as' json | 'asdf'        | data 3 json        <-- table

編寫此查詢的關鍵是要理解,您只需要獲取單個節的所有數據以及您剛剛加入的其余數據。 您也無法使用架構直接按節過濾數據,因此您僅需要為此而加入條目:

SELECT d.* FROM data d JOIN entries e ON (d.entry = e.id) 
WHERE e.section = ?

然后,您可以將字段連接到每一行以獲取默認值,類型和標題:

SELECT d.*, f.title, f.type, f."default" 
FROM data d JOIN entries e ON (d.entry = e.id) 
            JOIN fields f ON (d.field = f.id)
WHERE e.section = ?

或者,您可以在單獨的查詢中選擇字段以節省一些網絡流量。

所以這是一個答案,這里是獎金:

  1. 使用外鍵而不是整數來引用其他表,它將使數據庫檢查一致性。

  2. 關系(表)應按慣例以單數形式調用,因此它是sectionentryfield

  3. 引用字段也稱為<name>_id ,例如,按照慣例也稱為field_idsection_id

  4. JSON字段的全部重點是存儲一個非靜態定義的數據的集合,因此,不使用entriesdata表,而是使用包含所有字段的JSON的單個表,會更有意義。

像這樣:

CREATE TABLE row ( -- less generic name would be even better
    id int primary key,
    section_id int references section (id),
    data json
)

data字段包含以下內容:

{
    "title": "iPhone 6",
    "price": 650,
    "available": true,
    ...
}

@Suor提供了很好的建議,您已經接受了其中的一些建議。 我建立在更新的架構上

架構

CREATE TABLE section (
  section_id serial PRIMARY KEY,
  title text,
  grp integer
);

CREATE TABLE field (
  field_id serial PRIMARY KEY,
  section_id integer REFERENCES section,
  title text,
  type text,
  default_val json
);

CREATE TABLE entry (
  entry_id serial PRIMARY KEY,
  section_id integer REFERENCES section
);

CREATE TABLE data (
  data_id serial PRIMARY KEY,
  field_id integer REFERENCES field,
  entry_id integer REFERENCES entry,
  data json
);

我又更改了兩個細節:

  • section_id代替id ,等等。“ id”作為列名是一種反模式,因為幾個ORM都在使用它。 別。 描述性名稱要好得多。 相同內容的相同名稱是有用的指南。 它還允許在join子句中使用快捷方式USING

  • 不要使用保留字作為標識符。 僅使用合法的小寫,無引號的名稱可以使您的生活更輕松。

參照完整性?

您的設計還有另一個固有的弱點。 是什么阻止data條目引用field和不在一起的entry 關於dba.SE的密切相關的問題

詢問

不知道您是否需要復雜的設計。 但是要回答這個問題,這是基本查詢:

SELECT entry_id, field_id, COALESCE(d.data, f.default_val) AS data
FROM   entry     e
JOIN   field     f USING (section_id)
LEFT   JOIN data d USING (field_id, entry_id)  -- can be missing
WHERE  e.section_id = 1
ORDER  BY 1, 2;

LEFT JOIN對於允許丟失數據條目並使用默認值至關重要。

SQL提琴。

crosstab()

最后一步是交叉制表。 由於未安裝其他模塊tablefunc因此無法在SQL Fiddle中顯示此內容。

crosstab()基礎知識:

SELECT * FROM crosstab(
   $$
   SELECT entry_id, field_id, COALESCE(d.data, f.default_val) AS data
   FROM   entry     e
   JOIN   field     f USING (section_id)
   LEFT   JOIN data d USING (field_id, entry_id)  -- can be missing
   WHERE  e.section_id = 1
   ORDER  BY 1, 2
   $$
  ,$$SELECT field_id FROM field WHERE section_id = 1 ORDER BY field_id$$
   ) AS ct (entry int, f1 json, f2 json, f3 json)  -- static
ORDER  BY f3->>'a';  -- static

這里最棘手的部分是函數的返回類型。 我為3個字段提供了一個靜態類型,但您確實希望該動態類型。 另外,我引用的是json類型的字段,該字段可能存在或可能不存在。因此,動態構建該查詢並在第二次調用中執行它。

有關更多信息:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM