簡體   English   中英

如何處理PostgreSQL函數中的單引號

[英]how to deal with single quotation marks in postgresql functions

我有一個pg函數,需要用單引號引起來。

create or replace function deal_null_value(in user_id numeric) returns integer as
$body$
    declare
        part_num integer;
        sql_str character varying;
    begin
        sql_str := '
        select b.num from (
            select regexp_split_to_table(together,E',\\s*') as together,
            count(id) as num
            from inc_info t
            where
            t.registime>=to_timestamp('2011-10-01 00:00:00','yyyy-MM-dd HH:mi:ss')
            and t.registime<=to_timestamp('2011-10-31 23:59:59','yyyy-MM-dd HH:mi:ss')
            group by together_person
        ) as b 
        where cast(b.together as integer) = ' || user_id;

    EXECUTE sql_str into part_num;
    return part_num;
    end;
$body$
LANGUAGE 'plpgsql'

您會看到我有一些單引號。

regexp_split_to_table(together,E',\\s*')
to_timestamp('2011-10-01 00:00:00','yyyy-MM-dd HH:mi:ss')

我想使用$$代替',並且想使用quote_literal函數,該如何使用?

提前致謝!

@Mu已經回答了有關報價的問題,@ araqnid清除了鑄造問題。 還有許多問題需要其他答案。 嘗試這個:

CREATE OR REPLACE FUNCTION deal_null_value(IN user_id numeric, OUT part_num integer)
  AS
$body$
DECLARE
    sql_str  text;
BEGIN
sql_str := $x$
    SELECT b.num FROM (
        SELECT regexp_split_to_table(together, ',') AS together_person
              ,count(*)::integer as num
        FROM   inc_info t
        WHERE  registime >= '2011-10-01 00:00:00'::timestamp
        AND    registime  < '2011-11-01 00:00:00'::timestamp
        GROUP  BY together_person
    ) b 
    WHERE  b.together::numeric = $1
    $x$;

EXECUTE sql_str
INTO    part_num
USING   user_id;

END;
$body$
LANGUAGE 'plpgsql';

要點:

  • 這是非法的,並且會引發錯誤:

     to_timestamp('2011-10-01 00:00:00','yyyy-MM-dd HH:mi:ss') 

    它必須是:

     to_timestamp('2011-10-01 00:00:00','yyyy-MM-dd HH24:mi:ss') 

    但最好簡化為:

     '2011-10-01 00:00:00'::timestamp 

    ISO 8601時間戳格式任何語言環境中有效 無需說明格式,這是標准。

  • 更換

     registime <= '2011-10-31 23:59:59'::timestamp 

     registime < '2011-11-01 00:00:00'::timestamp 

    時間戳記可以包含小數秒。 你會想念像

     '2011-10-31 23:59:59.034'::timestamp 

    ...很難找出原因。

  • 簡化

     regexp_split_to_table(together,E',\\\\s*') as together 

     regexp_split_to_table(together, ',') AS together 

    另外,我懷疑你想稱呼它

     regexp_split_to_table(together, ',') AS together_person 

    當您進一步分組時。 您稍后將其轉換為數字(或整數)。 在這兩個轉換中, 前導/尾隨空白都會自動修剪 因此,不需要轉義序列或更復雜的正則表達式。 更快,更干凈。

  • 如果 id不為空(如我所假設), 則使用 count(*)代替count(id) )。 count(*)更快。

  • 聚合函數count()返回bigint 它轉換為integer如您返回整數。 這里沒有問題,因為它是自動投射的,但在其他情況下可能會成為問題。

  • part_num使用OUT參數可以簡化代碼。 然后,在分配給part_num ,您不需要顯式的RETURN語句。

  • 為什么將b.togetherinteger 您將其與numeric user_id進行比較? 也可以將user_id integer ,或者將其user_idnumeric

關於count(*) vs.count count(col)

1)考慮一下: count(*)僅檢查行的存在,而count(col)也必須檢查col是否為NULL NULL值不計算在內!
2)嘗試使用任何大桌子:

`EXPLAIN ANALYZE SELECT count(*) from tbl`

`EXPLAIN ANALYZE SELECT count(col) from tbl`.

如果列col被定義為NOT NULL或您知道 ,則不能有NULL值,那么count(*)產生的結果與count(col) 在這種情況下使用count(*)更快一些。

美元報價非常簡單:只需選擇一個令牌(可選),將其放在美元符號( $token$ )之間,然后像引用一樣使用它:

    sql_str := $sql$
    select b.num from (
        select regexp_split_to_table(together,E',\\s*') as together,
        count(id) as num
        from inc_info t
        where
        t.registime>=to_timestamp('2011-10-01 00:00:00','yyyy-MM-dd HH:mi:ss')
        and t.registime<=to_timestamp('2011-10-31 23:59:59','yyyy-MM-dd HH:mi:ss')
        group by together_person
    ) as b 
    where cast(b.together as integer) = $sql$ || user_id;

您可以像其他任何字符串函數一樣使用quote_literal

    where cast(b.together as integer) = cast($sql$ || quote_literal(user_id) || $sql$ as integer)$sql$;

盡管您的user_id是數字,所以您可能不需要它。 太太,我認為這不會造成傷害。

暫無
暫無

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

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