PostgreSQL. Функции. Строки…

На предыдущую страницу…

В процессе формирования…

Важно!
1. При копировании текстов функций этого раздела, следует «крупно иметь в виду», что существенная часть функций вызывает другие функции (размещенные в этом разделе, а также и в других разделах тоже).
2. Чтобы компенсировать этот момент — в конце страницы можно скачать исходные тексты всех функций в формате PG-backup (SQL-текст).


  • str_words_count — вычислить кол-во слов в заданной строке;
  • str_word_by_num — получить слово из заданной строки по заданному номеру;
  • str_sets_intersect — проверка пересечения 2-х множеств, заданных в виде строк символов;
  • str_reverse — инвертирвать заданную строку;
  • str_replace — замена в заданной строке sx символов, перечисленных в unchars (типа: множество символов), на символ char_repl;
  • str_build_left — нарастить входную строку заданными символами до заданного размера слева;
  • str_build_right — нарастить входную строку заданными символами до заданного размера справа.

CREATE OR REPLACE FUNCTION public.str_words_count(
    sx text,
    sunchar character varying DEFAULT ' '::character varying,
    yestrimbefore boolean DEFAULT true,
    sxrenovina character varying DEFAULT '|'::character varying)
  RETURNS integer AS
$BODY$
DECLARE
    i integer;
    k integer;
    m integer;
    inword boolean;
    ch char(1);
    res integer;
BEGIN
/*
Вычислить кол-во слов в строке Sx.
Разделителями слов могут быть любые символы из sUnChar
Параметры:
  sx - входная строка;
  sunchar - НеСимволы. Строка (типа - множество НеСимволов);
  yestrimbefore - если TRUE, то перед обработкой удаляются НеСимволы слева и справа в Sx
  sxrenovina - подстрока, на которую заменяются пробелы (следствие НеЯсности для меня работы функций substring, position). Такого символа в принципе не должно быть в строке.
Возвращаемое значение: кол-во слов (integer)
Примеры:
  select str_words_count(' ,,,1, ;;; 2, 3', ' ,'); -- 4 слова
  select * from str_words_count('1,2 ;3', ';, '); -- 3 слова
  select * from str_words_count('1,2 ;3', ','); -- 2 слова
  select * from str_words_count('1,2 ;3', ';3' ); -- 1 слово
  select * from str_words_count('1,2 ;3', ' ' ); -- 2 слова
  select * from str_words_count('1, 2 ;3', ' ' ); -- 3 слова
  select * from str_words_count('1, ;;;   2,,,, ;  3', ',;' ); -- 5 слов
  select * from str_words_count('1, ;;;   2,,,, ;  3', ', ;' ); -- 3 слова
*/
 res = 0;
 IF (sx is NULL) THEN sx = ''; END IF;
 IF (sunchar is NULL) THEN sunchar = ' '; END IF;
 yestrimbefore = bool_is_null(yestrimbefore);
 IF (yestrimbefore) THEN
    sx = btrim(sx,sunchar);
 END IF;
 m = char_length(sx);
 IF (m>0) THEN
   IF (char_length(sunchar)>0) THEN
        -- **************************************
        -- Это - на предмет НеЧеткости описАния и работы какой-то из функций: substring, position
        IF (sxrenovina is NULL) THEN sxrenovina = ''; END IF;
        IF char_length(sxrenovina)>0 THEN
           k = position(' ' in sunchar);
           IF k<=0 THEN
              sx = replace(sx,' ',sxrenovina);
           END IF;
        END IF;
        -- **************************************
        res = 0;
        inword = false;
        i = 0;
        WHILE i<m LOOP
          i = i + 1;
          ch = substring(sx,i,1);
          k = position(ch in sunchar);
          IF k<=0 THEN
             IF (NOT inword) THEN res = res+1; END IF;
             inword = true;
          ELSE
             inword = false;
          END IF;
        END LOOP;
    ELSE
       res = 1;
    END IF;
 END IF;
 RETURN res;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
COMMENT ON FUNCTION public.str_words_count(text, character varying, boolean, character varying) IS 'Вычислить кол-во слов в строке';

CREATE OR REPLACE FUNCTION public.str_word_by_num(
    sx text,
    num integer,
    sunchar character varying DEFAULT ' '::character varying,
    yestrimbefore boolean DEFAULT true,
    sxrenovina character varying DEFAULT '|'::character varying)
  RETURNS text AS
$BODY$
DECLARE
    i integer;
    k integer;
    m integer;
    nword integer;
    inword boolean;
    yesexit boolean;
    ch char(1);
    res text;
BEGIN
/*
Получить слово из строки по его номеру.
Алгоритм, мягко говоря, не быстрый
Разделителями слов могут быть любые символы из sUnChar
Параметры:
  sx - входная строка;
  num - номер слова в строке;
  sunchar - НеСимволы. Строка (типа - множество НеСимволов);
  yestrimbefore - если TRUE, то перед обработкой удаляются НеСимволы слева и справа в Sx;
  sxrenovina - символ, на который заменяются пробелы (следствие НеЯсности для меня работы функций substring, position). Такого символа в принципе не должно быть в строке.
Возвращаемое значение: слово по его номеру
Примеры:
  select str_word_by_num(' ,,,1, ;;; 2, 3', 3, ' ,');   -- 2
  select * from str_word_by_num('1,2a ;3', 2, ';, ');   -- 2a
  select * from str_word_by_num('1,2 ;3', 2, ',');      -- 2 ;3
  select * from str_word_by_num('1,2 ;3', 2, ';3' );    -- пустая строка
  select * from str_word_by_num('1,2 ;3', 2, ' ' );     -- ;3
  select * from str_word_by_num('1, 2 ;3', 2, ' ' );    -- 2
*/
 res = '';
 IF (sx is NULL) THEN sx = ''; END IF;
 IF (sunchar is NULL) THEN sunchar = ' '; END IF;
 yestrimbefore = bool_is_null(yestrimbefore);
 IF (yestrimbefore) THEN
    sx = btrim(sx,sunchar);
 END IF;
 m = char_length(sx);
 IF (m>0) THEN
   IF (char_length(sunchar)>0) THEN
        -- **************************************
        -- Это - на предмет НеЧеткости описАния и работы какой-то из функций: substring, position
        IF (sxrenovina is NULL) THEN sxrenovina = ''; END IF;
        IF char_length(sxrenovina)>0 THEN
           k = position(' ' in sunchar);
           IF k<=0 THEN
              sx = replace(sx,' ',sxrenovina);
           END IF;
        END IF;
        -- **************************************
        yesexit = false;
        nword = 0;
        inword = false;
        i = 0;
        WHILE i<m LOOP
          i = i + 1;
          IF (not yesexit) THEN
             ch = substring(sx,i,1);
             k = position(ch in sunchar);
             IF k<=0 THEN
                IF (NOT inword) THEN nword = nword+1; END IF;
                inword = true;
             ELSE
                inword = false;
                IF (nword>=num) THEN
                   yesexit = true; -- Выход из цикла
                END IF;
             END IF;
             IF (inword) THEN
                IF (nword=num) THEN
                   res = res || ch;
                END IF;
             END IF;
          END IF;
        END LOOP;
        res = replace(res, sxrenovina, ' ');
    ELSE
       res = sx;
    END IF;
 END IF;
 IF (res is NULL) THEN res = ''; END IF;
 RETURN res;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
COMMENT ON FUNCTION public.str_word_by_num(text, integer, character varying, boolean, character varying) IS 'Получить слово из строки по его номеру';

CREATE OR REPLACE FUNCTION public.str_sets_intersect(
    set1 text,
    set2 text,
    sep_left character DEFAULT '['::bpchar,
    sep_right character DEFAULT ']'::bpchar,
    yes_upper boolean DEFAULT true,
    sxrenovina character DEFAULT '`'::bpchar)
  RETURNS boolean AS
$BODY$
DECLARE
    i integer;
    c  integer;
    sxrenovina char;
    s character varying;
    res boolean;
BEGIN
/*
Проверка пересечения 2-х множеств, заданных в виде строк символов
Параметры:
  set1 - множество 1;
  set2 - множество 2;
  sep_left - разделитель элементов множества слева;
  sep_right - разделитель элементов множества справа;
  yes_upper - игнорировать регистр символов.
Важно! 
  1. Очевидно, что элементы множества НЕ должны содержать разделителей;
  2. Полное равенство строк (set1 и set2) считается пересечением (включая и пустые строки).
  3. Символ sxrenovina НЕ должен присутствовать среди символов в: set1, set2, sep_left, sep_right
Возвращаемое значение: TRUE, если множества пересекаются. FALSE в противном случае
Примеры:
  select * from str_sets_intersect('[1][3679][3680]', '[3680]'); -- true
  select * from str_sets_intersect('[1][3679][3680]', '[3680][100]');  -- true
  select * from str_sets_intersect('[1][3679][3680]', '[3681][100]');    -- false
  select * from str_sets_intersect('[1]', '[3680]');  -- false
  select * from str_sets_intersect('[1]', '[1][3680]');  -- true
  select * from str_sets_intersect('[ 1]', '[1][3680]');  -- false  
  select * from str_sets_intersect('[1]' || chr(10) || '[3679]' || chr(10) || '[3680]', '[15][3680]'); -- true
  select * from str_sets_intersect('[1]' || chr(10) || '[3679]' || chr(10) || chr(13)  || chr(9) || '[3680]', '[15]' || chr(10) || '[3685]' || chr(10) || '[3679]'); -- true
*/
 res = false;
 set1 = str_is_null(set1);
 set2 = str_is_null(set2);
 yes_upper = bool_is_null(yes_upper);
 IF (yes_upper = TRUE) THEN
    set1 = upper(set1);
    set2 = upper(set2);
 END IF;
 IF (set1 = set2) THEN
    res = true; 
 ELSE 
    IF (sep_left is null) THEN sep_left = '['; END IF;
    IF (sep_right is null) THEN sep_right = ']'; END IF;
    IF (sxrenovina is null) THEN sxrenovina = '`'; END IF;
    c = str_words_count(set1, sep_left || sep_right, false, sxrenovina);
    IF (c>0) THEN
       i = 0;
       WHILE i<c LOOP
         i = i + 1;
         s = str_word_by_num(set1, i, sep_left || sep_right, false, sxrenovina);
         IF (s <> '') THEN
             s = sep_left || s || sep_right;
             IF (position(s in set2)>0) THEN
                res = true;
                i = c+1; 
             END IF;
         END IF;
       END LOOP;
    END IF;
 END IF;
 RETURN Res;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
COMMENT ON FUNCTION public.str_sets_intersect(text, text, character, character, boolean, character) IS 'Проверка пересечения 2-х множеств, заданных в виде строк символов';

1CREATE OR REPLACE FUNCTION public.str_reverse(sx character varying)
  RETURNS character varying AS
$BODY$
DECLARE
    res character varying;
BEGIN
  /*
    Инвертирвать строку sx
    Пример:
      select * from str_reverse(null);
      select * from str_reverse('Привет, как дела ?');
      select * from str_reverse(str_reverse('Привет, как дела ?'));
      select * from str_reverse('   Привет, как дела ?');
      select * from str_reverse('   Привет, как дела ?   ');
      select * from str_reverse(str_reverse('   Привет, как дела ?   '));
  */
  sx = str_is_null(sx,'',false);
  res = reverse(sx);
  RETURN res;  
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
COMMENT ON FUNCTION public.str_reverse(character varying) IS 'Инвертирвать строку sx';

CREATE OR REPLACE FUNCTION public.str_replace(
    sx character varying,
    unchars character varying DEFAULT ' '::character varying,
    char_repl character DEFAULT '_'::bpchar,
    char_xz character DEFAULT '|'::bpchar)
  RETURNS character varying AS
$BODY$
DECLARE
    i integer;
    yes99 boolean;
    m integer;
    k integer;
    ch char(1);
    res character varying;
BEGIN
  /*
    Замена в строке sx символов, перечисленных в unchars (типа: множество символов), на символ char_repl
    Вх. параметры:
      sx - входная строка;
      unchars - перечень НеСимволов (аналог множества символов);
      char_repl - замещающий символ;
      char_xz - символ, "компенсирующий" пробел в unchars.
    ВАЖНО!!!  Среди символов unchars не должно быть символа char_xz и, кроме этого, нельзя, чтобы char_xz = ' '.
    Пример:
       select * from str_replace('Привет, как дела ?', ' ,?', '_');  -- Привет__как_дела__
       select * from str_replace('Привет, как дела ? | А у тебя?', '| ,?', '_');  -- Привет__как_дела___|_А_у_тебя_
       select * from str_replace('Привет, как дела ? | А у тебя?', '| ,?', '_', '\'); -- Привет__как_дела_____А_у_тебя_
       select * from str_replace(btrim('   Привет, как дела ? | А у тебя?'  ), '| ,?', '_', '\');  -- Привет__как_дела_____А_у_тебя_
  */
  res = '';
  IF (sx is NULL) THEN sx = ''; END IF;
  IF (sx <> '') THEN
     res = sx;
     IF (unchars is NULL) THEN unchars = ''; END IF;
     m = char_length(unchars);
     IF (m>0) THEN              
        IF (char_xz is NULL) THEN char_xz = '|'; END IF;    
        unchars = replace(unchars,' ',char_xz);
        IF (char_repl is NULL) THEN char_repl = '_'; END IF;    
        i = 0;
        WHILE i<m LOOP
         i = i + 1;
         ch = substring(unchars,i,1);
         IF (ch = char_xz) THEN
            res = replace(res, ' ', char_repl);
         ELSE
            res = replace(res, ch, char_repl);
         END IF;
     END LOOP;
     END IF;
  END IF;
  RETURN res;  
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
COMMENT ON FUNCTION public.str_replace(character varying, character varying, character, character) IS 'Замена в строке sx символов, перечисленных в unchars (типа: множество символов), на символ char_repl';

CREATE OR REPLACE FUNCTION public.str_build_left(
    sx text,
    newsize integer,
    ch character DEFAULT '0'::bpchar)
  RETURNS text AS
$BODY$
DECLARE
  res text;
  yes99 boolean; 
BEGIN
  /*
    Нарастить входную строку заданными символами до заданного размера слева
    sx - входня строка
    newsize - новый размер строки
    ch - символы, которыми "наращивается строка"
    Пример вызова:
       select str_build_left ('3',5,'0'); --  Результат: 00003
       select str_build_left ('3',10,'-'); -- Результат: ---------3
       select str_build_left ('Привет',10,'='); -- Результат: ====Привет
       select str_build_left ('',10,' '); 
  */
  sx = str_is_null(sx);
  res = sx;
  newsize = int_is_null(newsize);
  IF (newsize > 0) THEN
     yes99 = false; 
     IF (ch IS NULL) THEN ch =' '; END IF;
     IF (ch = ' ') THEN 
        ch = '|';
        yes99 = true; 
     END IF; 
     WHILE (CHAR_LENGTH(res) < newsize) LOOP
       res = ch || res;
     END LOOP;
     IF (yes99 = true) THEN
        res = replace(res,'|',' ');
     END IF; 
  END IF;
  res = str_is_null(res,'',false);
  RETURN res;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
COMMENT ON FUNCTION public.str_build_left(text, integer, character) IS 'Нарастить входную строку заданными символами до заданного размера слева';
CREATE OR REPLACE FUNCTION public.str_build_right(
    sx text,
    newsize integer,
    ch character DEFAULT '0'::bpchar)
  RETURNS text AS
$BODY$
DECLARE
  res text;
  yes99 boolean; 
BEGIN
  /*
    Нарастить входную строку заданными символами до заданного размера справа 
    sx - входная строка
    newsize - новый размер строки
    ch - символы, которыми "наращивается строка"
    Пример вызова:
       select str_build_right ('3',5,'0');
       Результат: 30000
  */
  sx = str_is_null(sx);
  res = sx;
  newsize = int_is_null(newsize);
  IF (newsize > 0) THEN
     IF (ch IS NULL) then ch =' '; END IF;
     IF (ch = ' ') THEN 
        ch = '|';
        yes99 = true; 
     END IF; 
     WHILE (CHAR_LENGTH(res) < newsize) LOOP
       res = res || ch;
     END LOOP;
     IF (yes99 = true) THEN
        res = replace(res,'|',' ');
     END IF; 
  END IF;
  res = str_is_null(res);
  RETURN res;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
COMMENT ON FUNCTION public.str_build_right(text, integer, character) IS 'Нарастить входную строку заданными символами до заданного размера справа';

Скачать PG-backup (SQL-текст функций)


Продолжение следует…


На предыдущую страницу…

Дата: 07.12.2021