Является ли эта функция postgres экономически эффективной или все еще должна быть очищена - PullRequest
2 голосов
/ 30 декабря 2010

В postgres db есть две таблицы.english_all и english_glob

Первая таблица содержит такие слова, как международные, конфиденциальные, загрузка, кулер и т. д.

Я написал функцию, чтобы получить слова из english_all, а затем выполнить цикл для каждого слова вполучить список слов, которые не вставлены в таблицу anglish_glob.Список слов похож на

I
In
Int
Inte
Inter
..
b
bo
boo
boot
..
c
co
coo
cool
etc..

, по какой-то причине zwnj (без объединения нулевой ширины) добавляется во время вставки в таблицу english_all.Но в функции я удаляю этот символ с помощью regexp_replace.

Функция Postgres for_loop_test принимает два параметра min и max, основываясь на том, что я выбираю слова из таблицы english_all.

код функции похож на

DECLARE
inMinLength ALIAS FOR $1;
inMaxLength ALIAS FOR $2;
mviews RECORD;
outenglishListRow english_word_list;--custom data type eng_id,english_text
BEGIN
FOR mviews IN SELECT id,english_all_text FROM english_all where wlength between inMinLength and inMaxLength 
ORDER BY english_all_text limit 30 LOOP

FOR i IN 1..char_length(regexp_replace(mviews.english_all_text,'(‌)$','')) LOOP
    FOR outenglishListRow IN
        SELECT distinct on (regexp_replace((substring(mviews.english_all_text from 1 for i)),'(‌)$','')) mviews.id,
        regexp_replace((substring(mviews.english_all_text from 1 for i)),'(‌)$','') where 
        regexp_replace((substring(mviews.english_all_text from 1 for i)),'(‌)$','') not 
        in(select english_glob.english_text from english_glob where i=english_glob.wlength)
        order by regexp_replace((substring(mviews.english_all_text from 1 for i)),'(‌)$','')
    LOOP
    RETURN NEXT outenglishListRow;
    END LOOP;


END LOOP;
END LOOP;
END;

Как только я получу список слов, я вставлю его в другую таблицу english_glob.Мой вопрос: есть ли что-нибудь, что я могу добавить или удалить из функции, чтобы сделать ее более эффективной.

edit Давайте предположим, что в таблице english_all есть такие слова, как

  • нижний колонтитул, урегулирование, вопрос, переполнение, база данных, королевство

Если inMinLength = 5 и inmaxLength = 7, то во внешнем цикле

  • нижний колонтитул, урегулирование, королевство

будет выбран.Для вышеупомянутых 3 слов будет применяться внутренний два цикла, чтобы получить такие слова, как

  • f, fo, foo, foot , foote, footer , s, se, установить , установить, установить .... и т. Д.

В последнем процессе слова, выделенные жирным шрифтом, будут введены в english_glob с другим параметром, например 1, чтобы обозначить, что это правильноеслово и хранится в другом поле таблицы english_glob.Оставшееся слово будет сохранено с другим параметром 0, потому что при следующем вызове слова, сохраненные в базе данных, больше не должны выбираться.

edit2: Это полный код

CREATE TABLE english_all
(
id serial NOT NULL,
english_all_text  text NOT NULL,
wlength integer NOT NULL,
CONSTRAINT english_all PRIMARY KEY (id),
CONSTRAINT english_all_kan_text_uq_id UNIQUE (english_all_text)
)

CREATE TABLE english_glob
(
id serial NOT NULL,
english_text  text NOT NULL,
is_prop integer default 1,
CONSTRAINT english_glob PRIMARY KEY (id),
CONSTRAINT english_glob_kan_text_uq_id UNIQUE (english_text)
)

insert into english_all(english_all_text,wlength) values ('ant',char_length('ant')),('forget',char_length('forget')),('forgive',char_length('forgive'));

для функциивызов с параметрами 3 и 6 следует выбрать следующие строки:

a
an
ant
f
fo
for
forg
forge
forget

затем вставка в другую таблицу на основе указанной выше строки

insert into english_glob(english_text,is_prop) 
values 
('a',1),('an',1),
('ant',1),('f',0),
('fo',0),('for',1),
('forg',0),('forge',1),
('forget',1),

при вызове функции в следующий раз с параметрами 3 и 7 следующие строкидолжен быть выбран. (потому что f, fo, for, forg все введены в таблицу english_glob)

forgi
forgiv
forgive

Снимок экрана

1 Ответ

3 голосов
/ 30 декабря 2010

Вы можете сделать это в одном выражении:

SELECT  english_all_text, part,
        part IN
        (
        SELECT  english_text
        FROM    english_glob
        ) AS found
FROM    (
        SELECT  *, SUBSTRING(english_all_text, 1, generate_series(1, LENGTH(english_all_text))) AS part
        FROM    english_all
        WHERE   LENGTH(english_all_text) BETWEEN 5 AND 7
        ) q

Некоторые примеры данных для проверки:

WITH    english_all(english_all_text) AS
        (
        SELECT  unnest('{footer,settle,question,overflow,database,kingdom}'::text[])
        ),
        english_glob(english_text) AS
        (
        SELECT  unnest('{foot,footer,set}'::text[])
        )
SELECT  english_all_text, part,
        part IN
        (
        SELECT  english_text
        FROM    english_glob
        ) AS found
FROM    (
        SELECT  *, SUBSTRING(english_all_text, 1, generate_series(1, LENGTH(english_all_text))) AS part
        FROM    english_all
        WHERE   LENGTH(english_all_text) BETWEEN 5 AND 7
        ) q

Обновление:

Если вам просто нужно вернуть слова, части которых отсутствуют в списке, используйте это:

SELECT  part
FROM    (
        SELECT  *, SUBSTRING(english_all_text, 1, generate_series(1, LENGTH(english_all_text))) AS part
        FROM    english_all
        WHERE   LENGTH(english_all_text) BETWEEN 5 AND 7
        ) q
WHERE   part NOT IN
        (
        SELECT  english_text
        FROM    english_glob
        )
...