проверка формата без использования функции в postgresql - PullRequest
0 голосов
/ 04 апреля 2020

Как проверить значения даты в ожидаемом формате или нет Мне нужно проверить значения даты в формате гггг-мм-дд или нет, если нет, то отобразить статус 0 dob и doj имеют тип данных varchar

Мне нужно реализовать эта логика c без использования пользовательских функций в postgresql

Таблица: Emp

Table: Emp

eid | ename | dob        | doj
1   | abc   | 1900-01-19 | 2019-02-20
2   | dx    | 1900-29-02 | 2019-04-22
3   | xy    | 1989-10-26 | 2018-27-02
4   |ji     | 2000-23-01 | 2019-29-04
5   |jj     |1980/04/09  |1999/08/20

на основе приведенных выше данных. Я хочу, чтобы формат даты проверки был гггг-мм-дд, если нет Флаг будет отображаться, как показано ниже:

eid | dobdateformatstatus | dojdateformatstatus
1   | 1                   | 1
2   | 0                   | 1
3   | 1                   | 0
4   | 0                   | 0
5   |0                    |0

Я получил солутон для существующего вопроса, и запрос:

create function try_cast_to_date(p_in text)
returns date 
as $$
begin
    begin
        return $1::date;
    exception 
        when others then return null;
    end;
end;
$$
language plpgsql;
then use it in query:

select 
    eid, 
    ename, 
    (try_cast_to_date(dob) is not null) dobdateformatstatus, 
    (try_cast_to_date(doj) is not null) dojdateformatstatus  
from mytable

Подскажите, пожалуйста, как написать запрос для выполнения этой задачи без использования пользователя. функции в PostgreSQL.

1 Ответ

0 голосов
/ 05 апреля 2020

Ну, определенная пользователем функция - самое ясное, если не самое правильное решение. Однако без пользовательской функции вы можете сделать это с помощью регулярного выражения. Следующее предлагает наиболее общее регулярное выражение для дат проверки, однако оно неверно помечает 29-февраль как недействительный в високосные годы (проверка того, что с помощью регулярного выражения начинает усложняться), но в противном случае проверяет даты. Это регулярное выражение:

'^(0[0-9]{2}[1-9]|[1-9][0-9]{3})-((0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01])|02-(0[1-9]|1[0-9]|2[0-8])|(0[469]|11)-(0[1-9]|[12][0-9]|30))$')

Разбивается следующим образом:

  • ^ ==> Начиная с начала строки.

  • (0 [0-9] {2} [1-9] | [1-9] [0-9] {3}) ==> год в диапазоне 0001 - 9999 (Postgres может на самом деле поддерживать годы далеко кроме этого, но этого должно быть достаточно).

  • - ==> буквальный символ
  • (0 [13578] | 10 | 12) ==> В течение нескольких месяцев январь, март, май , Июль, август, октябрь, декабрь
    • - ==> литерал
    • (0 [1-9] | [12] [0-9] | 3 [01]) ==> день находится в диапазоне от 01 до 31
  • 02 для февраля
  • - ==> литерал
  • (0 [1-9] | 1 [0 -9] | 2 [0-8]) ==> день в диапазоне от 01 до 28
  • (0 [469] | 11) ==> Для апреля, июня, сентября, ноября
    • - ==> литерал
    • (0 [1-9] | [12] [0-9] | 30) ==> день находится в диапазоне от 01 до 30
  • $ ==> конец строки

Следующий тест каждый день для 2020 года и несколько правильных и недействительных дат, добавленных в:

with date_validator(pattrn) as
     ( select '^(0[0-9]{2}[1-9]|[1-9][0-9]{3})-((0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01])|02-(0[1-9]|1[0-9]|2[0-8])|(0[469]|11)-(0[1-9]|[12][0-9]|30))$')
   , extras (dt) as 
       (select * from ( values  ('2020/02/15'), ('abcd'),('00-01-01'),('1215-06-15'),('1776-07-04'),('bad_date')) as t(dt))  
   , test_data as 
     (select ('2020-01-01'::timestamp + lev * interval '1 day')::date::text dt
          from generate_series(0,365) lev   
        union all 
        select * from extras
       ) 
select dt, dt ~ pattrn "Is Valid Date"
  from test_data 
  cross join date_validator; 

И, наконец, с ваши тестовые данные и возвращая 1 для действительной даты s и 0 для недопустимых:

with  emp(eid,ename,dob,doj) as 
      ( values (1, 'abc', '1900-01-19', '2019-02-20' )
             , (2, 'dx',  '1900-29-02', '2019-04-22' )
             , (3, 'xy',  '1989-10-26', '2018-27-02' )
             , (4, 'ji',  '2000-23-01', '2019-29-04' )
             , (5, 'jj',  '1980/04/09', '1999/08/20' )
      )
   , date_validator(pattrn) as
     ( select '^(0[0-9]{2}[1-9]|[1-9][0-9]{3})-((0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01])|02-(0[1-9]|1[0-9]|2[0-8])|(0[469]|11)-(0[1-9]|[12][0-9]|30))$')
select eid
     , case when dob ~ pattrn::text then 1 else 0 end "dob date format status"
     , case when doj ~ pattrn::text then 1 else 0 end "doj date format status"
  from emp cross join date_validator ; 

Конечно, если бы мне пришлось это реализовать, я бы, конечно, скрыл это пользовательскую функцию. Я, конечно, не доверял бы попытаться напечатать это каждый раз. Но, как другие отметили, сохраните ваши даты как дату (или отметку времени), и у вас не возникнет этой проблемы.

...