Адреса ФИАС в среде PostgreSQL. Часть 3

от автора

Адреса ФИАС в среде PostgreSQL. Часть 3
Это третья часть статьи, в которой описана функция поиска в списке адресообразующих
элементов ФИАС, загруженных в базу данных под управлением PostgreSQL. С первой и
второй частями статьи можно ознакоматься здесь: habrahabr.ru/post/316314,
habrahabr.ru/post/316380


Полный текст статьи состоит состоит из 4 частей.
В первой половине этой части статьи изложены комментарии к реализации функции. Во
второй- исходный текст функции.
Тем из читателей, кого интересуют только исходные тексты, предлагаем сразу перейти к
Приложению.

Поиск адресообразующего элемента

Функция fstf_AddressObjects_SearchByName предназначена для поиска адрсообразующих элементов ФИАС по их названиям. При этом поиск может осуществялться не только по названию и типу текущего элемента, но и названиям и типам одного или двух его ближайших предков.
Рассмотрим несколько примеров. И для начала найдем все адресообразующие элементы в названии которых встречается слово «Грибной».

Таблица 8. Результат выполнения функции fstf_AddressObjects_SearchByName(‘Грибной’)

AOGUID AOLevel Полный адрес ShortName FormalName CurrStatus ActStatus
15faf08c-78b6-4b92-8a56-2ff70f2c4cab 6 Ачинский р-н, п Грибной п Грибной 0 1
f1772172-4dd1-449d-b2d2-ab96883d8871 7 Кежемский р-н, г Кодинск, пер Грибной пер Грибной 0 1
146cbcb5-4ad9-4578-916f-80ebd5c2b846 7 Емельяновский р-н, п Элита, пер Грибной пер Грибной 0 1
a8ee8caf-fd5f-489c-92d9-f560e3f93c8b 7 Сухобузимский р-н, д Шестаково, пер Грибной пер Грибной 0 1
84f4baa8-1db2-471d-967d-20d489bca68e 7 Курагинский р-н, с Тюхтят, пер Грибной пер Грибной 0 1
1f2b7975-ce05-4627-bd13-d8d6228accd7 7 г Сорск, пер Грибной пер Грибной 0 1

В полученном результате нет ничего неожиданного, если не считать наглядного доказательства пользы от функции построения полного наименования.
Теперь изменим запрос. Найдем все адресообразующие элементы, в названии ближайшего предка которых встречается слово «Грибной».

Таблица 9. Результат выполнения функции fstf_AddressObjects_SearchByName
(NULL,NULL,’Грибной’)

AOGUID AOLevel Полный адрес ShortName FormalName CurrStatus ActStatus Parent ShortName Parent FormalName
45064ade-a0a7-4258-88c8-baa57094aa2d 7 Ачинский р-н, п Грибной, ул Железнодорожная ул Железнодорожная 0 1 п Грибной
ba4ec53c-50b7-4325-866a-81f97a38214c 7 Ачинский р-н, п Грибной, ул Западная ул Западная 0 1 п Грибной
d6e9e0cc-e944-4deb-a09c-c545af691836 7 Ачинский р-н, п Грибной, ул Северная ул Северная 0 1 п Грибной
5ae71e68-5477-446b-b878-0a9c9bf3bdcd 7 Ачинский р-н, п Грибной, ул Южная ул Южная 0 1 п Грибной

Результат этого запроса несколько более неожиданный, т.к. в названиях найденных адресообразующих элементах нет слова «Грибной», но оно есть в названии их предка.
И, наконец, рассмотрим поиск по наименованию прародителя, в котором должно
присутствовать слово «Ачинский», а в наименовании его внука должен присутствовать
часть слова «Оз_рн». Здесь использован специальный символ — символ подчеркивания «_». Этот символ указывает, что на его месте может находиться любой одиночный символ. Здесь он применен, для того чтобы найти не только элементы с названиями «Озерный» или «Озерная», но и «Озёрный» или «Озёрная».

Таблица 9. Результат выполнения функции fstf_AddressObjects_SearchByName(NULL,NULL,’Грибной’)

AOGUID AOLevel Полный адрес ShortName FormalName CurrStatus ActStatus Parent ShortName Parent FormalName Grand Parent ShortName Grand Parent FormalName
715eef9d-48f6-4322-bcaa-9d239e89b7e4 7 Ачинский р-н, д Барабановка, пер Озерный пер Озерный 0 1 д Барабановка р-н Ачинский
05c7b2ad-e405-4c8b-9503-6761971e858e 7 Ачинский р-н, д Ильинка, ул Озерная ул Озерная 0 1 д Ильинка р-н Ачинский
bdfcd515-1851-4caf-83ba-12ee79f9f6a7 7 Казачинский р-н, с Дудовка, ул Озерная ул Озерная 0 1 с Дудовка р-н Казачинский

В результате запроса найдены улицы Озерная и переулок озерный в трех населенных пунктах Ачинского и Казачинского районов Красноярского края.
Текст функции приведен в разделе Приложения «Создание функции fstf_AddressObjects_SearchByName».

Как это работает

Если значения присвоены только первым двум аргументам – названию (a_FormalName) и
типу (a_ShortName) адресообразующего элемента, то поиск осуществляется во всех записях таблицы fias_AddressObjects. Предварительно значения переданных параметров преобразуются в верхний регистр, пробелы заменяются символом «%». Этим же символом окружается значение справа и слева. Преобразованные таким образом значения используются в поисковом запросе как часть операции LIKE. Пример такого запроса приведен на Рис. 4.

Рис. 4. Простой поиск адресообразующего элемента.

Условие выбора значения CurrStatus подробно обсуждалось в первой части статьи в разделе «Родословная адресообразующего элемента» «Как это работает».

Для поиска по названию и типу родительского адресообразующего элемента необходимо присвоить значение хотя бы одному из двух аргументов: третьему (a_ParentFormalName), или четвертому (a_ParentShortName). В этом случае поиск осуществляется во всех записях таблицы, полученной соединением (INNER JOIN) всех записей fias_AddressObjects с записями родительского адресообразующего элемента по признаку pfa.AOGUID=cfa.ParentGUID.
Пример такого запроса приведен на Рис. 5.

Рис. 5. Поиск по названию и типу родительского адресообразующего элемента.

Предварительная обработка значений входных параметров осуществляется по тем же правилам, как и в случае простого поиска.
Для поиска по названию и типу прародительского адресообразующего элемента необходимо присвоить значение хотя бы одному из двух аргументов: пятому (a_GrandParentFormalName) или шестому (a_GrandParentShortName). В этом случае поиск осуществляется во всех записях таблицы, полученной двойным соединением (INNER JOIN) всех записей fias_AddressObjects с записями родительского и прародительских адресообразующих элементов. Пример такого запроса приведен на Рис. 6.

Рис. 6. Поиск по названию и типу прародительского адресообразующего элемента.

Предварительная обработка значений входных параметров осуществляется по тем же правилам, как и в случае простого поиска.

ПРИЛОЖЕНИЕ

Создание функции fstf_AddressObjects_SearchByName

BEGIN TRANSACTION; DROP FUNCTION IF EXISTS fstf_AddressObjects_SearchByName(   a_FormalName VARCHAR(150), a_ShortName VARCHAR(20),   a_ParentFormalName VARCHAR(150),a_ParentShortName VARCHAR(20),   a_GrandParentFormalName VARCHAR(150),a_GrandParentShortName VARCHAR(20)); /************************************************************************/ /* Возвращает результат поиска в списке адресообразующих элементов ФИАС */ /* по их названию и типу	 		                        */ /***********************************************************************/	 CREATE OR REPLACE FUNCTION fstf_AddressObjects_SearchByName(   a_FormalName VARCHAR(150),	 /* Оптимизированное для поиска наименование */                                       /* адресообразующего элемента*/   a_ShortName VARCHAR(20) default NULL,	/* Сокращенное наименование типа */                                       /*адресообразующего элемента */  a_ParentFormalName 	VARCHAR(150) default NULL, /* Оптимизированное для поиска */                                      /* наименование адресообразующего элемента*/  a_ParentShortName VARCHAR(20) default NULL,	/* Сокращенное наименование типа */                                      /*адресообразующего элемента */  a_GrandParentFormalName VARCHAR(150) default NULL, /*Оптимизированное для поиска */                                      /* наименование адресообразующего элемента*/  a_GrandParentShortName	VARCHAR(20) default NULL	/* Сокращенное наименование типа */                                      /* адресообразующего элемента */ ) RETURNS  TABLE (rtf_AOGUID VARCHAR(36),                 rtf_AOLevel INTEGER,                 rtf_AddressObjectsFullName VARCHAR(1000),                 rtf_ShortName VARCHAR(20),                 rtf_FormalName VARCHAR(150),                 rtf_CurrStatus INTEGER,                 rtf_ParentShortName VARCHAR(20),                 rtf_ParentFormalName VARCHAR(150),                 rtf_GrandParentShortName VARCHAR(20),                  rtf_GrandParentFormalName VARCHAR(150)) AS		 $BODY$ DECLARE 	c_WildChar   CONSTANT VARCHAR(2)='%'; 	c_BlankChar  CONSTANT VARCHAR(2)=' '; 	v_FormalNameTemplate VARCHAR(150); /* Шаблон для поиска наименования */                                      /* адресообразующего элемента*/ 	v_ShortNameTemplate		VARCHAR(20);	/* Шаблон для поиска типа */                                      /* адресообразующего элемента */ 	v_ParentFormalNameTemplate VARCHAR(150); /* Шаблон для поиска наименования */                                      /* родительского адресообразующего элемента*/ 	v_ParentShortNameTemplate VARCHAR(20); /* Шаблон для поиска типа родительского */                                      /* адресообразующего элемента */ 	v_GrandParentFormalNameTemplate	VARCHAR(150);	/* Шаблон для поиска */                                      /* наименования родительского адресообразующего элемента*/ 	v_GrandParentShortNameTemplate	VARCHAR(20);	/* Шаблон для поиска типа */                                      /* родительского адресообразующего элемента */ --************************************************************ --************************************************************  BEGIN 	v_ShortNameTemplate:=UPPER(COALESCE(c_WildChar||                                  REPLACE(TRIM(a_ShortName),c_BlankChar,c_WildChar)||                                 c_WildChar,c_WildChar)); 	v_FormalNameTemplate:=UPPER(c_WildChar||                                  REPLACE(TRIM(a_FormalName),c_BlankChar,c_WildChar)||                                 c_WildChar); 	IF a_ParentFormalName IS NULL AND a_ParentShortName IS NULL  			AND a_GrandParentFormalName IS NULL                          AND a_GrandParentShortName IS NULL THEN 		RETURN QUERY                 SELECT cfa.AOGUID,cfa.AOLevel,                        fsfn_AddressObjects_TreeActualName(cfa.AOGUID),                        cfa.ShortName,cfa.FORMALNAME,                         cfa.currstatus,NULL::VARCHAR,NULL::VARCHAR, 			NULL::VARCHAR,NULL::VARCHAR                   FROM fias_AddressObjects cfa                    WHERE cfa.currstatus=                         CASE WHEN 0 < ALL(SELECT iao.currstatus FROM fias_AddressObjects iao                                                              WHERE cfa.aoguid = iao.aoguid)                                   THEN (SELECT MAX(iao.currstatus) FROM fias_AddressObjects iao                                                               WHERE cfa.aoguid = iao.aoguid) 			           ELSE 0                              END                        AND UPPER(cfa.FORMALNAME) LIKE v_FormalNameTemplate                        AND  UPPER(cfa.ShortName) LIKE v_ShortNameTemplate                   ORDER BY cfa.AOLevel,cfa.ShortName,cfa.FORMALNAME; 	ELSIF a_ParentFormalName IS NOT NULL 			AND a_GrandParentFormalName IS NULL  			AND a_GrandParentShortName IS NULL THEN 		v_ParentShortNameTemplate:=UPPER(COALESCE(c_WildChar||                                  REPLACE(TRIM(a_ParentShortName),c_BlankChar,c_WildChar)||                                  c_WildChar,c_WildChar)); 		v_ParentFormalNameTemplate:=UPPER(c_WildChar||                                  REPLACE(TRIM(a_ParentFormalName),c_BlankChar,c_WildChar)||                                  c_WildChar); 		v_FormalNameTemplate:=COALESCE(v_FormalNameTemplate,c_WildChar);                 RETURN QUERY                  SELECT cfa.AOGUID,cfa.AOLevel,fsfn_AddressObjects_TreeActualName(cfa.AOGUID),                              cfa.ShortName,cfa.FORMALNAME,cfa.currstatus,                              pfa.ShortName,pfa.FORMALNAME,                              NULL::VARCHAR,NULL::VARCHAR                  FROM fias_AddressObjects pfa                          INNER JOIN fias_AddressObjects cfa ON pfa.AOGUID=cfa.ParentGUID                  WHERE cfa.currstatus=CASE WHEN 0 <                          ALL (SELECT iao.currstatus FROM fias_AddressObjects iao                                                              WHERE cfa.aoguid = iao.aoguid)                                   THEN (SELECT MAX(iao.currstatus) FROM fias_AddressObjects iao                                                              WHERE cfa.aoguid = iao.aoguid)                                   ELSE 0 END                      AND pfa.currstatus=CASE WHEN 0 <                           ALL(SELECT iao.currstatus FROM fias_AddressObjects iao                                                            WHERE pfa.aoguid = iao.aoguid)                                   THEN (SELECT MAX(iao.currstatus) FROM fias_AddressObjects iao                                                            WHERE pfa.aoguid = iao.aoguid)                                   ELSE 0 END                      AND UPPER(pfa.FORMALNAME) LIKE v_ParentFormalNameTemplate                       AND  UPPER(pfa.ShortName) LIKE v_ParentShortNameTemplate                      AND UPPER(cfa.FORMALNAME) LIKE v_FormalNameTemplate                       AND  UPPER(cfa.ShortName) LIKE v_ShortNameTemplate                 ORDER BY pfa.ShortName,pfa.FORMALNAME,                     cfa.AOLevel,cfa.ShortName,cfa.FORMALNAME;	 	ELSE 		v_GrandParentShortNameTemplate:=UPPER(COALESCE(c_WildChar||                                  REPLACE(TRIM(a_GrandParentShortName),c_BlankChar,c_WildChar)||                                  c_WildChar,c_WildChar)); 		v_GrandParentFormalNameTemplate:=UPPER(c_WildChar||                                  REPLACE(TRIM(a_GrandParentFormalName),c_BlankChar,c_WildChar)||                                  c_WildChar); 		v_ParentShortNameTemplate:=COALESCE(UPPER(COALESCE(c_WildChar||                                  REPLACE(TRIM(a_ParentShortName),c_BlankChar,c_WildChar)||                                  c_WildChar,c_WildChar)),c_WildChar); 		v_ParentFormalNameTemplate:=COALESCE(UPPER(c_WildChar||                                 REPLACE(TRIM(a_ParentFormalName),c_BlankChar,c_WildChar)||                                 c_WildChar),c_WildChar); 		v_FormalNameTemplate:=COALESCE(v_FormalNameTemplate,c_WildChar);                 RETURN QUERY                  SELECT cfa.AOGUID,cfa.AOLevel,fsfn_AddressObjects_TreeActualName(cfa.AOGUID),                             cfa.ShortName,cfa.FORMALNAME,                             cfa.currstatus,pfa.ShortName,pfa.FORMALNAME,                             gpfa.ShortName,gpfa.FORMALNAME                   FROM fias_AddressObjects gpfa                             INNER JOIN fias_AddressObjects pfa ON gpfa.AOGUID=pfa.ParentGUID                           INNER JOIN fias_AddressObjects cfa ON pfa.AOGUID=cfa.ParentGUID                   WHERE cfa.currstatus=CASE WHEN 0 <                          ALL(SELECT iao.currstatus FROM fias_AddressObjects iao                                                             WHERE 	cfa.aoguid = iao.aoguid)                                   THEN (SELECT MAX(iao.currstatus) FROM fias_AddressObjects iao                                                              WHERE cfa.aoguid = iao.aoguid)                                  ELSE 0 END                         AND pfa.currstatus=CASE WHEN 0 <                            ALL(SELECT iao.currstatus FROM fias_AddressObjects iao                                                             WHERE pfa.aoguid = iao.aoguid)                                   THEN (SELECT MAX(iao.currstatus) FROM fias_AddressObjects iao                                                             WHERE pfa.aoguid = iao.aoguid)                                   ELSE 0 END                         AND gpfa.currstatus=CASE WHEN 0 <                            ALL(SELECT iao.currstatus FROM fias_AddressObjects iao                                                            WHERE gpfa.aoguid = iao.aoguid)                                   THEN (SELECT MAX(iao.currstatus) FROM fias_AddressObjects iao                                                             WHERE gpfa.aoguid = iao.aoguid)                                   ELSE 0 END                         AND UPPER(gpfa.FORMALNAME) LIKE v_GrandParentFormalNameTemplate                         AND  UPPER(gpfa.ShortName) LIKE v_GrandParentShortNameTemplate                         AND UPPER(pfa.FORMALNAME) LIKE v_ParentFormalNameTemplate                          AND  UPPER(pfa.ShortName) LIKE v_ParentShortNameTemplate                         AND UPPER(cfa.FORMALNAME) LIKE v_FormalNameTemplate                          AND  UPPER(cfa.ShortName) LIKE v_ShortNameTemplate                   ORDER BY gpfa.ShortName,gpfa.FORMALNAME,                         pfa.ShortName,pfa.FORMALNAME,                         cfa.AOLevel,cfa.ShortName,cfa.FORMALNAME;  	END IF; END;  $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION fstf_AddressObjects_SearchByName(    a_FormalName VARCHAR(150),a_ShortName VARCHAR(20),    a_ParentFormalName VARCHAR(150),a_ParentShortName VARCHAR(20),    a_GrandParentFormalName VARCHAR(150),a_GrandParentShortName VARCHAR(20))    IS 'Возвращает результат поиска в списке адресообразующих элементов ФИАС по их названию и типу'; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; --SELECT * FROM fstf_AddressObjects_SearchByName('БОРОДИН','г'); --SELECT * FROM fstf_AddressObjects_SearchByName('БОРОДИН'); --SELECT * FROM fstf_AddressObjects_SearchByName('два',NULL,'МИГНА'); --SELECT * FROM fstf_AddressObjects_SearchByName(NULL,NULL,'МИГНА'); --SELECT * FROM fstf_AddressObjects_SearchByName('Зел_ная','УЛ',NULL); SELECT * FROM fstf_AddressObjects_SearchByName('Зел_ная','УЛ','Куваршино',NULL,'Емельян'); 

ссылка на оригинал статьи https://habrahabr.ru/post/316622/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *