Parte 2
\?
Practico
Un rol puede ser considerado como un usuario de base de datos o un grupo de usuarios de base de datos, dependiendo de cómo se configura la función. Los roles son creados por los usuarios (normalmente los administradores) y se utilizan para agrupar privilegios (un derecho para ejecutar un tipo particular de sentencia SQL o un derecho de acceso al objeto de otro usuario) u otros roles.
PostgreSQL gestiona los permisos de acceso a bases de datos utilizando el concepto de funciones. Se puede crear un rol utilizando el comando SQL: CREATE ROLE.
CREATE ROLE añade un nuevo rol a un clúster de bases de datos PostgreSQL. Debe tener privilegios CREATEROLE o ser un SUPERUSER de base de datos para utilizar este comando.
Por defecto nuestro usuario postgres tiene todos esos privilegios. Veamos.
CREATE ROLE nombre [ [ WITH ] option [ ... ] ]
nombre: El nombre del nuevo rol
option:
option:
1. Cree un rol (sin contraseña) que pueda iniciar sesión:
CREATE ROLE yhoan LOGIN;
Este ejemplo solo nos permitiría trabajar si en el archivo pg_hba.conf tenemos la siguiente configuración:
2. Cree un rol con password:
CREATE USER lucho WITH PASSWORD '123';
3. Cree un rol con una contraseña válida hasta el final de 2017. Después de un segundo en 2018, la contraseña ya no es válida.
CREATE ROLE jose WITH LOGIN PASSWORD '123' VALID UNTIL '2018-01-01';
4. Cree un rol con una contraseña válida hasta las 9:19 de la noche del 17 de Agosto del 2017 .
CREATE ROLE luisa WITH LOGIN PASSWORD '123' VALID UNTIL '2017-08-17 21:19:00';
5. Crear un rol que puede crear bases de datos y administrar roles:
CREATE ROLE admin WITH CREATEDB CREATEROLE LOGIN PASSWORD '123';
5. Crear un rol que puede crear bases de datos y administrar roles:
CREATE ROLE admin WITH CREATEDB CREATEROLE LOGIN PASSWORD '123';
5. Crear un rol que puede crear bases de datos y administrar roles:
CREATE ROLE admin WITH CREATEDB CREATEROLE LOGIN PASSWORD '123';
Probare lo anterior con otro usuario (lucho, 123):
Probare lo anterior con otro usuario (lucho, 123):
El comando ALTER ROLE se utiliza para cambiar los atributos de un rol de PostgreSQL.
ALTER ROLE name [ [ WITH ] option [ ... ] ]
las opciones pueden ser:
SUPERUSER | NOSUPERUSER
| CREATEDB | NOCREATEDB
| CREATEROLE | NOCREATEROLE
| CREATEUSER | NOCREATEUSER
| INHERIT | NOINHERIT
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
| CONNECTION LIMIT connlimit
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD 'password'
| VALID UNTIL 'timestamp'
ALTER ROLE name RENAME TO new_name
ALTER ROLE name [ IN DATABASE database_name ] SET configuration_parameter { TO | = } { value | DEFAULT }
ALTER ROLE { name | ALL } [ IN DATABASE database_name ] SET configuration_parameter FROM CURRENT
ALTER ROLE { name | ALL } [ IN DATABASE database_name ] RESET configuration_parameter
ALTER ROLE { name | ALL } [ IN DATABASE database_name ] RESET ALL
1. Cambiar la contraseña de un rol:
ALTER ROLE yhoan WITH PASSWORD '123';
2. Eliminar la contraseña de un rol:
ALTER ROLE yhoan WITH PASSWORD NULL;
No olvide que el ejemplo anterior solo funciona si habilito la conexión de los usuarios de forma trust en el archivo pg_hba.conf de lo contrario le aparecería el siguiente error:
3. Cambie la fecha de vencimiento de una contraseña especificando que la contraseña debe expirar al mediodía del 4 de octubre de 2017 utilizando la zona horaria que está una hora por delante de UTC:
ALTER ROLE yhoan VALID UNTIL 'Oct 4 12:00:00 2017 +1';
4. Actualice el rol yhoan para hacer su contraseña válida para siempre:
ALTER ROLE yhoan VALID UNTIL 'infinity';
5. Dar la capacidad a un rol de crear otros roles y nuevas bases de datos:
ALTER ROLE lucho CREATEROLE CREATEDB;
6. Para rol yhoan cambie la configuración del parámetro client_min_messages de DEFAULT a DEBUG para la base de datos dvdrental. Para saber mas sobre estos parámetros de configuración:https://www.postgresql.org/docs/current/static/runtime-config.html
ALTER ROLE yhoan IN DATABASE dvdrental SET client_min_messages = DEBUG;
SELECT * FROM pg_authid;
SELECT * FROM pg_roles;
Con frecuencia es conveniente agrupar a los usuarios para facilitar la administración de privilegios: de esa manera, los privilegios se pueden conceder o revocar a un grupo como un todo. De esta forma se simplifica la gestión de permisos, pues es más simple lidiar con la granularidad de altas (GRANT) y bajas (REVOKE) de privilegios. Un rol de grupo es un rol común y corriente sin posibilidad de login (si se le otorga login se convierte en un rol de usuario).
Con frecuencia es conveniente agrupar a los usuarios para facilitar la administración de privilegios: de esa manera, los privilegios se pueden conceder o revocar a un grupo como un todo. De esta forma se simplifica la gestión de permisos, pues es más simple lidiar con la granularidad de altas (GRANT) y bajas (REVOKE) de privilegios.
Un rol de grupo es un rol común y corriente sin posibilidad de login (si se le otorga login se convierte en un rol de usuario).
CREATE ROLE Analistas;
GRANT group_role TO role1, ... ;
REVOKE group_role FROM role1, ... ;
-- Creando los grupos de usuarios
CREATE ROLE grupo_administradores;
CREATE ROLE grupo_aprendices;
-- Creando los usuarios del grupo administrativo
CREATE ROLE ygaleano WITH LOGIN PASSWORD 'admin' IN ROLE grupo_administradores;
CREATE USER cserna WITH PASSWORD 'admin' IN ROLE grupo_administradores;
-- Creando los usuarios del grupo aprendices
CREATE USER egomez WITH PASSWORD 'aprendiz' IN ROLE grupo_aprendices;
CREATE USER egomez1 WITH PASSWORD 'aprendiz' IN ROLE grupo_aprendices;
CREATE USER jserna WITH PASSWORD 'aprendiz' IN ROLE grupo_aprendices;
CREATE USER yramos WITH PASSWORD 'aprendiz' IN ROLE grupo_aprendices;
CREATE USER esuarez WITH PASSWORD 'aprendiz' IN ROLE grupo_aprendices;
Digamos que debemos crear un grupo de administradores y aprendices que tendrán acceso a la base de datos y que luego por medio de privilegios se asignaran los permisos a los objetos de la base de datos.
Veamos el ejemplo.
-- Creando los grupos de usuarios
CREATE ROLE grupo_instructores;
-- Asignando los usuarios al grupo instructores
GRANT grupo_instructores TO ygaleano, cserna;
Si por alguna razón los usuarios ya hubiesen sido creados y por alguna razón se debe crear un grupo, realizamos el siguiente comando:
-- Creando los grupos de auto-evaluación
CREATE ROLE grupo_autoevaluacion ROLE ygaleano, cserna;
O pudieses realizar esta sentencia:
DROP ROLE name;
Cualquier rol perteneciente al grupo se revoca automáticamente (pero los roles miembros no se ven afectadas de otro modo).
Cuando se crea un objeto, se le asigna un propietario. Normalmente, un propietario tiene la función de ejecutar determinadas instrucciones. Para la mayoría de tipos de objetos, el estado inicial es que sólo el propietario (o un superusuario) puede hacer algo con el objeto. Para permitir que otros roles lo utilicen, deben concederse privilegios. Un privilegio es un derecho para ejecutar un tipo particular de instrucción SQL o para acceder al objeto de otro usuario.
Hay diferentes tipos de privilegios:
SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER, CREATE, CONNECT, TEMPORARY, EXECUTE y USAGE.
Los privilegios aplicables a un objeto determinado varían dependiendo del tipo del objeto (tabla, función, etc.)
La sentencia GRANT define los privilegios de acceso.
Esta se utiliza para otorgar privilegios a un objeto de base de datos (tabla, columna, vista, tabla externa, secuencia, base de datos, función, lenguaje de procedimiento, esquema o espacio de tablas) y estos permisos se le asignan a un rol o grupo de roles.
Que estos permisos le sean asignados a un grupo es muy significativo, puesto que este grupo transmite los privilegios otorgados a cada uno de sus miembros.
Permisos para tablas
GRANT {
{ SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } [, ...]
|
ALL [ PRIVILEGES ]
}
ON {
[ TABLE ] table_name [, ...]
|
ALL TABLES IN SCHEMA schema_name [, ...]
}
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
Permisos para columnas de una tabla
GRANT {
{ SELECT | INSERT | UPDATE | REFERENCES } ( column [, ...] ) [, ...]
|
ALL [ PRIVILEGES ] ( column [, ...] )
}
ON [ TABLE ] table_name [, ...]
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
Permisos para las secuencias
GRANT {
{ USAGE | SELECT | UPDATE } [, ...]
|
ALL [ PRIVILEGES ]
}
ON {
SEQUENCE sequence_name [, ...]
|
ALL SEQUENCES IN SCHEMA schema_name [, ...]
}
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
Permisos para las bases de datos
GRANT {
{ CREATE | CONNECT | TEMPORARY | TEMP } [, ...]
|
ALL [ PRIVILEGES ]
}
ON DATABASE database_name [, ...]
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
Permisos para los dominios creados
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN domain_name [, ...]
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
Permisos para las funciones
GRANT {
EXECUTE
|
ALL [ PRIVILEGES ]
}
ON {
FUNCTION function_name ( [ [ argmode ] [ arg_name ] arg_type [, ...] ] ) [, ...]
|
ALL FUNCTIONS IN SCHEMA schema_name [, ...]
}
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
Permisos para los esquemas
GRANT {
{ CREATE | USAGE } [, ...]
|
ALL [ PRIVILEGES ]
}
ON SCHEMA schema_name [, ...]
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
Permisos para los espacios de tablas
GRANT { CREATE | ALL [ PRIVILEGES ] }
ON TABLESPACE tablespace_name [, ...]
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
Permisos para los tipos de datos
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON TYPE type_name [, ...]
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
Permisos para roles
GRANT role_name [, ...] TO role_name [, ...] [ WITH ADMIN OPTION ]
El comando REVOKE se utiliza para revocar los privilegios concedidos anteriormente de uno o más roles
REVOKE [ GRANT OPTION FOR ]
{
{ SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER } [, ...]
|
ALL [ PRIVILEGES ]
}
ON
{
[ TABLE ] table_name [, ...]
|
ALL TABLES IN SCHEMA schema_name [, ...]
}
FROM { [ GROUP ] role_name | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
Tablespace en PostgreSQL permiten a los administradores definir los lugares, en el sistema de archivos, donde los archivos de la base de datos se pueden almacenar.
Una vez creado, un Tablespace puede ser llamado por su nombre a la hora de crear objetos de base de datos.
Mediante el uso de Tablespace, un administrador puede controlar la estructura del disco de instalación de PostgreSQL. Esto es útil por lo menos en dos formas.
En primer lugar, si la partición o volumen en el que el grupo se ha inicializado se queda sin espacio y no puede extenderse, un espacio de Tablespace se pueden crear en una partición diferente y se utiliza hasta que el sistema puede ser reconfigurado.
En segundo lugar, permitir a un administrador el uso de los patrones de uso de objetos de base de datos para optimizar el rendimiento. Por ejemplo, un índice que es muy usado puede ser colocado en un dispositivo de estado sólido.
Al mismo tiempo, una tabla para almacenar datos que rara vez se utiliza o los resultados no son críticos, podrían estar almacenados en un sistema de disco menos costoso o más lento.
CREATE TABLESPACE tablespace_name
OWNER user_name
LOCATION directory_path;
CREATE TABLESPACE tbl_mis_datos
OWNER postgres
LOCATION 'E:\especializacion\postgres\tablespaces';
Tablas, índices, bases de datos completas pueden ser asignadas a los TABLESPACES.
Por ejemplo, el siguiente query crea una tabla en la tablespace tbl_mis_datos.
Como alternativa, utilice el parámetro default_tablespace.
CREATE TABLE prueba (i int) TABLESPACE tbl_mis_datos;
SET default_tablespace = tbl_mis_datos;
CREATE TABLE prueba (i int);
CREATE DATABASE mi_db TABLESPACE tbl_mis_datos;
PostgreSQL tiene una rica y amplia variedad de tipos de datos en los que se puede guardar valores de para los usos comunes, científicos y financieros que el usuario necesite.
Si no se encuentran entre los tipos nativos, algun tipo de dato que necesites, puedes definir alguno con el comando CREATE TYPE.
Veamos algunos de los tipos de datos mas importantes para trabajar con PostgreSQL:
/*Creación de tabla*/
CREATE TABLE tbl_producto(
idProducto INT NOT NULL PRIMARY KEY,
disponible BOOLEAN NOT NULL
);
/*Inserciones*/
INSERT INTO tbl_producto(idProducto, disponible)
VALUES
(100, TRUE),
(200, FALSE),
(300, 't'),
(400, '1'),
(500, 'y'),
(600, 'yes'),
(700, 'no'),
(800, '0');
/*Selects*/
SELECT *
FROM tbl_producto
WHERE disponible = 'yes';
SELECT *
FROM tbl_producto
WHERE disponible;
SELECT *
FROM tbl_producto
WHERE disponible = 'no';
SELECT *
FROM tbl_producto
WHERE NOT disponible;
/*Alterar las tablas*/
ALTER TABLE tbl_producto
ALTER COLUMN disponible SET DEFAULT FALSE;
INSERT INTO tbl_producto(idProducto)
VALUES (900);
SELECT *
FROM tbl_producto
WHERE NOT disponible;
El tipo de dato text puede almacenar una cadena de longitud ilimitada.
Si no especifica el entero n para el tipo de dato varchar, se comporta como el tipo de dato text.
El rendimiento del varchar (sin n) y el text son los mismos. La única ventaja de especificar la longitud para el tipo de datos varchar es que PostgreSQL comprobará y emitirá un error si intenta insertar una cadena más larga en la columna varchar(n).
A diferencia de varchar, el character o char sin el especificador de longitud es el mismo que el character(1) o char(1).
Diferente de otros sistemas de bases de datos, en PostgreSQL, no hay diferencia de rendimiento entre tres tipos de caracteres.
En la mayoría de las situaciones, debe utilizar text o varchar y varchar(n) si desea que PostgreSQL compruebe el límite de longitud.
CREATE TABLE tbl_caracter (
idCaracter serial PRIMARY KEY,
a CHAR (1),
b VARCHAR (10),
c TEXT
);
INSERT INTO tbl_caracter (a, b, c)
VALUES
(
'Si',
'Esto es una prueba para el varchar',
'Esto es un gran texto para probar el tipo de dato text'
);
INSERT INTO tbl_caracter (a, b, c)
VALUES
(
'S',
'Esto es una prueba para el varchar',
'Esto es un gran texto para probar el tipo de dato text'
);
INSERT INTO tbl_caracter (a, b, c)
VALUES
(
'S',
'Varchar(n)',
'Esto es un gran texto para probar el tipo de dato text'
);
Los campos de tipo serial : se almacenan en un campo de tipo int
Los bigserial : se almacenan en un campo de tipo bigint.
En los decimales el rango depende de los argumentos que le pasemos, también los bytes que ocupa.
Se utiliza el punto como separador de decimales.
Si ingresamos un valor con más decimales que los permitidos, redondea al más cercano; por ejemplo, si definimos "decimal(4,2)" e ingresamos el valor "12.686", guardará "12.69", redondeando hacia arriba; si ingresamos el valor "12.682", guardará "12.67", redondeando hacia abajo.
Si intentamos ingresar un valor fuera de rango, no lo permite.
Si ingresamos una cadena, PostgreSQL intenta convertirla a valor numérico, si dicha cadena consta solamente de dígitos, la conversión se realiza, luego verifica si está dentro del rango, si es así, la ingresa, sino, muestra un mensaje de error y no ejecuta la sentencia. Si la cadena contiene caracteres que PostgreSQL no puede convertir a valor numérico, muestra un mensaje de error y la sentencia no se ejecuta.
Es importante elegir el tipo de dato adecuado según el caso, el más preciso. Por ejemplo, si un campo numérico almacenará valores positivos menores a 255, el tipo "int" no es el más adecuado, conviene el tipo "smallint", de esta manera usamos el menor espacio de almacenamiento posible.
CREATE TABLE tbl_numerico (
idNumerico serial PRIMARY KEY,
codigoBarras bigserial,
popular INT NOT NULL,
edad SMALLINT NOT NULL,
cedula BIGINT NOT NULL,
precio DECIMAL(5, 2) NOT NULL,
flotante1 FLOAT NOT NULL, -- Maximo de 8 Bytes, Por defecto es de 2 Bytes
flotante2 REAL NOT NULL, -- Es un Float de 4 Bytes, float4
doubleColumna DOUBLE PRECISION NOT NULL, -- Es un Float de 8 Bytes, float8
resultado NUMERIC(5, 2) NOT NULL
);
CREATE TABLE tbl_post(
idPost serial PRIMARY KEY,
encabezado VARCHAR (255) NOT NULL,
fechaCreacion DATE NOT NULL DEFAULT CURRENT_DATE
);
INSERT INTO tbl_post(encabezado)
VALUES ('Probando las fechas');
SELECT *
FROM tbl_post;
SELECT NOW()::date, NOW()::time, NOW();
SELECT CURRENT_DATE;
SELECT AGE('1993-07-05' :: DATE);
SELECT to_char(date '2017-09-02', 'YYYY/MM/DD');
SELECT to_char('2017-09-02' :: DATE, 'YYYY/MM/DD');
SELECT TO_CHAR(NOW() :: DATE, 'dd/mm/yyyy');
SELECT
EXTRACT (YEAR FROM NOW()) AS YEAR,
EXTRACT (MONTH FROM NOW()) AS MONTH,
EXTRACT (DAY FROM NOW()) AS DAY;
SELECT '2017-09-09' - now() as "¿Falta para el evento?"
CREATE TABLE tbl_turnos (
idTurno serial PRIMARY KEY,
nombreTurno VARCHAR NOT NULL,
empieza TIME NOT NULL,
termina TIME NOT NULL
);
INSERT INTO tbl_turnos (nombreTurno , empieza , termina )
VALUES('Mañana', '08:00:00', '12:00:00'),
('Tarde', '13:00:00', '17:00:00'),
('Noche', '18:00:00', '22:00:00');
SELECT CURRENT_TIME;
SELECT CURREN_TIME(5);
SELECT LOCALTIME;
SELECT LOCALTIME(3);
CREATE TABLE tbl_ZonaHoraria(
idZona serial NOT NULL PRIMARY KEY,
nombre varchar(50) NOT NULL
);
INSERT INTO tbl_ZonaHoraria(nombre)
VALUES ('Asia/Yekaterinburg'),
('America/Bogota'),
('America/Adak');
SELECT * FROM tbl_ZonaHoraria;
SELECT nombre, CURRENT_TIME AT TIME ZONE (nombre), LOCALTIME AT TIME ZONE (nombre)
FROM tbl_ZonaHoraria;
SELECT
LOCALTIME,
EXTRACT (HOUR FROM LOCALTIME) as hora,
EXTRACT (MINUTE FROM LOCALTIME) as minutos,
EXTRACT (SECOND FROM LOCALTIME) as segundos,
EXTRACT (milliseconds FROM LOCALTIME) as Milisegundos;
/*Oparaciones*/
SELECT LOCALTIME + INTERVAL '2 hours';
SELECT time '10:00' - time '02:00';
SELECT time '10:00' * 2;
CREATE TABLE tbl_timestamp (ts TIMESTAMP, tstz TIMESTAMPTZ);
SHOW TIMEZONE;
INSERT INTO tbl_timestamp (ts, tstz)
VALUES
(
'2017-09-02 19:10:25-07',
'2017-09-02 19:10:25-07' -- 'America/Los_Angeles'
);
SELECT *
FROM tbl_timestamp;
SELECT NOW();
SELECT CURRENT_TIMESTAMP;
SELECT TIMEOFDAY();
SELECT timezone('America/Los_Angeles','2017-09-02 00:00');
SELECT timezone('America/Los_Angeles','2017-09-02 00:00'::timestamptz);
/*
Sintaxis: cantidad unidad [dirección]
cantidad es cualquier numero (+ o -)
unidad puede ser cualquiera de las siguientes: millennium, century, decade, year, month, week,
day, hour, minute, second, millisecond, microsecond, sus abreviaturas (y, m, d, etc.,) o
sus formas plurales (months, days, etc.).
dirección puede ser: ago
*/
SELECT INTERVAL '2 months ago', INTERVAL '3 hours 20 minutes';
SELECT NOW() - interval '2 DAY' AS "Hace dos días";
SELECT NOW() - interval 'P0000-00-02T00:00:00' AS "Hace dos días";
SELECT NOW() - interval 'P0Y0M2DT0H0M0S' AS "Hace dos días";
SET intervalstyle = 'sql_standard';
SELECT
INTERVAL '6 years 5 months 4 days 3 hours 2 minutes 1 second';
SET intervalstyle = 'postgres';
SELECT
INTERVAL '6 years 5 months 4 days 3 hours 2 minutes 1 second';
SET intervalstyle = 'postgres_verbose';
SELECT
INTERVAL '6 years 5 months 4 days 3 hours 2 minutes 1 second';
SET intervalstyle = 'iso_8601';
SELECT
INTERVAL '6 years 5 months 4 days 3 hours 2 minutes 1 second';
SELECT
INTERVAL '2h 50m' + INTERVAL '10m'; -- 03:00:00
SELECT
INTERVAL '2h 50m' - INTERVAL '50m'; -- 02:00:00
SELECT
600 * INTERVAL '1 minute'; -- 10:00:00
SELECT
justify_days(INTERVAL '80 days'),
justify_hours(INTERVAL '50 hours'),
justify_interval(interval '13 month')
justify_interval(interval '1 year -1 hour');
SELECT EXTRACT (MINUTE FROM INTERVAL '5 hours 21 minutes');
SELECT TO_CHAR( INTERVAL '17h 20m 05s', 'HH24:MI:SS');
CREATE TABLE tbl_ordenes (
ID serial NOT NULL PRIMARY KEY,
info json NOT NULL
);
INSERT INTO tbl_ordenes(info)
VALUES
(
'{ "cliente": "John Doe", "items": {"producto": "Cerveza","cantidad": 6}}'
),
(
'{ "cliente": "Yhoan Galeano", "items": {"producto": "Pañales","cantidad": 24}}'
),
(
'{ "cliente": "Adalberto Carcamo", "items": {"producto": "Galletas","cantidad": 1}}'
),
(
'{ "cliente": "Christian Serna", "items": {"producto": "Cuadernos","cantidad": 2}}'
);
SELECT info FROM tbl_ordenes;
PostgreSQL proporciona dos operadores nativos -> y - >> para ayudarle a consultar los datos de JSON.
El operador -> devuelve el campo del objeto JSON por clave.
El operador - >> devuelve el campo de objeto JSON por texto.
SELECT
info -> 'cliente' AS cliente,
info -> 'items' AS items,
info ->> 'cliente' AS cliente,
info ->> 'items' AS items
FROM
tbl_ordenes;
SELECT
info -> 'items' ->> 'producto' as producto
FROM
tbl_ordenes
ORDER BY
producto;
SELECT
info -> 'items' ->> 'producto' as producto
FROM
tbl_ordenes
WHERE
info -> 'items' ->> 'producto' LIKE '%ñ%'
ORDER BY
producto;
SELECT
info -> 'items' ->> 'producto' as producto
FROM
tbl_ordenes
WHERE
CAST(info -> 'items' ->> 'cantidad' AS INTEGER) > 5
ORDER BY
producto;
SELECT json_each (info) FROM tbl_ordenes;
SELECT json_object_keys (info->'items') FROM tbl_ordenes;
SELECT json_typeof (info->'items') FROM tbl_ordenes;
SELECT json_typeof (info->'items'->'cantidad') FROM tbl_ordenes;
SELECT point(6.300953, -75.568887)
UUID de PostgreSQL UUID significa Universal Unique Identifier definido por RFC 4122 y otras normas relacionadas. Un valor UUID es la cantidad de 128 bits generada por un algoritmo que la hace única en el universo conocido usando el mismo algoritmo (Secuencia de 32 - Más información https://www.postgresql.org/docs/9.5/static/uuid-ossp.html).
A continuación se muestran algunos ejemplos de los valores UUID:
Como puede ver, un UUID es una secuencia de 32 dígitos hexadecimales representados en grupos separados por guiones.
Debido a su característica de singularidad, a menudo se encuentra UUID en los sistemas distribuidos, ya que garantiza una singularidad mejor que el tipo de datos SERIAL que genera sólo valores únicos dentro de una sola base de datos.
Para almacenar valores UUID en la base de datos PostgreSQL, se utiliza el tipo de datos UUID.
Como puede ver, un UUID es una secuencia de 32 dígitos hexadecimales representados en grupos separados por guiones.
Debido a su característica de singularidad, a menudo se encuentra UUID en los sistemas distribuidos, ya que garantiza una singularidad mejor que el tipo de datos SERIAL que genera sólo valores únicos dentro de una sola base de datos.
Para almacenar valores UUID en la base de datos PostgreSQL, se utiliza el tipo de datos UUID.
Para habilitar el uso de UUID, PostgreSQL no cuenta con funciones propias para esto. Lo bueno es que permite el uso de funciones de terceros para generarlos.
Para esto debemos ejecutar el siguiente comando:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
El IF NOT EXIST me permite que el modulo no se vuelva a instalar.
Si desea generar un valor UUID basándose únicamente en números aleatorios, puede utilizar la función uuid_generate_v4 ().
Por ejemplo:
SELECT uuid_generate_v4();
El IF NOT EXIST me permite que el modulo no se vuelva a instalar.
Para crear una tabla utilizando este tipo de dato, podríamos realizar lo siguiente:
CREATE TABLE contacts (
contact_id uuid DEFAULT uuid_generate_v4 (),
first_name VARCHAR NOT NULL,
last_name VARCHAR NOT NULL,
email VARCHAR NOT NULL,
phone VARCHAR,
PRIMARY KEY (contact_id)
);
Una secuencia (sequence) se emplea para generar valores enteros secuenciales únicos y asignárselos a campos numéricos; se utilizan generalmente para las claves primarias de las tablas garantizando que sus valores no se repitan (normalmente utilizamos la definición de un campo serial, este tiene asociado una secuencia en forma automática)
Una secuencia es una tabla con un campo numérico en el cual se almacena un valor y cada vez que se consulta, se incrementa tal valor para la próxima consulta.
CREATE SEQUENCE [ IF NOT EXISTS ] name
[ START [ WITH ] start ]
[ INCREMENT [ BY ] increment ]
[ MAXVALUE maxvalue | NO MAXVALUE ]
[ MINVALUE minvalue | NO MINVALUE ]
[ [ NO ] CYCLE ]
[ OWNED BY { table_name.column_name | NONE } ]
La cláusula "start with" indica el valor desde el cual comenzará la generación de números secuenciales. Si no se especifica, se inicia con el valor que indique "minvalue".
La cláusula "increment by" especifica el incremento, es decir, la diferencia entre los números de la secuencia; debe ser un valor numérico entero positivo o negativo diferente de 0. Si no se indica, por defecto es 1.
"maxvalue" define el valor máximo para la secuencia. Si se omite, por defecto es 9223372036854775807.
"minvalue" establece el valor mínimo de la secuencia. Si se omite será -9223372036854775808.
La cláusula "cycle" indica que, cuando la secuencia llegue a máximo valor (valor de "maxvalue") se reinicie, comenzando con el mínimo valor ("minvalue") nuevamente, es decir, la secuencia vuelve a utilizar los números.
La opción OWNED BY hace que la secuencia se asocie con una columna de tabla específica, de tal manera que si esa columna (o toda su tabla) se deja caer, la secuencia se eliminará automáticamente también. La tabla especificada debe tener el mismo propietario y estar en el mismo esquema que la secuencia. OWNED BY NONE, el valor predeterminado, especifica que no existe tal asociación.
Si se omite, por defecto la secuencia se crea "nocycle", lo que produce un error si supera el máximo valor. Si no se especifica ninguna cláusula, excepto el nombre de la secuencia, por defecto, comenzará en 1, se incrementará en 1, el mínimo valor será -9223372036854775808, el máximo será 9223372036854775807 y "nocycle".
CREATE SEQUENCE sec_discotecas
START 1
INCREMENT 1
MAXVALUE 99999
MINVALUE 1;
SELECT nextval('sec_discotecas');
SELECT currval('sec_discotecas');
SELECT setval('sec_discotecas', 7);
drop sequence sec_discotecas;
-- SINTAXIS
CREATE DATABASE nombre OWNER = usuario TABLESPACE = el_tablespace
-- SINTAXIS
CREATE TABLE [ IF NOT EXISTS ] nombre_tabla (
columna1 tipo_dato,
columna2 tipo_dato (tamaño),
columna3 tipo_dato NOT NULL,
columna4 tipo_dato
DEFAULT valor_x_defecto,
columna5 SERIAL,
CONSTRAINT nombre_constraint1
CHECK (columnaN > valor and columaN < valor),
CONSTRAINT nombre_constraint2
PRIMARY KEY (columnaN, …, columnaM),
CONSTRAINT nombre_constraint3
UNIQUE (columnaN, …, columnaM),
CONSTRAINT nombre_constraint4
FOREIGN KEY (columnaN, … columnaM)
REFERENCES otra_tabla(columnaN, … columnaM)
ON DELETE acción ON UPDATE accion
);
-- SINTAXIS
ALTER DATABASE nombre RENAME TO nuevo_nombre;
ALTER DATABASE nombre OWNER TO nuevo_usuario;
ALTER DATABASE nombre SET TABLESPACE nuevo_tablespace;
ALTER TABLE nombre ADD COLUMN campoN tipo_dato (tamaño);
ALTER TABLE nombre DROP COLUMN campoN;
ALTER TABLE nombre ALTER COLUMN campoN SET NOT NULL;
ALTER TABLE nombre ALTER COLUMN campoN DROP NOT NULL;
ALTER TABLE nombre ADD CONSTRAINT nombre_constraint
FOREIGN KEY (campoN, … campoM)
REFERENCES otra_tabla (campoN, …, campoM) ON DELETE acción ON UPDATE acción;
ALTER TABLE nombre DROP CONSTRAINT nombre_constraint;
ALTER TABLE nombre ALTER COLUMN campoN SET DEFAULT valor_x_defecto;
ALTER TABLE nombre ALTER COLUMN campoN DROP DEFAULT;
ALTER TABLE nombre ALTER COLUMN campoN TYPE nuevo_tipo (tamaño);
ALTER TABLE nombre RENAME COLUMN columnaN TO columnaM;
ALTER TABLE nombre RENAME TO nuevo_nombre;
-- Usuarios
DROP USER nombre
-- Bases de Datos
DROP DATABASE nombre
-- Tablas
DROP TABLE nombre
INSERT INTO tabla (campo1, campo2, …, campoN)
VALUES (valor1, valor2, …., valorN)
INSERT INTO tabla (campo5, campo3, campo1, campo18, …, campoN)
VALUES (valor5, valor1, valor18, …, valorN)
INSERT INTO tabla
VALUES (valor1, valor2, …, valorN)
INSERT INTO tabla
VALUES (DEFAULT, valorN, valorM, …, valorZ)
INSERT INTO tabla
VALUES (valorA1, valorA2, … valorAN),
(valorB1, valorB2, …, valorBN),
(valorC1, valorC2, … valorCN)
INSERT INTO tabla SELECT consulta_aqui
UPDATE tabla SET campo1 = valor1, campo2 = valor2, …, campoN = valorN
WHERE campoM = valorM
Where:
WHERE campoM = valorM (=, >, <, <>)
WHERE campoM BETWEEN valor1 AND valor2
WHERE campoM IN (valor1, valor2, …, valorN)
WHERE campoM IN SELECT consulta
WHERE campoM NOT IN…
DELETE FROM tabla WHERE campoN = valorN
Where:
WHERE campoM = campoM (=, >, <, <>)
WHERE campoM BETWEEN valor1 AND valor2
WHERE campoM IN (valor1, valor2, …, valorN)
WHERE campoM IN SELECT consulta
WHERE campoM NOT IN…
alter table NOMBRETABLA
add constraint NOMBRECONSTRAINT
primary key (CAMPO,...);
alter table NOMBRETABLA1
add constraint NOMBRERESTRICCION
foreign key (CAMPOCLAVEFORANEA)
references NOMBRETABLA2 (CAMPOCLAVEPRIMARIA);
PRIMARY KEY constraint
UNIQUE Constraint
ALTERAR PRIMARY KEY
ALTERAR UNIQUE
FOREIGN KEY
REFERENCES
[ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
DELETE ON [NO ACTION | RESTRICT | CASCADE | SET NULL | SET DEFAULT]
UPDATE ON [NO ACTION | RESTRICT | CASCADE | SET NULL | SET DEFAULT]
ALTERAR FOREIGN
CHECK Constraint
NOT NULL constraint
ALTERAR CHECK
ALTERAR NOT NULL
CREATE VIEW define una vista de una consulta. La vista no se materializa físicamente. En su lugar, la consulta se ejecuta cada vez que se hace referencia a la vista en un SELECT.
-- Sintaxis:
CREATE [ OR REPLACE ]
VIEW name [ ( column_name [, ...] ) ]
AS query
CREATE OR REPLACE VIEW permite que verificar si la vista ya existe con el mismo nombre, de ser así, esta se reemplaza.
Las vistas temporales existen en un esquema especial, por lo que no se puede dar un nombre de esquema al crearla.
El nombre de la vista debe ser distinto del nombre de cualquier otra vista, tabla, secuencia, índice o tabla externa en el mismo esquema.
Estas permiten ocultar información: De esta manera estaríamos protegiendo de pronto información importante o que no esta disponible para todos los usuarios.
Permisos sobre tablas: se puede dar al usuario permisos para que solamente pueda acceder a los datos a través de vistas, en lugar de concederle permisos para acceder a ciertos campos, así se protegen las tablas base de cambios en su estructura.
Mejorar el rendimiento: se puede evitar tipear instrucciones repetidamente almacenando en una vista el resultado de una consulta compleja que incluya información de varias tablas.
SELECT
cu.customer_id AS id,
cu.store_id AS sid,
(((cu.first_name)::text || ' '::text) || (cu.last_name)::text) AS name,
ad.address,
ad.postal_code AS "zip code",
ad.phone,
ci.city,
co.country,
CASE WHEN cu.activebool
THEN 'active'::text
ELSE ''::text
END AS notes
FROM
customer as cu
INNER JOIN address as ad ON cu.address_id = ad.address_id
INNER JOIN city as ci ON ad.city_id = ci.city_id
INNER JOIN country as co ON ci.country_id = co.country_id
ORDER BY cu.customer_id
CREATE VIEW customer_master AS
SELECT
cu.customer_id AS id,
cu.store_id AS sid,
(((cu.first_name)::text || ' '::text) || (cu.last_name)::text) AS name,
ad.address,
ad.postal_code AS "zip code",
ad.phone,
ci.city,
co.country,
CASE WHEN cu.activebool
THEN 'active'::text
ELSE ''::text
END AS notes
FROM
customer as cu
INNER JOIN address as ad ON cu.address_id = ad.address_id
INNER JOIN city as ci ON ad.city_id = ci.city_id
INNER JOIN country as co ON ci.country_id = co.country_id
ORDER BY cu.customer_id
CREATE OR REPLACE VIEW customer_master AS
SELECT
cu.customer_id AS id,
cu.store_id AS sid,
(((cu.first_name)::text || ' '::text) || (cu.last_name)::text) AS name,
ad.address,
ad.postal_code AS "zip code",
ad.phone,
ci.city,
co.country,
CASE WHEN cu.activebool
THEN 'active'::text
ELSE ''::text
END AS notes,
cu.email
FROM
customer as cu
INNER JOIN address as ad ON cu.address_id = ad.address_id
INNER JOIN city as ci ON ad.city_id = ci.city_id
INNER JOIN country as co ON ci.country_id = co.country_id
ORDER BY cu.customer_id
ALTER VIEW customer_master RENAME TO customer_info;
ALTER VIEW customer_master RENAME TO customer_info;
DROP VIEW IF EXISTS customer_info;
Una vista de PostgreSQL es actualizable cuando cumple con las siguientes condiciones:
La consulta de definición de la vista debe tener exactamente una entrada en la cláusula FROM, que puede ser una tabla u otra vista actualizable.
La consulta de definición no debe contener una de las siguientes cláusulas: GROUP BY, HAVING, LIMIT, OFFSET, DISTINCT, WITH, UNION, INTERSECT y EXCEPT.
La lista de selección no debe contener ninguna función de devolución de conjuntos o cualquier función agregada tal como SUM, COUNT, AVG, MIN, MAX, etc.
Al ejecutar una operación de actualización como INSERT, UPDATE o DELETE, PosgreSQL convertirá esta instrucción en la instrucción correspondiente de la tabla subyacente.
En caso de que tenga una condición WHERE en la consulta de definición de una vista, puede de igual manera actualizar o eliminar las filas que no son visibles a través de la vista.
Los usuarios que realizan operaciones de actualización deben tener el privilegio correspondiente en la vista, pero no necesitan tener privilegios en la tabla subyacente. Sin embargo, los propietarios de vista deben tener privilegios de la tabla subyacente.
CREATE VIEW colombia_cities AS
SELECT
city,
country_id
FROM
city
WHERE
country_id = 24;
SELECT * FROM colombia_cities;
INSERT INTO colombia_cities (city, country_id)
VALUES('Medellín', 24);
SELECT
city,
country_id
FROM
city
WHERE
country_id = 24
ORDER BY last_update DESC;
DELETE
FROM
colombia_cities
WHERE
city = 'Medellín';
Un disparador de PostgreSQL es una función que se invoca automáticamente cada vez que se produce un evento, por ejemplo, insertar, actualizar o eliminar.
Un trigger es una función especial definida por el usuario que se une a una tabla. Para crear un nuevo trigger, primero debe definir una función de activación y a continuación, vincularla a una tabla.
La diferencia entre un trigger y una función definida por el usuario es que un disparador se invoca automáticamente cuando se produce un evento.
PostgreSQL proporciona dos tipos principales de triggers: triggers a nivel de fila e instrucción.
Las diferencias entre los dos son cuántas veces se invoca el trigger y en qué momento. Por ejemplo, si emite una instrucción UPDATE que afecta a 20 filas, el trigger a nivel de fila se invocará 20 veces, mientras que el trigger a nivel de instrucción se invocará 1 vez.
Puede especificar si el trigger se invoca antes o después de un evento. Si el trigger se invoca antes de un evento, puede omitir la operación de la fila actual o incluso cambiar la fila que se está actualizando o insertando. En caso de que el trigger se invoque después del evento, todos los cambios están disponibles para ser usados y verificados (dependiendo de lo que se quiera realizar).
Los triggers son útiles en caso de que la base de datos sea accedida por varias aplicaciones, y desea mantener la funcionalidad cruzada dentro de la base de datos.
Por ejemplo, si desea mantener el historial de datos sin requerir que la aplicación tenga lógica para comprobar cada evento como INSERT o UDPATE.
Estos también se utilizan para mantener reglas complejas de integridad de datos. Por ejemplo, cuando se agrega una nueva fila a la tabla de clientes, también deben crearse otras filas en tablas de bancos y créditos.
El principal inconveniente de usar el trigger es que usted debe saber que este existe y entender su lógica con el fin de averiguar los efectos cuando haga cambios a los datos.
Aunque PostgreSQL implementa el estándar SQL, los triggers en PostgreSQL tienen algunas características específicas como:
CREATE FUNCTION trigger_function()
RETURN trigger AS
logic ...
Tenga en cuenta que puede crear funciones de activación utilizando cualquier lenguaje compatible con PostgreSQL. Nosotros usaremos PL/pgSQL.
La función de disparo permite acceder a unas variables importantes a través de una estructura especial llamada TriggerData, que contiene un conjunto de variables locales para trabajar. Por ejemplo, OLD y NEW representan los estados de fila en la tabla antes o después del evento trigger.
PostgreSQL proporciona otras variables locales que comienzan con TG_ como prefijo. Por ejemplo TG_WHEN, TG_TABLE_NAME, etc.
Una vez definida la función de trigger, puede vincularla a acciones específicas en una tabla.
CREATE TRIGGER trigger_name {BEFORE | AFTER | INSTEAD OF} {event [OR ...]}
ON table_name
[FOR [EACH] {ROW | STATEMENT}]
EXECUTE PROCEDURE trigger_function
Puede definir el trigger para que se active antes (ANTES) o después del evento (AFTER). El INSTEAD OF se utiliza sólo para INSERT, UPDATE o DELETE en las vistas.
El evento puede ser INSERT, UPDATE, DELETE o TRUNCATE.
PostgreSQL proporciona dos tipos de triggers: a nivel de fila y a nivel de instrucción, que puede especificarse por FOR EACH ROW o FOR EACH STATEMENT.
CREATE TRIGGER trigger_name {BEFORE | AFTER | INSTEAD OF} {event [OR ...]}
ON table_name
[FOR [EACH] {ROW | STATEMENT}]
EXECUTE PROCEDURE trigger_function
Puede definir el trigger para que se active antes (ANTES) o después del evento (AFTER). El INSTEAD OF se utiliza sólo para INSERT, UPDATE o DELETE en las vistas.
El evento puede ser INSERT, UPDATE, DELETE o TRUNCATE.
PostgreSQL proporciona dos tipos de triggers: a nivel de fila y a nivel de instrucción, que puede especificarse por FOR EACH ROW o FOR EACH STATEMENT.
CREATE DATABASE api OWNER = postgres;
CREATE TABLE tblEmpresa(
idEmpresa serial PRIMARY KEY NOT NULL,
NIT VARCHAR(13) NOT NULL,
razonSocial VARCHAR(50) NOT NULL,
telefono VARCHAR(15) NOT NULL,
nombreResponsable VARCHAR(40) NOT NULL,
usuario VARCHAR(20) NOT NULL,
contrasena VARCHAR(100) NOT NULL,
correo VARCHAR(30) NOT NULL,
estado BOOLEAN DEFAULT TRUE
);
CREATE TABLE tblEmpleado(
idEmpleado serial PRIMARY KEY NOT NULL,
nombre VARCHAR(40) NOT NULL,
apellido VARCHAR(40) NOT NULL,
fechaNacimiento DATE NOT NULL,
genero CHAR NOT NULL,
usuario VARCHAR(20) NOT NULL,
contrasena VARCHAR(100) NOT NULL,
correo VARCHAR(30) NOT NULL,
estado BOOLEAN DEFAULT TRUE,
idEmpresa INTEGER NULL,
CONSTRAINT tblEmpleado_tblEmpresa_idEmpresa
FOREIGN KEY (idEmpresa)
REFERENCES tblempresa (idEmpresa)
);
CREATE TABLE tblEmpleadoAuditoria(
idEmpleadoAuditoria serial PRIMARY KEY NOT NULL,
idEmpleado int4 NOT NULL,
idEmpresa int4 NOT NULL,
cambioEmpresa timestamp NOT NULL
);
CREATE OR REPLACE FUNCTION log_cambio_empresa()
RETURNS trigger AS
$BODY$
BEGIN
IF NEW.idEmpresa <> OLD.idEmpresa THEN
INSERT INTO tblEmpleadoAuditoria(idEmpleado,idEmpresa,cambioEmpresa)
VALUES(OLD.idEmpleado,OLD.idEmpresa,now());
END IF;
RETURN NEW;
END;
$BODY$ LANGUAGE plpgsql;
CREATE TRIGGER tg_cambio_empresa
BEFORE UPDATE
ON tblempleado
FOR EACH ROW
EXECUTE PROCEDURE log_cambio_empresa();
-- Empresas
INSERT INTO tblempresa (
nit,
razonsocial,
telefono,
nombreresponsable,
usuario,
contrasena,
correo,
estado
)
VALUES
(
'890904478-6',
'Colanta',
'4455555',
'Juan Peralta',
'colanta1',
'$2a$10$MD3RYBuMBhevj2v/K8lhEuIgx9u6OmT6GEvuu/2DrRJXVnyNi21VG',
'juanperalta@colanta.com',
't'
),
(
'890905988-6',
'Zenu',
'5035826',
'Daniela Posada',
'zenu1',
'$2a$10$MD3RYBuMBhevj2v/K8lhEuIgx9u6OmT6GEvuu/2DrRJXVnyNi21VG',
'dposada@zenu.com',
't'
);
-- Empleados
INSERT INTO tblempleado (
nombre,
apellido,
fechanacimiento,
genero,
usuario,
contrasena,
correo,
estado,
idempresa
)
VALUES
(
'Yhoan',
'Galeano',
'1993-07-05',
'M',
'yhoan1',
'$2a$10$MD3RYBuMBhevj2v/K8lhEuIgx9u6OmT6GEvuu/2DrRJXVnyNi21VG',
'yhoan@colanta.com',
TRUE,
1
),
(
'Jose',
'Lujan',
'1993-02-10',
'M',
'jose2',
'$2a$10$MD3RYBuMBhevj2v/K8lhEuIgx9u6OmT6GEvuu/2DrRJXVnyNi21VG',
'joselujan@colanta.com',
TRUE,
1
);
SELECT * FROM tblempresa;
SELECT * FROM tblempleado;
SELECT * FROM tblempleadoauditoria;
UPDATE tblempleado
SET idempresa = 2
WHERE idempleado = 2;
SELECT * FROM tblempresa;
SELECT * FROM tblempleado;
SELECT * FROM tblempleadoauditoria;
CREATE FUNCTION function_name(p1 type, p2 type)
RETURNS type AS
BEGIN
-- logic
END;
LANGUAGE language_name;
CREATE FUNCTION incrementar(IN i integer, IN val integer)
RETURNS integer AS
$BODY$
BEGIN
RETURN i + val;
END;
$BODY$
LANGUAGE plpgsql;
SELECT incrementar(10,20);
La función obtener_suma() acepta dos parámetros: a, b y devuelve un valor numérico.
De forma predeterminada, el tipo de parámetro en PostgreSQL es IN.
Puede pasar los parámetros IN a la función pero no se pueden recuperar como parte del resultado.
CREATE OR REPLACE FUNCTION obtener_suma(
a NUMERIC,
b NUMERIC)
RETURNS NUMERIC AS
$BODY$
BEGIN
RETURN a + b;
END;
$BODY$
LANGUAGE plpgsql;
Los parámetros OUT forman parte de la lista de argumentos de y de igual manera se pueden obtener en el resultado de la función.
CREATE OR REPLACE FUNCTION mayor_menor(
a NUMERIC,
b NUMERIC,
c NUMERIC,
OUT mayor NUMERIC,
OUT menor NUMERIC)AS
$BODY$
BEGIN
mayor := GREATEST(a,b,c);
menor := LEAST(a,b,c);
END;
$BODY$
LANGUAGE plpgsql;
El parámetro INOUT es la combinación de los parámetros IN y OUT. Significa al llamar la función podemos pasar el valor. Dentro de la función podrá cambiar el argumento y lo devuelve como parte del resultado.
CREATE OR REPLACE FUNCTION elevar_cuadrado(
INOUT a NUMERIC)AS
$BODY$
BEGIN
a := a * a;
END;
$BODY$
LANGUAGE plpgsql;
Una función de PostgreSQL puede aceptar un número variable de argumentos. Esto con una condición, que todos los argumentos tengan el mismo tipo de dato. Los argumentos se pasan a la función como una matriz.
CREATE OR REPLACE FUNCTION sum_avg(
VARIADIC lista NUMERIC[],
OUT total NUMERIC,
OUT average NUMERIC) AS
$BODY$
BEGIN
SELECT SUM(lista[i]) INTO total
FROM generate_subscripts(lista, 1) g(i);
SELECT AVG(lista[i]) INTO average
FROM generate_subscripts(lista, 1) g(i);
END;
$BODY$
LANGUAGE plpgsql;
-- Llamar la función
SELECT *
FROM
sum_avg(VARIADIC ARRAY[0,10,20,30,40,50,60])
CREATE OR REPLACE FUNCTION sobrecarga(
a INTEGER,
b INTEGER DEFAULT 5
)
RETURNS INTEGER AS $BODY$
DECLARE
total integer;
BEGIN
total := a * b;
RETURN total;
END;
$BODY$
LANGUAGE plpgsql;
SELECT sobrecarga(4);
SELECT sobrecarga(4, 20);
Como vemos en la declaración de la función, podemos declarar los parámetros de entrada y asignarles valores por defecto.
Esto permite que a la hora de realizar el llamado de la función podamos omitir el valor que tiene por defecto.
Los parámetros alternativos siempre van después de los obligatorios.
CREATE OR REPLACE FUNCTION SP_listarEmpleados()
RETURNS TABLE (
idEmpleado INTEGER,
nombreCompleto VARCHAR(80),
fechaNacimiento TIMESTAMP,
genero CHAR,
usuario VARCHAR(20),
correo VARCHAR(30),
estado BOOLEAN,
idEmpresa INTEGER,
razonSocial VARCHAR(50)
)
AS $BODY$
BEGIN
RETURN QUERY SELECT
e.idEmpleado, (e.nombre || ' ' || e.apellido)::VARCHAR(80), e.fechaNacimiento::TIMESTAMP, e.genero,
e.usuario, e.correo, e.estado, e.idEmpresa, emp.razonSocial
FROM
tblempleado AS e
INNER JOIN tblempresa emp
ON(e.idEmpresa = emp.idEmpresa)
ORDER BY e.idEmpleado;
END; $BODY$
LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION SP_listarEmpleados2() RETURNS TABLE (
idEmpleado INTEGER,
nombreCompleto VARCHAR (80),
fechaNacimiento TIMESTAMP,
genero CHAR,
usuario VARCHAR (20),
correo VARCHAR (30),
estado BOOLEAN,
idEmpresa INTEGER,
razonSocial VARCHAR (50)
) AS $BODY$
DECLARE
var_r record;
BEGIN
FOR var_r IN (
SELECT
e.idEmpleado,
(e.nombre || ' ' || e.apellido) :: VARCHAR (80) as nombreCompleto,
e.fechaNacimiento :: TIMESTAMP as fechaNacimiento,
e.genero,
e.usuario,
e.correo,
e.estado,
e.idEmpresa,
emp.razonSocial
FROM
tblempleado AS e
INNER JOIN tblempresa emp ON (e.idEmpresa = emp.idEmpresa)
ORDER BY
e.idEmpleado
) LOOP
idEmpleado := var_r.idEmpleado;
nombreCompleto := var_r.nombreCompleto;
fechaNacimiento := var_r.fechaNacimiento;
genero := var_r.genero;
usuario := var_r.usuario;
correo := UPPER(var_r.correo);
estado := var_r.estado;
idEmpresa := var_r.idEmpresa;
razonSocial := var_r.razonSocial;
RETURN NEXT;
END LOOP ;
END ; $BODY$ LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION SP_listarEmpleados3 ()
RETURNS SETOF tblempleado
AS
$BODY$
BEGIN
RETURN QUERY SELECT *
FROM tblempleado
ORDER BY idEmpleado;
END;
$BODY$
LANGUAGE 'plpgsql';
SELECT * FROM SP_listarEmpleados3 ()
//En el SENA
npm config set proxy http://proxy2.sena.edu.co:80
npm config set https-proxy http://proxy2.sena.edu.co:80
//En la casa
npm config rm proxy
npm config rm https-proxy
npm init
"start": "nodemon index.js",
npm i nodemon --save-dev
npm i express --save
npm i massive --save
npm i pg --save
npm i body-parser --save
npm i bcrypt-nodejs --save
npm i socket.io --save
CREATE OR REPLACE FUNCTION notify_trigger() RETURNS trigger AS $$
DECLARE
channel_name varchar DEFAULT ('changes_' || TG_TABLE_NAME);
BEGIN
IF TG_OP = 'INSERT' THEN
PERFORM pg_notify(channel_name, '{"id": "' || NEW.idempleado || '"}');
RETURN NEW;
END IF;
IF TG_OP = 'DELETE' THEN
PERFORM pg_notify(channel_name, '{"id": "' || OLD.idempleado || '"}');
RETURN OLD;
END IF;
IF TG_OP = 'UPDATE' THEN
PERFORM pg_notify(channel_name, '{"id": "' || NEW.idempleado || '"}');
RETURN NEW;
END IF;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS tg_cambios_empleado on tblempleado;
CREATE TRIGGER tg_cambios_empleado AFTER INSERT OR UPDATE OR DELETE ON tblempleado
FOR EACH ROW
EXECUTE PROCEDURE notify_trigger();
CREATE OR REPLACE VIEW vw_listaEmpleados AS
SELECT
e.idEmpleado, (e.nombre || ' ' || e.apellido)::VARCHAR(80), e.fechaNacimiento::TIMESTAMP, e.genero,
e.usuario, e.correo, e.estado, e.idEmpresa, emp.razonSocial
FROM
tblempleado AS e
INNER JOIN tblempresa emp
ON(e.idEmpresa = emp.idEmpresa)
ORDER BY e.idEmpleado;
SELECT * FROM vw_listaEmpleados;