2016-11-10 6 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

LANGUAGE plpgsql –

+0

Пожалуйста, отредактируйте ваш вопрос с необходимой информацией. 'SELECT version()' сообщает номер версии Postgres. –

ответ

1

Используйте параметр типа символов (text или varchar, неcharacter!) И функция 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), который является однозначным с какой-либо настройки локали. Не поддавайтесь местным синтаксическим диалектам, они ломаются, если сеанс должен работать с другой локалью.

Я использую переменную date в функции plpgsql, которую можно сразу назначить декларацией.

Это выражение очень универсальна:

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

to_date() позволяет опускать элементы вправо на 1 недостающих данных. Все они являются действительными и привести к «2016-01-01»:

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'. Я добавил вариант, чтобы всегда включать все дни месяца. –

+0

Если я сделаю выбор с полной датой, он отлично работает, но если я сделаю выбор с месяцем и годом, он ничего не отобразит, выберите * из fn_reporte_venta ('2016-05', 2, '01') –

+0

Рассмотрите обновления. –