Funciones para documentar bases de datos PostgreSQL. Primera parte

Durante el trabajo con PostgreSQL, se han acumulado más de cien funciones para trabajar con directorios del sistema: pg_class, pg_attribute, pg_constraints, etc.


¿Qué hacer con ellos? Se usan relativamente raramente. ¿Incluir en algún proyecto? El cliente de Krasnoyarsk no pagará por tales "tonterías". Y, sin embargo, ¿qué pasa si son útiles para otra persona que no sea el autor? Y decidió ponerlos, como leer libros, en un armario público para quienes lo deseen.

Alguien quiere usarlos en su trabajo. Y alguien interesado en algo más que su experiencia con los catálogos de sistemas.

Pero para no convertir la publicación en una enumeración aburrida, no se sabe por qué se crearon las funciones, decidí detenerme en aquellas que pueden unirse por un objetivo común. Por lo tanto, se seleccionan las funciones que se utilizan para mostrar una lista extendida de características de una tabla de base de datos arbitraria.

La función admtf_Table_ComplexFeatures devuelve la lista extendida de características de la tabla de la base de datos, que en este artículo se denominará la función head Por lo tanto, el artículo se limitará a considerar las funciones que se llaman en el proceso de ejecución de la función head.

La primera mitad del artículo proporciona comentarios sobre la implementación de funciones. El segundo es el código fuente de las funciones. Para aquellos lectores que solo están interesados ​​en los textos de origen, sugerimos proceder inmediatamente al Apéndice .

Ver también
Funciones para documentar bases de datos PostgreSQL. Parte dos ;
Funciones para documentar bases de datos PostgreSQL. Tercera parte
Funciones para documentar bases de datos PostgreSQL. El final (parte cuatro) .




¿De qué características avanzadas estamos hablando?


Para tener una idea de lo que se entiende por las características extendidas de la tabla de base de datos, comenzamos considerando la siguiente lista de características. La lista contiene las características de la tabla de la base de datos de Street devuelta por admtf_Table_ComplexFeatures ( 'public' , 'street' ) .

La siguiente tabla contiene una lista abreviada de las características de la tabla Street. Un conjunto completo de características de esta tabla se proporciona en Materiales complementarios del Apéndice 2.

Tabla 1. Características avanzadas de la tabla Street.

La versión de texto de la tabla en la figura.
CategoríaNoTituloComentariotipoTipo base? no NULL
tbl0 0calleLista de calles en asentamientos
att1wcrccodeCódigo de paíswcrccodeletra pequeñat
att2localityidID de comunidadlocalityidenterot
att3streetidID calle del pueblostreetidletra pequeñat
att4 4streettypeacrmSiglas de la callestreettypeacrmpersonaje (8)f
att5 5nombre de calleNombre de la callestreettypeacrmvarchar (150)t
pk0 0xpkstreetClave principal de la mesa de calle
pkatt1wcrccodeCódigo de paíswcrccodeletra pequeñat
fk011fk_street_localityClave externa de tabla
fk022fk_street_streettypeClave externa de tabla
idx011xie1streetIndice por tipo y nombre de calle del asentamiento
idx022xie2streetCódigo postal
idx033xie3streetÍndice de nombres de calles de todos los asentamientos
idx044 4xpkstreetEl índice único (clave principal) de la tabla de calle


Enumerando la hostilidad hacia este conjunto de letras y números, puede ver que estamos hablando de las características habituales de una tabla de base de datos:


  • Nombres de tablas;
  • La lista de atributos de tabla y sus tipos;
  • La clave primaria y la lista de claves foráneas de la tabla, junto con los atributos de la tabla que las componen;
  • Una lista de índices de tabla.

La unicidad de cada entrada de la lista de características está garantizada por los valores de los campos de "categoría" y el número de serie ("No.") de la característica.



Tabla 2. Categorías de características de la tabla.

La versión de texto de la tabla en la figura.
AcrónimoCita
tbCaracterísticas de la mesa
attCaracterísticas del atributo de tabla
seqCaracterísticas de secuencia
pkCaracterísticas principales principales
pkAttCaracterísticas principales del atributo clave
fk99Características clave extranjeras
fk99attCaracterísticas de atributos de clave externa
fk99rtblCaracterísticas de la tabla referenciada por la clave externa
fk99rattCaracterísticas del atributo de la tabla a la que hace referencia la clave externa
Idx99Características del índice
Idx99attCaracterísticas de los atributos del índice
Inhtbl99Características de la tabla generada.


El valor de la categoría es necesario para distinguir diferentes grupos de características entre sí. Un número de serie, para distinguir las características dentro del grupo.


Se pueden declarar varias claves foráneas (CLAVE EXTRANJERA) e índices en la tabla de la base de datos. Por lo tanto, el valor de categoría para estas características y sus descendientes contiene un número de serie. Por ejemplo, una entrada con la clave "Categoría" = idx02att y "No." = 1 indica el primer atributo del segundo índice.


En la lista de categorías anterior, la ubicación del número de serie se indica como '99'.


Observación 1



El código fuente del operador en la figura
SELECT * FROM admtf_Table_ComplexFeatures('pg_catalog','pg_class'); 



El artículo da ejemplos de las características de las tablas, que se describen brevemente en un esquema auxiliar creado específicamente para demostrar las capacidades de las funciones. Pero el lector, después de haber creado esta o aquella función en su base de datos, puede usar los nombres de sus esquemas y tablas como parámetros. Además, por ejemplo, el directorio pg_class se puede usar como parámetro, aunque en este caso se emite un número limitado de características.

El final del comentario.



Estructura de la función de la cabeza



Fig. 1. Las funciones que causan la función de la cabeza.

Tabla 3. Asignación de funciones.

La versión de texto de la tabla en la figura.
NoTituloCita
1admtf_Table_FeaturesLa función devuelve una lista de características de la tabla de la base de datos.
2admtf_Table_AttributesLa función devuelve una lista de atributos de tabla de base de datos y sus características.
3admtf_Table_ConstraintesLa función devuelve una lista de restricciones de tabla de base de datos y sus características.
4 4admtf_Table_IndexesLa función devuelve una lista de índices de tabla de base de datos y sus características.
5 5admtf_Table_InheritanceChildrensLa función devuelve una lista de tablas generadas por (IHERITS) de la tabla de la base de datos de origen.
6 6admtf_Table_SequencesLa función devuelve una lista de secuencias (SECUENCIA) de la que depende la tabla.
7 7admtf_PrimaryKey_ComplexFeaturesLa función devuelve una lista completa (extendida) de características de clave primaria (CLAVE PRIMARIA) de la tabla de la base de datos.
8admtf_ForeignKey_ComplexFeaturesLa función devuelve una lista completa (extendida) de características de clave externa (CLAVE EXTRANJERA) de la tabla de la base de datos.
9 9admtf_Index_ComplexFeaturesLa función devuelve una lista completa (extendida) de las características del índice de la tabla de la base de datos.
10admtf_Table_ComplexFeaturesLa función devuelve una lista completa (extendida) de las características de la tabla de la base de datos.


Observación 2.


Las descripciones de las funciones se organizarán en el orden que se muestra arriba. La razón es que el artículo tendrá que dividirse en varias partes. Y las funciones dispuestas en este orden se pueden usar independientemente del hecho de que algunas de ellas se describirán solo en las siguientes partes de la publicación.


El final del comentario.



Lista de funciones Admtf_Table_Features de las características de la tabla de base de datos




La función admtf_Table_Features devuelve una lista de características de la tabla de la base de datos. El código fuente se puede ver y descargar aquí.


Como parámetros, la función toma el nombre de la tabla fuente (a_TableName ) y el nombre del esquema dentro del cual se crea la tabla ( a_SchemaName ).


La función extrae los datos principales de la entrada de catálogo pg_class , que contiene, además de las entradas de la tabla, también registros sobre secuencias, vistas, vistas materializadas y tipos compuestos. Por lo tanto, para seleccionar tablas, se usa la condición relkind = 'r' .



 SELECT tbl.relname,dsc.description,tbl.relnatts::INTEGER,tbl.relchecks::INTEGER, tbl.relhaspkey,tbl.relhasindex,tbl.relhassubclass,tbl.reltuples::INTEGER FROM pg_class tbl INNER JOIN pg_namespace nspc ON tbl.relnamespace = nspc.oid LEFT OUTER JOIN pg_description dsc ON tbl.oid=dsc.objoid AND dsc.objsubid=0 WHERE LOWER( nspc.nspname)=LOWER(a_SchemaName) AND tbl.relkind='r' AND LOWER(tbl.relname) =LOWER(a_TableName); 

Además, la función accede a los datos del directorio pg_namespace y pg_description . El primero contiene los nombres de los esquemas de la base de datos y el segundo contiene comentarios sobre todos los objetos de la base de datos.


Es importante prestar atención a la condición objsubid = 0 . Define el comentario en la tabla, ya que el valor del campo objoid es el mismo para la tabla y sus atributos. El comentario sobre el atributo de la tabla está contenido en la entrada en la que objsubid coincide con el número de este atributo.



Tabla 4. El resultado de ejecutar la función admtf_Table_Features ('public', 'Street').

TituloComentarioNumero de atributosNúmero de restricciones CHECK? hay una clave primaria? son índices declarados? hay descendientesEl número de entradas en la tabla.
calleLista de calles en asentamientos220 0ttf20150

Observación 3


Presta atención al número de atributos de la tabla de calle. Difiere significativamente del número de atributos especificados en el esquema auxiliar.


Tabla 5. Atributos adicionales de la tabla Street.


attnameatttypidAttnumNota
cmin29-4Atributo del sistema
xmin28-3Atributo del sistema
ctid27-1Atributo del sistema
wcrccode7953691Atributo válido
localityid7953522Atributo válido
streetid7953643Atributo válido
streettypeacrm19191684 4Atributo válido
nombre de calle10435 5Atributo válido
........ pg.dropped.6 ........0 06 6Atributo remoto
........ pg.dropped.7 ........0 07 7Atributo remoto

El hecho es que PostgreSQL, además de los atributos principales, también tiene en cuenta varios atributos del sistema e incluso atributos eliminados.


Comentario final



Función admtf_Table_Attributes lista de atributos de tabla de base de datos y sus características


La función admtf_Table_Attributes devuelve una lista de atributos de la tabla de la base de datos. El código fuente se puede ver y descargar aquí.


Como parámetros, la función toma el nombre de la tabla fuente ( a_TableName ) y el nombre del esquema dentro del cual se crea la tabla ( a_SchemaName ).


La función recupera los datos principales de las entradas de directorio pg_attribute y pg_type . El primero contiene registros con datos sobre los atributos de tablas, vistas, vistas materializadas, tipos compuestos e incluso funciones. El segundo trata sobre las características de los tipos de atributos.


Quizás se requiera alguna aclaración por la forma en que el usuario y los tipos base se definen en la función.


Un atributo de tabla se declara con un tipo personalizado si el campo typbasetype es mayor que 0 en la entrada de directorio pg_type correspondiente, de lo contrario, el atributo es del tipo base. Por lo tanto, el directorio pg_type está involucrado dos veces en la cláusula FROM. En la primera entrada del directorio, se determina la presencia de un tipo de usuario; si no está definido ( typbasetype = 0 ), se genera un valor de tipo base a partir de esta entrada. De lo contrario, el tipo base se determina a partir del registro para el cual btyp.OID = typ.typbasetype.


Directamente, la línea con el tipo base se forma utilizando la función del catálogo del sistema FORMAT_TYPE (type_oid, typemod) . El primer parámetro de los cuales es el tipo base de registros OID. El segundo parámetro es el valor modificador para los tipos que contienen un tamaño. Por ejemplo, VARCHAR (100) o NUMERIC (4,2), DECIMAL (4,2). El valor del parámetro typemod se toma de typ.typtypmod si el atributo es de un tipo de usuario, de lo contrario, de attr.atttypmod , es decir directamente desde un registro de atributos.



El código fuente del operador en la figura
 SELECT attr.attnum, attr.attname::VARCHAR(100), CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::VARCHAR(100) ELSE '' END, FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid), COALESCE(NULLIF(typ.typtypmod,-1),attr.atttypmod))::VARCHAR(256), attr.attnotnull, dsc.description FROM pg_attribute attr INNER JOIN pg_class tbl ON tbl.oid = attr.attrelid INNER JOIN pg_namespace nspc ON tbl.relnamespace = nspc.oid INNER JOIN pg_type typ ON attr.atttypid=typ.oid LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid AND dsc.objsubid=attr.attnum WHERE LOWER( nspc.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname) =LOWER(a_TableName) AND tbl.relkind='r' AND attr.attnum>0 AND attr.atttypID>0 ORDER BY tbl.relname,attr.attnum; 


Además, la función accede a los datos del directorio pg_class , pg_namespace y pg_description . Los directorios primero y segundo se usan para buscar atributos por los nombres del esquema y la tabla de la base de datos.

El tercer directorio se utiliza para recuperar el comentario para el atributo de tabla.


El comentario sobre el atributo de la tabla está en la entrada en la que dsc.objoid contiene el OID de la tabla de origen, y dsc.objsubid es el número de serie del atributo en la tabla, es decir. attr.attnum .


Para evitar que la función devuelva el sistema y los atributos remotos, la cláusula WHERE establece la condición attr.attnum> 0 AND attr.atttypID> 0 .



Tabla 6. El resultado de ejecutar la función admtf_Table_Attributes ('public', 'Street').

NoTituloTipo personalizadoTipo base? no NULLComentario
1wcrccodewcrccodeletra pequeñatCódigo de país
2localityidlocalityidenterotID de comunidad
3streetidstreetidletra pequeñatID calle del pueblo
4 4streettypeacrmstreettypeacrmpersonaje (8)fSiglas de la calle
5 5nombre de callevarchar (150)tNombre de la calle del asentamiento.

Versión de función utilizando alias regclass para tipo oid


Los identificadores de objetos PostgreSQL (OID) son del mismo tipo que OID, que actualmente se implementa como un entero de cuatro bytes sin signo. Pero debido a la presencia de alias de este tipo, un número entero se puede representar como el nombre de un objeto. Y viceversa: convierta el nombre del objeto en un entero de tipo OID.


Como ejemplo, eche un vistazo a la siguiente instrucción SELECT . Inusualmente recupera los nombres de la tabla de atributos y los nombres de sus tipos; en lugar de acceder a los campos de directorio correspondientes con los nombres de estas características, se utilizan:

  • attrelid :: regclass (attrelid :: regclass: NAME) ,
  • atttypid :: regtype (atttypid :: regtype: NAME)
  • typbasetype :: regtype (typbasetype :: regtype: NAME) .


 SELECT attr.attname,attr.attrelid::regclass, attr.atttypid::regtype, typ.typbasetype::regtype,attr.attrelid::regclass::name, attr.atttypid::regtype::name,typ.typbasetype::regtype::name FROM pg_attribute attr INNER JOIN pg_type typ ON attr.atttypid=typ.oid WHERE attr.attrelid=('public'||'.'||'Street')::regclass AND attr.attnum>0 AND attr.atttypID>0 ORDER BY attr.attnum; 

El siguiente es el resultado de ejecutar esta consulta.



En la lista de valores de salida del operador SELECT antes de la conversión utilizando alias del tipo OID, todos los valores, excepto el nombre del atributo, son numéricos, pero como resultado, se muestran los nombres de tabla y los tipos de atributo. Los tipos de valores de salida pueden considerarse en la segunda línea del encabezado de la tabla.


Además, en la cláusula WHERE de la declaración, se encuentra la condición attr.attrelid = ('public' || '.' || 'Street') :: regclass , en el lado izquierdo del cual hay un valor numérico, y a la derecha hay una cadena que se convierte en un valor numérico con usando el alias regclass .



El código fuente del operador en la figura
 SELECT attr.attnum, attr.attname::VARCHAR(100), CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::VARCHAR(100) ELSE '' END, FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid), COALESCE(NULLIF(typ.typtypmod,-1),attr.atttypmod))::VARCHAR(256), attr.attnotnull, dsc.description FROM pg_attribute attr INNER JOIN pg_type typ ON attr.atttypid=typ.oid LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid AND dsc.objsubid=attr.attnum WHERE attr.attrelid=( a_SchemaName ||'.'|| a_TableName)::regclass AND attr.attnum>0 AND attr.atttypID>0 ORDER BY attr.attnum; 


Usando el alias regclass de la declaración principal, puede eliminar la conexión a dos directorios. Pero tal mejora casi no tuvo efecto en el rendimiento de la función: en ambas versiones, la función se ejecuta en 11 ms. Quizás debido al hecho de que la tabla de prueba tiene pocos atributos.
Observación 4

Un defecto grave en la condición en la forma attr.attrelid = (a_SchemaName || '.' || a_TableName) :: regclass se manifiesta cuando hay un esquema y / o tabla con un nombre inusual en la base de datos. Por ejemplo, "Mi esquema" y / o "Mi tabla" . Dichos valores deben transmitirse entre comillas dobles o utilizar la función QUOTE_IDENT; de lo contrario, la función fallará con un error del sistema.



El código fuente del operador en la figura
 /*       «   »*/ SELECT attr.attname,attr.attrelid::regclass, attr.atttypid::regtype,typ.typbasetype::regtype, attr.attrelid::regclass::name, attr.atttypid::regtype::name,typ.typbasetype::regtype::name FROM pg_attribute attr INNER JOIN pg_type typ ON attr.atttypid=typ.oid WHERE attr.attrelid=(' '||'.'||' ')::regclass AND attr.attnum>0 AND attr.atttypID>0 ORDER BY attr.attnum; /*       */ SELECT attr.attname,attr.attrelid::regclass, attr.atttypid::regtype,typ.typbasetype::regtype, attr.attrelid::regclass::name, attr.atttypid::regtype::name,typ.typbasetype::regtype::name FROM pg_attribute attr INNER JOIN pg_type typ ON attr.atttypid=typ.oid WHERE attr.attrelid=('" "'||'.'||'" "')::regclass AND attr.attnum>0 AND attr.atttypID>0 ORDER BY attr.attnum; 


Por lo tanto, prefiero usar condiciones en la forma INFERIOR (nspc.nspname) = INFERIOR (a_SchemaName) Y INFERIOR (tbl.relname) = INFERIOR (a_TableName) , lo que no conduce a errores del sistema.

Comentario final

APÉNDICE 1. Scripts


Creación de la función admtf_Table_Features


Los comentarios sobre el código fuente de la función se pueden encontrar aquí.
código fuente de la función
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Features (a_SchemaName NAME,a_TableName NAME); /********************************************************************************************************/ /*     ,   */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Features (a_SchemaName NAME default 'public', /*     */ a_TableName NAME default NULL /*   */ ) RETURNS TABLE (rs_TableName NAME,rs_TableDescription TEXT,rs_NumberOfAttribute INTEGER,rs_NumberOfChecks INTEGER,rs_hasPKey BOOLEAN,rs_hasIndex BOOLEAN,rs_hasSubClass BOOLEAN,rs_NumberOfRow INTEGER) AS $BODY$ DECLARE c_TableKind CONSTANT CHAR:='r'; v_TableOID OID; /*   */ v_TableName NAME; /*   */ v_TableDescription TEXT; /*   */ v_TableNumberOfRowCalc INTEGER; /*     */ --****************************************************************************************************** BEGIN SELECT INTO rs_TableName,rs_TableDescription,rs_NumberOfAttribute, rs_NumberOfChecks,rs_hasPKey,rs_hasIndex,rs_hasSubClass, rs_NumberOfRow tbl.relname,dsc.description,tbl.relnatts::INTEGER,tbl.relchecks::INTEGER, tbl.relhaspkey,tbl.relhasindex,tbl.relhassubclass,tbl.reltuples::INTEGER FROM pg_class tbl INNER JOIN pg_namespace nspc ON tbl.relnamespace = nspc.oid LEFT OUTER JOIN pg_Description dsc ON tbl.oid=dsc.objoid AND dsc.objsubid=0 WHERE nspc.nspname=LOWER(a_SchemaName) AND tbl.relkind=c_TableKind AND tbl.relname =LOWER(a_TableName); EXECUTE 'SELECT count(*) FROM ' ||LOWER(a_SchemaName) ||'.'||quote_ident(LOWER(a_TableName)) INTO v_TableNumberOfRowCalc; RETURN QUERY SELECT rs_TableName,rs_TableDescription,rs_NumberOfAttribute, rs_NumberOfChecks,rs_hasPKey,rs_hasIndex, rs_hasSubClass,v_TableNumberOfRowCalc AS rs_NumberOfRow; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Features(a_SchemaName NAME,a_TableName NAME) IS '   ,  '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Features (a_SchemaName VARCHAR(256),a_TableName VARCHAR(256)); /********************************************************************************************************/ /*     ,   */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Features (a_SchemaName VARCHAR(256) default 'public', /*     */ a_TableName VARCHAR(256) default NULL /*   */ ) RETURNS TABLE (rs_TableName VARCHAR(256),rs_TableDescription TEXT,rs_NumberOfAttribute INTEGER,rs_NumberOfChecks INTEGER,rs_hasPKey BOOLEAN,rs_hasIndex BOOLEAN,rs_hasSubClass BOOLEAN,rs_NumberOfRow INTEGER) AS $BODY$ DECLARE c_TableKind CONSTANT CHAR:='r'; v_TableOID OID; /*   */ v_TableName VARCHAR(256); /*   */ v_TableDescription TEXT; /*   */ v_TableNumberOfRowCalc INTEGER; /*     */ --****************************************************************************************************** BEGIN RETURN QUERY SELECT tf.rs_TableName::VARCHAR(256), tf.rs_TableDescription::TEXT, tf.rs_NumberOfAttribute::INTEGER, tf.rs_NumberOfChecks::INTEGER, tf.rs_hasPKey::BOOLEAN, tf.rs_hasIndex::BOOLEAN, tf.rs_hasSubClass::BOOLEAN, tf.rs_NumberOfRow::INTEGER FROM admtf_Table_Features(a_SchemaName::NAME,a_TableName::NAME) tf; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Features(a_SchemaName VARCHAR(256),a_TableName VARCHAR(256)) IS '   ,  '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECt * FROM admtf_Table_Features('public'::VARCHAR(256),'Street'::VARCHAR(256)); SELECt * FROM admtf_Table_Features('public':: NAME,'Street'::NAME); 



Creación de la función admtf_Table_Attributes


Los comentarios sobre el código fuente de la función se pueden encontrar aquí.
código fuente de la función
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Attributes (a_SchemaName NAME,a_TableName NAME); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Attributes (a_SchemaName NAME default 'public', /*     */ a_TableName NAME default NULL /*   */ ) RETURNS TABLE (r_AttributeNumber SMALLINT,r_AttributeName NAME,r_UserTypeName NAME,r_TypeName NAME,r_isNotNULL BOOLEAN, r_Description Text) AS $BODY$ DECLARE c_TableKind CONSTANT CHAR:='r'; v_Scale INTEGER; /*   */ --****************************************************************************************************** BEGIN RETURN QUERY SELECT attr.attnum AS r_AttributeNumber, attr.attname::NAME AS r_AttributeName, CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::NAME ELSE ''::NAME END AS r_UserTypeName, FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid), COALESCE(NULLIF(typ.typtypmod,-1),attr.atttypmod))::NAME AS r_TypeName, attr.attnotnull AS r_isNotNULL, dsc.description AS r_Description FROM pg_attribute attr INNER JOIN pg_class tbl ON tbl.oid = attr.attrelid INNER JOIN pg_namespace nsp ON tbl.relnamespace=nsp.oid LEFT OUTER JOIN pg_type typ ON attr.atttypid=typ.oid LEFT OUTER JOIN pg_type btyp ON typ.typbasetype=btyp.oid LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid AND dsc.objsubid=attr.attnum WHERE LOWER(nsp.nspname)=LOWER(a_SchemaName) AND LOWER(tbl.relname)=LOWER(a_TableName) AND tbl.relkind=c_TableKind AND attr.attnum>0 AND attr.atttypID>0 ORDER BY tbl.relname,attr.attnum; RETURN; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Attributes(a_SchemaName NAME,a_TableName NAME) IS '   '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Attributes (a_SchemaName VARCHAR(256),a_TableName VARCHAR(256)); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Attributes (a_SchemaName VARCHAR(256) default 'public', /*     */ a_TableName VARCHAR(256) default NULL /*   */ ) RETURNS TABLE (r_AttributeNumber SMALLINT,r_AttributeName VARCHAR(256),r_UserTypeName VARCHAR(256),r_TypeName VARCHAR(256),r_isNotNULL BOOLEAN, r_Description Text) AS $BODY$ DECLARE c_TableKind CONSTANT CHAR:='r'; v_Scale INTEGER; /*   */ --****************************************************************************************************** BEGIN RETURN QUERY SELECT ta.r_AttributeNumber::SMALLINT, ta.r_AttributeName::VARCHAR(256), ta.r_UserTypeName::VARCHAR(256), ta.r_TypeName::VARCHAR(256), ta.r_isNotNULL::BOOLEAN, ta.r_Description::TEXT FROM admtf_Table_Attributes(a_SchemaName::NAME,a_TableName::NAME) ta; RETURN; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Attributes(a_SchemaName VARCHAR(256),a_TableName VARCHAR(256)) IS '   '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Table_Attributes('public'::VARCHAR(256),'Street'::VARCHAR(256)); SELECT * FROM admtf_Table_Attributes('public'::NAME,'Street'::NAME); 


Creación de la función admtf_Table_Attributes con el alias Regclass


Los comentarios sobre el código fuente de la función se pueden encontrar aquí.
código fuente de la función
 BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Attributes (a_SchemaName NAME,a_TableName NAME); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Attributes (a_SchemaName NAME default 'public', /*     */ a_TableName NAME default NULL /*   */ ) RETURNS TABLE (r_AttributeNumber SMALLINT,r_AttributeName NAME,r_UserTypeName NAME,r_TypeName NAME,r_isNotNULL BOOLEAN, r_Description Text) AS $BODY$ DECLARE c_TableKind CONSTANT CHAR:='r'; v_Scale INTEGER; /*   */ --****************************************************************************************************** BEGIN RETURN QUERY SELECT attr.attnum AS r_AttributeNumber, attr.attname::NAME AS r_AttributeName, CASE WHEN COALESCE(typ.typbasetype,0)>0 THEN typ.typname::NAME ELSE ''::NAME END AS r_UserTypeName, FORMAT_TYPE(COALESCE(NULLIF(typ.typbasetype,0),typ.oid), COALESCE(NULLIF(typ.typtypmod,-1),attr.atttypmod))::NAME AS r_TypeName, attr.attnotnull AS r_isNotNULL, dsc.description AS r_Description FROM pg_attribute attr INNER JOIN pg_type typ ON attr.atttypid=typ.oid LEFT OUTER JOIN pg_type btyp ON typ.typbasetype=btyp.oid LEFT OUTER JOIN pg_description dsc ON dsc.objoid=attr.attrelid AND dsc.objsubid=attr.attnum WHERE attr.attrelid=(LOWER(a_SchemaName)||'.'|| LOWER(a_TableName))::regclass AND attr.attnum>0 AND attr.atttypID>0 ORDER BY attr.attnum; RETURN; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Attributes(a_SchemaName NAME,a_TableName NAME) IS '   '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; BEGIN TRANSACTION; DROP FUNCTION IF EXISTS admtf_Table_Attributes (a_SchemaName VARCHAR(256),a_TableName VARCHAR(256)); /********************************************************************************************************/ /*      */ /********************************************************************************************************/ CREATE OR REPLACE FUNCTION admtf_Table_Attributes (a_SchemaName VARCHAR(256) default 'public', /*     */ a_TableName VARCHAR(256) default NULL /*   */ ) RETURNS TABLE (r_AttributeNumber SMALLINT,r_AttributeName VARCHAR(256),r_UserTypeName VARCHAR(256),r_TypeName VARCHAR(256),r_isNotNULL BOOLEAN, r_Description Text) AS $BODY$ DECLARE c_TableKind CONSTANT CHAR:='r'; v_Scale INTEGER; /*   */ --****************************************************************************************************** BEGIN RETURN QUERY SELECT ta.r_AttributeNumber::SMALLINT, ta.r_AttributeName::VARCHAR(256), ta.r_UserTypeName::VARCHAR(256), ta.r_TypeName::VARCHAR(256), ta.r_isNotNULL::BOOLEAN, ta.r_Description::TEXT FROM admtf_Table_Attributes(a_SchemaName::NAME,a_TableName::NAME) ta; RETURN; END $BODY$ LANGUAGE plpgsql; COMMENT ON FUNCTION admtf_Table_Attributes(a_SchemaName VARCHAR(256),a_TableName VARCHAR(256)) IS '   '; --ROLLBACK TRANSACTION; COMMIT TRANSACTION; SELECT * FROM admtf_Table_Attributes('public'::VARCHAR(256),'Street'::VARCHAR(256)); SELECT * FROM admtf_Table_Attributes('public'::NAME,'Street'::NAME); 



APÉNDICE 2. Materiales adicionales


Esquema de base de datos auxiliar





  • PAÍS - Clasificador de países del mundo - OKSM (Clasificación de países del mundo en toda Rusia);
  • HOUSEADDR - Lista de números de casas en las calles de los asentamientos;
  • LCLTYTYPE - Directorio de tipos de asentamientos;
  • LOCALIDAD - Lista de asentamientos;
  • STREET — ;
  • STREETTYPE — ;
  • TERRITORY — (, , , ..);
  • TERRITORYTYPE — .



Street ()


.
1. Street ().

CategoríaNoTituloComentariotipoTipo base? no NULL
tbl0 0calleLista de calles en asentamientos
att1wcrccodeCódigo de paíswcrccodeletra pequeñat
att2localityidID de comunidadlocalityidenterot
att3streetidID calle del pueblostreetidletra pequeñat
att4 4streettypeacrmSiglas de la callestreettypeacrmpersonaje (8)f
att5 5nombre de calleNombre de la callestreettypeacrmvarchar (150)t
pk0 0xpkstreetClave principal de la mesa de calle
pkatt1wcrccodeCódigo de paíswcrccodeletra pequeñat
pkatt2localityidID de comunidadlocalityidenterot
pkatt3streetidID calle del pueblostreetidletra pequeñat
fk011fk_street_localityClave externa de tabla
fk01att1wcrccodeCódigo de paíswcrccodeletra pequeñat
fk01att2localityidID de comunidadlocalityidenterot
fk01rtbl0 0locality
fk01ratt1wcrccodewcrccodesmallintt
fk01ratt2localityidlocalityidintegert
fk022fk_street_streettype
fk02att1streettypeacrmstreettypeacrmcharacter(8)f
fk02rtbl0 0streettype
fk02ratt1streettypeacrmstreettypeacrmcharacter(8)t
idx011xie1street
idx01att1wcrccodewcrccodesmallintt
idx01att2localityidlocalityidintegert
idx01att3streettypeacrmstreettypeacrmcharacter(8)f
idx01att4 4streetnamevarchar(150)t
idx022xie2street
idx02att1wcrccodewcrccodesmallint
idx02att2localityidlocalityidintegert
idx02att3streetnamevarchar(150)t
idx033xie3street
idx03att1streetnamevarchar(150)t
idx044 4xpkstreet( ) street
idx04att1wcrccodewcrccodesmallintt
idx04att2localityidlocalityidintegert
idx04att3streetidstreetidsmallintt


Ver también


Funciones para documentar bases de datos PostgreSQL. ;
Funciones para documentar bases de datos PostgreSQL. Tercera parte
Funciones para documentar bases de datos PostgreSQL. El final (parte cuatro) .

Source: https://habr.com/ru/post/es415575/


All Articles