0

我正在嘗試編寫一個函數以從Redshift獲取模式中的對象列表。我創建了一個從RDS PostgreSQL到Redshift的dblink。查詢在單獨調用時工作得很好,但在使用參數寫入函數時不起作用。我想傳遞多個參數(模式名稱),因此我使用VARIADIC參數。該函數看起來像下面 -Postgresql函數 - 使用文本類型的VARIADIC參數

CREATE FUNCTION f_fetch_tables(VARIADIC list text[]) 
RETURNS VOID 
AS $$ 
    DECLARE 
     begin_time TIMESTAMP; 
     expire_time TIMESTAMP; 
    BEGIN 
     /* To fetch the list of all objects from Redshift */ 
     EXECUTE 'drop table if exists tmp_rs_obj_list; 
     create table tmp_rs_obj_list as 
     SELECT * FROM dblink(''rs_link'',$REDSHIFT$ select * from (select schemaname, 
     tablename from pg_tables UNION select schemaname, viewname from pg_views) where schemaname 
     not in (array_to_string($1,'','')) $REDSHIFT$) AS t1 (schema_nm varchar(30), obj_nm varchar(100))' using list; 
    END; 
    $$ 
    LANGUAGE plpgsql 
; 

功能編譯罰款,併成功創建,但我不能想出一個辦法來稱呼它 -

使用這些電話,到目前爲止,沒有任何的運氣 -

  1. 選擇f_fetch_tables( '{公衆,pg_catalog}')

    錯誤:沒有參數$ 1 其中:發生在DBLINK CONNEC錯誤名爲「未命名」的命令:不能 執行查詢。

  2. SELECT * FROM f_fetch_tables(可變參數 '{公衆,pg_catalog}')

    錯誤:沒有參數$ 1 其中:發生在一個名爲 「無名」 dblink的連接錯誤:無法執行查詢。

任何建議將是非常有用的。

謝謝 卡姆利什

回答

2

您的功能有幾個問題。我會建議使用:

  • ,方便傳遞參數的功能format()
  • 美元報價內execute($fmt$)查詢,
  • <> all(array)而不是not in運營商(不必轉換一個數組串)。

與建議的修改功能:

create or replace function f_fetch_tables(variadic list text[]) 
returns void 
as $$ 
    declare 
     begin_time timestamp; 
     expire_time timestamp; 
    begin 
     /* to fetch the list of all objects from redshift */ 
     execute format($fmt$ 
      drop table if exists tmp_rs_obj_list; 
      create table tmp_rs_obj_list as 
       select * 
       from dblink(
        'rs_link', $redshift$ 
         select * 
         from (
          select schemaname, tablename 
          from pg_tables 
          union 
          select schemaname, viewname 
          from pg_views) s 
         where schemaname <> all(%L) 
        $redshift$) 
        as t1 (schema_nm varchar(30), obj_nm varchar(100)) 
      $fmt$, list); 
    end; 
$$ 
language plpgsql; 

還要注意傳遞參數的函數具有可變參數參數的正確方法是:

select f_fetch_tables('pg_catalog', 'information_schema'); 
select * from tmp_rs_obj_list; 
+0

謝謝@klin。這對我工作..! –

0

這個問題是不相關的可變參數的參數 - 同樣的行爲,如果你使用普通的參數太多,你會得到。它與動態SQL相關 - 由PLpgSQL執行的EXECUTE命令具有自己的參數環境。所以你不能使用函數環境中的變量或參數引用。

此代碼不起作用:

CREATE OR REPLACE FUNCTION fx(a int) 
RETURNS void AS $$ 
BEGIN 
    EXECUTE 'SELECT * FROM foo WHERE foo.a = $1'; 
END; 
$$ LANGUAGE plpgsql; 

在這種情況下,有沒有通過任何參數來執行的查詢。 $1無效。如果要將某些參數傳遞給動態SQL,則應該使用USING子句。

此代碼應工作:

CREATE OR REPLACE FUNCTION fx(a int) 
RETURNS void AS $$ 
BEGIN 
    EXECUTE 'SELECT * FROM foo WHERE foo.a = $1' USING a; 
END; 
$$ LANGUAGE plpgsql; 

但它不解決你的問題太多,因爲你使用USING條款。但是,您僅在級別EXECUTE命令中使用USING子句 - 不在dblink級別 - 不支持該級別。 dblink API與USING子句的EXECUTE命令沒有任何相似之處。因此,在將它發送到dblink API之前,必須先使用解包(preevaluated)參數構建本機SQL字符串。

您使用動態SQL的兩級

  • EXECUTE
    • dblink

dblink不支持查詢參數化 - 所以你不應該使用參數的地方持有人.. $ x。

在這種情況下,最好將輸入數組序列化爲頂級plpgsql級別的字符串,並像動態SQL參數那樣傳遞此字符串。

DECLARE serialized_params text; 
BEGIN 
    serialized_params = (SELECT array_agg(quote_literal(quote_ident(v))) FROM unnest(ARRAY['A','b']) g(v)); 
    EXECUTE ' ....' USING serialized_params; 
END