亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

用實例和組動態替代樞軸

用實例和組動態替代樞軸

HUWWW 2019-06-25 15:08:27
用實例和組動態替代樞軸我有張桌子看起來像這樣:id    feh    bar1     10     A2     20     A3      3     B4      4     B5      5     C6      6     D7      7     D8      8     D我想讓它看起來像這樣bar  val1   val2   val3A     10     20 B      3      4 C      5        D      6      7     8我有這樣一個查詢:SELECT bar,    MAX(CASE WHEN abc."row" = 1 THEN feh ELSE NULL END) AS "val1",   MAX(CASE WHEN abc."row" = 2 THEN feh ELSE NULL END) AS "val2",   MAX(CASE WHEN abc."row" = 3 THEN feh ELSE NULL END) AS "val3"FROM(  SELECT bar, feh, row_number() OVER (partition by bar) as row  FROM "Foo" ) abcGROUP BY bar這是一種非常巧妙的方法,如果需要創建大量的新列,就會變得難以處理。我在想如果CASE語句可以更好地使查詢更動態嗎?而且,我也希望看到其他的方法來做這件事。
查看完整描述

3 回答

?
海綿寶寶撒

TA貢獻1809條經驗 獲得超8個贊

如果沒有安裝附加模塊[醫]tablefunc,運行以下命令一次每個數據庫:

CREATE EXTENSION tablefunc;

對問題的回答

對于您的情況,一個非?;镜慕徊姹斫鉀Q方案:

SELECT * FROM crosstab(
  'SELECT bar, 1 AS cat, feh
   FROM   tbl_org
   ORDER  BY bar, feh')
 AS ct (bar text, val1 int, val2 int, val3 int);  -- more columns?

這個特殊困難在這里,沒有范疇 (cat)在基表中?;?/trans>1-參數形式我們只需提供一個具有虛擬值的虛擬列作為類別。無論如何,這個值都會被忽略。

這是罕見病例在那里第二參數crosstab()功能是不需要,因為所有NULL值僅顯示在此問題的定義右側的懸空列中。的順序可以由價值.

如果我們有一個范疇列的名稱確定結果中值的順序,我們需要2-參數形式crosstab()..這里,我借助窗口函數合成了一個類別列。row_number(),到基地crosstab()關于:

SELECT * FROM crosstab(
   $$
   SELECT bar, val, feh   FROM  (
      SELECT *, 'val' || row_number() OVER (PARTITION BY bar ORDER BY feh) AS val      FROM tbl_org      ) x   ORDER BY 1, 2
   $$
 , $$VALUES ('val1'), ('val2'), ('val3')$$         -- more columns?) AS ct (bar text, val1 int, val2 int, val3 int);  -- more columns?

剩下的差不多是一成不變的。在這些緊密相關的答案中可以找到更多的解釋和鏈接。

基本要素:
如果您不熟悉crosstab()功能!

高級:

適當的測試裝置

首先,您應該提供一個測試用例:

CREATE TEMP TABLE tbl_org (id int, feh int, bar text);INSERT INTO tbl_org (id, feh, bar) VALUES
   (1, 10, 'A')
 , (2, 20, 'A')
 , (3,  3, 'B')
 , (4,  4, 'B')
 , (5,  5, 'C')
 , (6,  6, 'D')
 , (7,  7, 'D')
 , (8,  8, 'D');

動態交叉表?

不太動態然而,@Clodoaldo評論..使用plpgsql很難實現動態返回類型。但在那里繞過它-有一些限制.

因此,為了不讓剩下的事情變得更復雜,我用一個更簡單測試用例:

CREATE TEMP TABLE tbl (row_name text, attrib text, val int);INSERT INTO tbl (row_name, attrib, val) VALUES
   ('A', 'val1', 10)
 , ('A', 'val2', 20)
 , ('B', 'val1', 3)
 , ('B', 'val2', 4)
 , ('C', 'val1', 5)
 , ('D', 'val3', 8)
 , ('D', 'val1', 6)
 , ('D', 'val2', 7);

呼叫:

SELECT * FROM crosstab('SELECT row_name, attrib, val FROM tbl ORDER BY 1,2')AS ct (row_name text, val1 int, val2 int, val3 int);

返回:

 row_name | val1 | val2 | val3----------+------+------+------
 A        | 10   | 20   |
 B        |  3   |  4   |
 C        |  5   |      |
 D        |  6   |  7   |  8

內建特征tablefunc模塊

tablefunc模塊為泛型提供了一個簡單的基礎結構。crosstab()調用,而不提供列定義列表。編寫的一些函數C(通常速度非常快):

crosstabN()


crosstab1() - crosstab4()都是預定義的。有一點是次要的:他們需要并返回所有text..所以我們需要integer價值。但它簡化了呼叫:

SELECT * FROM crosstab4('SELECT row_name, attrib, val::text  -- cast!
                         FROM tbl ORDER BY 1,2')

結果:

 row_name | category_1 | category_2 | category_3 | category_4----------+------------+------------+------------+------------
 A        | 10         | 20         |            |
 B        | 3          | 4          |            |
 C        | 5          |            |            |
 D        | 6          | 7          | 8          |

習俗crosstab()功能

更多列其他數據類型,我們創造了我們自己的復合型功能(一次)。
類型:

CREATE TYPE tablefunc_crosstab_int_5 AS (
  row_name text, val1 int, val2 int, val3 int, val4 int, val5 int);

職能:

CREATE OR REPLACE FUNCTION crosstab_int_5(text)
  RETURNS SETOF tablefunc_crosstab_int_5AS '$libdir/tablefunc', 'crosstab' LANGUAGE c STABLE STRICT;

呼叫:

SELECT * FROM crosstab_int_5('SELECT row_name, attrib, val   -- no cast!
                              FROM tbl ORDER BY 1,2');

結果:

 row_name | val1 | val2 | val3 | val4 | val5----------+------+------+------+------+------
 A        |   10 |   20 |      |      |
 B        |    3 |    4 |      |      |
 C        |    5 |      |      |      |
 D        |    6 |    7 |    8 |      |

多態的,動態的

這超出了tablefunc模塊。
為了使返回類型動態,我使用多態類型,并在這個相關的答案中詳細介紹了一種技術:



1-參數形式:

CREATE OR REPLACE FUNCTION crosstab_n(_qry text, _rowtype anyelement)
  RETURNS SETOF anyelement AS$func$BEGIN
   RETURN QUERY EXECUTE 
   (SELECT format('SELECT * FROM crosstab(%L) t(%s)'
                , _qry                , string_agg(quote_ident(attname) || ' ' || atttypid::regtype                           
                , ', ' ORDER BY attnum))
    FROM   pg_attribute    WHERE  attrelid = pg_typeof(_rowtype)::text::regclass    AND    attnum > 0
    AND    NOT attisdropped);END$func$  LANGUAGE plpgsql;

使用此變體重載2-參數形式:

CREATE OR REPLACE FUNCTION crosstab_n(_qry text, _cat_qry text, _rowtype anyelement)
  RETURNS SETOF anyelement AS$func$BEGIN
   RETURN QUERY EXECUTE 
   (SELECT format('SELECT * FROM crosstab(%L, %L) t(%s)'
                , _qry, _cat_qry                , string_agg(quote_ident(attname) || ' ' || atttypid::regtype                           
                , ', ' ORDER BY attnum))
    FROM   pg_attribute    WHERE  attrelid = pg_typeof(_rowtype)::text::regclass    AND    attnum > 0
    AND    NOT attisdropped);END$func$  LANGUAGE plpgsql;

pg_typeof(_rowtype)::text::regclass:為每個用戶定義的復合類型定義了行類型,以便在系統目錄中列出屬性(列)。pg_attribute..要得到它的快車道:拋出已注冊的類型(regtype)到text投下這個textregclass.

創建組合類型一次:

您需要定義一次要使用的每個返回類型:

CREATE TYPE tablefunc_crosstab_int_3 AS (
    row_name text, val1 int, val2 int, val3 int);CREATE TYPE tablefunc_crosstab_int_4 AS (
    row_name text, val1 int, val2 int, val3 int, val4 int);...

對于臨時調用,您還可以創建一個臨時表產生同樣(臨時)效果:

CREATE TEMP TABLE temp_xtype7 AS (
    row_name text, x1 int, x2 int, x3 int, x4 int, x5 int, x6 int, x7 int);

如果可用,則使用現有表、視圖或物化視圖的類型。

打電話

使用上述行類型:

1-參數形式(無缺失值):

SELECT * FROM crosstab_n(
   'SELECT row_name, attrib, val FROM tbl ORDER BY 1,2'
 , NULL::tablefunc_crosstab_int_3);

2-參數形式(可能缺少一些值):

SELECT * FROM crosstab_n(
   'SELECT row_name, attrib, val FROM tbl ORDER BY 1'
 , $$VALUES ('val1'), ('val2'), ('val3')$$
 , NULL::tablefunc_crosstab_int_3);

這,這個單函數適用于所有返回類型,而crosstabN()委員會提供的框架tablefunc每個模塊都需要一個單獨的函數。
如果您按照上面演示的順序命名了您的類型,則只需替換粗體數字即可。若要在基表中查找最大類別數,請執行以下操作:

SELECT max(count(*)) OVER () FROM tbl  -- returns 3GROUP  BY row_name
LIMIT  1;

如果你想的話,這幾乎是動態的個別列..數組由@Clocoldo演示或簡單的文本表示形式或封裝在文檔類型中的結果,如jsonhstore可以動態地處理任意數量的類別。

免責聲明:
當用戶輸入轉換為代碼時,總是存在潛在的危險。確保這不能用于SQL注入。不要接受來自不可信用戶的輸入(直接)。

要求提出原始問題:

SELECT * FROM crosstab_n('SELECT bar, 1, feh FROM tbl_org ORDER BY 1,2'
                       , NULL::tablefunc_crosstab_int_3);


查看完整回答
反對 回復 2019-06-25
?
RISEBY

TA貢獻1856條經驗 獲得超5個贊

我已經在其他答案中建議了JSON方法,在9.6的方便之前。json_object_agg功能。使用以前的工具集只需要更多的工作。

引用的兩個可能的缺點實際上不是。如果有必要,對隨機密鑰順序進行小的修正。丟失的鍵(如果相關的話)需要處理幾乎微不足道的代碼:

select
    row_name as bar,
    json_object_agg(attrib, val order by attrib) as datafrom
    tbl    right join
    (
        (select distinct row_name from tbl) a        cross join
        (select distinct attrib from tbl) b    ) c using (row_name, attrib)group by row_nameorder by row_name;
 bar |                     data                     
-----+----------------------------------------------
 a   | { "val1" : 10, "val2" : 20, "val3" : null }
 b   | { "val1" : 3, "val2" : 4, "val3" : null }
 c   | { "val1" : 5, "val2" : null, "val3" : null }
 d   | { "val1" : 6, "val2" : 7, "val3" : 8 }

對于理解JSON的最后一個查詢使用者來說,沒有缺點。唯一的原因是它不能作為表源使用。


查看完整回答
反對 回復 2019-06-25
  • 3 回答
  • 0 關注
  • 398 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號