2016-11-10 68 views
2

我與PostgreSQL的工作,我有一個功能三個變量,其中一個是date類型:月份和年份,而不是日期變量

CREATE OR REPLACE FUNCTION public.fn_reporte_venta_mes(
IN p_fech = date, 
IN p_client integer, 
IN p_comprobante character 

參數p_fech服務於進入從PHP日期格式'1111-11-11'。相反,我只想插入日期格式爲「1111-11」的月份和年份。但是我不知道如何改變p_fech變量的數據類型,因爲當我只在PHP中放置日期和月份時,我遇到了兼容性錯誤。

我的完整功能:

CREATE OR REPLACE FUNCTION public.fn_reporte_venta(
IN p_fech date, 
IN p_client integer, 
IN p_comprobante character) 
RETURNS TABLE(nro integer, fecha date, tipo character varying, cliente text, porc_igv numeric, st numeric, igv numeric, total numeric) AS 
$BODY$ 
begin 
return query 
select v.numero_venta, 
     v.fecha_venta, 
     tc.descripcion, 
     concat(apellido_paterno, ' ', apellido_materno, ' ', nombres) as client, 
     v.porcentaje_igv, 
     v.sub_total, 
     v.igv, 
     v.total 
from venta v 
    inner join cliente cl on v.codigo_cliente = cl.codigo_cliente 
    inner join tipo_comprobante tc on v.codigo_tipo_comprobante = tc.codigo_tipo_comprobante 
where v.estado = 'E' and 
     (
    case when p_fech = '11-11-1111' then 
     1 = 1 
    else 
     v.fecha_venta = p_fech 
    end 
    ) 
     and 
     (
    case when p_client = 0 then 
     1 = 1 
    else 
     cl.codigo_cliente = p_client 
    end 
    ) and 
     (
    case when p_comprobante = '00' then 
     1 = 1 
    else 
     tc.codigo_tipo_comprobante = p_comprobante 
    end 
    ) 
     order by 2; 
    end 
    $BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100 
    ROWS 1000; 
+0

這將有助於聲明您的Postgres版本和函數中使用的語言。(SQL,plpgsql還是別的?) –

+0

語言plpgsql –

+0

請用重要信息[編輯]你的問題。 'SELECT version()'告訴你Postgres的版本號。 –

回答

1

使用字符類型參數(textvarcharcharacter!)和函數to_date()將輸入轉換爲日期。

你的功能,簡化的固定:

CREATE OR REPLACE FUNCTION public.fn_reporte_venta(p_fech text 
               , p_client integer 
               , p_comprobante text) 
    RETURNS TABLE(nro integer, fecha date, tipo varchar, cliente text 
       , porc_igv numeric, st numeric, igv numeric, total numeric) AS 
$func$ 
DECLARE 
    v_fech date := to_date(p_fech, 'YYYY-MM-DD'); -- transform to date 
BEGIN 
    RETURN QUERY 
    SELECT v.numero_venta, 
      v.fecha_venta, 
      t.descripcion, 
      concat_ws(' ', c.apellido_paterno, c.apellido_materno, c.nombres) AS client, 
      v.porcentaje_igv, 
      v.sub_total, 
      v.igv, 
      v.total 
    FROM venta v 
    JOIN cliente c USING (codigo_cliente) 
    JOIN tipo_comprobante t USING (codigo_tipo_comprobante) 
    WHERE v.estado = 'E' 
    AND (v_fech = '1111-11-11' OR v.fecha_venta = v_fech) -- var goes here 
    AND (p_client = 0   OR c.codigo_cliente = p_client) 
    AND (p_comprobante = '00' OR t.codigo_tipo_comprobante = p_comprobante) 
    ORDER BY 2; 
END 
$func$ LANGUAGE plpgsql STABLE ROWS 1000; 

始終使用日期文字的ISO-8601格式(YYYY-MM-DD),這是明確的任何區域設置。不要使用本地語法方言,如果會話應該以不同的語言環境運行,它們會中斷。

我在plpgsql函數中使用date變量,它可以在聲明中立即分配。

這種表達是非常通用的:

to_date(p_fech, 'YYYY-MM-DD'); 

to_date()允許省略元素到右側,以1對丟失數據。所有這些都是有效的,並導致「2016年1月1日」

SELECT to_date('2016-01-01', 'YYYY-MM-DD') 
    , to_date('2016-1-1' , 'YYYY-MM-DD') 
    , to_date('2016-01' , 'YYYY-MM-DD') 
    , to_date('2016-'  , 'YYYY-MM-DD') 
    , to_date('2016'  , 'YYYY-MM-DD'); 

所以,你可以在全日通或截斷到一個月甚至一年。你總是這樣指定一個單一的

或者總是覆蓋了整整一個月:

... 
    v_fech date := to_date(p_fech, 'YYYY-MM'); -- no "-DD" truncates to month 
... 
    AND (v_fech = '1111-11-01' -- also truncated to 1st of month! 
     OR v.fecha_venta >= v_fech 
     AND v.fecha_venta < v_fech + interval '1 month') 
... 

爲什麼不是數據類型character?因爲這是一個過時的,主要是無用的類型,通常是一個誤區:

另外請注意我如何更換您的詳細CASE語句簡單或表達式。

和其他一些小改進...

+0

表達式很好:'v_fech date:= to_date(p_fech,'YYYY-MM-DD')'允許foll日期指定一天。考慮我的答案中的解釋。不過,您需要'v.fecha_venta'中的* exact *日期(本月的第一個!)。我添加了一個變體,以便始終包含上述月份的所有日期。 –

+0

如果我使用完整的日期進行選擇,它的工作原理是完美的,但是如果我使用月份和年份進行選擇,它不顯示任何內容select * from fn_reporte_venta('2016-05',2,'01') –

+0

考慮更新。 –

相關問題