Postgresql

pl/pgsql:從記錄中動態獲取列名

  • February 12, 2017

問候,我想從記錄中動態獲取列名。如下面的程式碼所示,我創建了一個游標,並使用循環來處理該游標中的每條記錄,方法是將每一行提取到記錄類型 r1。在我的表中,我有這些列

$$ dlq_2000,dlq_2001,…,dlq_2017,dlq_2017 $$. 我還在它之上創建了一個循環來單獨處理每一列。 我面臨的問題是從 r1 動態獲取欄位名稱,並且在執行程式碼時出現此錯誤:

$$ Err $$錯誤:記錄 “r1” 沒有欄位 “‘dlq_’||counter::text” 上下文:SQL 語句 “SELECT (r1."‘dlq_’||counter::text” = 1 )"

請建議如何解決這個問題。

謝謝,

CREATE OR REPLACE FUNCTION update()
  RETURNS VOID AS $$
DECLARE 
cur SCROLL CURSOR   FOR select * from my_tbl;
r1 RECORD;
begin
OPEN cur ;
FOR counter IN  2000..2017 LOOP
   r1 := NULL;
   LOOP
       FETCH cur INTO r1;
       EXIT WHEN NOT FOUND;

       IF (r1."'dl_'||counter::text" = 1 ) THEN
           -- do some thing
           RAISE NOTICE 'processing year of : %', counter;
       END IF;     
   END LOOP;
END LOOP;
CLOSE cur;
END; 

$$

LANGUAGE plpgsql;

您沒有簡單的方法來檢查“變數列”。有一種(不是很優雅的)方法可以通過使用 a 來實現此結果CASE

CREATE OR REPLACE FUNCTION update()
   RETURNS VOID AS $$
DECLARE 
   cur SCROLL CURSOR   FOR select * from my_tbl;
   r1 RECORD;
BEGIN
   OPEN cur ;
   FOR counter IN  2000..2017 LOOP
       r1 := NULL;
       LOOP
           FETCH cur INTO r1;
           EXIT WHEN NOT FOUND;

           IF
             (CASE counter 
               WHEN 2000 THEN r1.dl_2000
               WHEN 2001 THEN r1.dl_2001
               WHEN 2002 THEN r1.dl_2002
               WHEN 2003 THEN r1.dl_2003
               WHEN 2004 THEN r1.dl_2004
               WHEN 2005 THEN r1.dl_2005
               WHEN 2006 THEN r1.dl_2006
               WHEN 2007 THEN r1.dl_2007
               WHEN 2008 THEN r1.dl_2008
               WHEN 2009 THEN r1.dl_2009
               WHEN 2010 THEN r1.dl_2010
               WHEN 2011 THEN r1.dl_2011
               WHEN 2012 THEN r1.dl_2012
               WHEN 2013 THEN r1.dl_2013
               WHEN 2014 THEN r1.dl_2014
               WHEN 2015 THEN r1.dl_2015
               WHEN 2016 THEN r1.dl_2016
               WHEN 2017 THEN r1.dl_2017
             END) = 1 
           THEN
               -- do some thing
               RAISE NOTICE 'processing year of : %', counter;
           END IF;     
       END LOOP;
   END LOOP;
   CLOSE cur;
END; 
$$
LANGUAGE plpgsql;

我假設所有列dl_2000..dl_2017都定義為integer(或bit)。也就是說,表定義如下所示:

CREATE TABLE t
(
   /* some columns */
   dl_2000 integer, 
   dl_2001 integer, 
   dl_2002 integer, 
   dl_2003 integer, 
   /* ... */
   dl_2017 integer,
   /* more columns */
) ;

您可以使用ARRAY整數代替:

CREATE TABLE t
(
   /* some columns */
   dl integer[],
   /* more columns */
) ;

(您可以使用 NOT NULL 約束,dl就像在列上使用它們一樣;儘管寫法不同。也就是說,如果需要,您可以使用CHECK (dl[2000] NOT NULL). 在這些情況下不能使用FOREIGN KEY約束。

然後,您的功能將是:

CREATE OR REPLACE FUNCTION update()
   RETURNS VOID AS $$
DECLARE 
   cur SCROLL CURSOR FOR select * from my_tbl;
   r1 RECORD;
BEGIN
   OPEN cur ;
   FOR counter IN  2000..2017 LOOP
       r1 := NULL;
       LOOP
           FETCH cur INTO r1;
           EXIT WHEN NOT FOUND;

           IF dl[counter] = 1 THEN
               -- do some thing
               RAISE NOTICE 'processing year of : %', counter;
           END IF;     
       END LOOP;
   END LOOP;
   CLOSE cur;
END; 
$$
LANGUAGE plpgsql;

注意:我沒有改變你函式中的邏輯,雖然我不確定我會這樣做。至少,我會交換這兩個循環。一個大的用於游標,然後在內部,一個用於列(或數組的索引)。

引用自:https://dba.stackexchange.com/questions/163950