PL/SQL MÁGICO

Herramientas Útiles en SQL

Objetivos:

  • Ampliar el repertorio de herramientas disponibles en Oracle.
  • Describir las cláusulas PIVOT y UNPIVOT.
  • Describir la función SYS_CONTEXT.

NOTA: Usamos como ejemplo la Base de Datos: ORCL, la cual viene por defecto en cualquier versión de ORACLE.

Introducción

Si interactúas con frecuencia con una Base de Datos Oracle, notarás que se trata de un entorno realmente amplio. En ocasiones encontramos sentencias que incluyen funciones y cláusulas poco familiares, lo que dificulta el análisis y la comprensión del bloque en cuestión.

En muchos casos, estas funciones ofrecen grandes ventajas y resultan muy eficientes cuando se combinan con aquellas que ya dominamos, facilitando así una mejor administración de la base de datos.

Sin mas que decir he aquí un diminuta lista de cláusulas y funciones útiles de Oracle.

PIVOT

La cláusula PIVOT, introducida en Oracle 11g, permite crear consultas de referencia cruzada a partir de una tabla relacional mediante sentencias SQL. Asimismo, facilita la transformación de datos entre una tabla relacional y una tabla de referencia cruzada.

En otras palabras, las consultas PIVOT convierten filas en columnas para generar resultados en formato de tabla cruzada, una técnica útil para la elaboración de informes.

Sintaxis:

SELECT *
FROM
 (
   SELECT column1, column2
   FROM tables
   WHERE conditions
 )
PIVOT 
 (
   aggregate_function(column2)
   FOR column2
   IN ( expr1, expr2, ... expr_n) | subquery
 )
ORDER BY expression [ ASC | DESC ];

Ejemplo:

SELECT *
FROM
 (
    SELECT
          e.employee_id, 
          d.department_name,
          c.country_name
    FROM
          hr.employees e,
          hr.departments d,
          hr.locations l,
          hr.countries c
    WHERE
          e.department_id = d.department_id
    AND   d.location_id = l.location_id
    AND   l.country_id = c.country_id
 )
PIVOT
 (
   COUNT(employee_id)
   FOR country_name
   IN 
      (
        'United States of America',
        'United Kingdom',
        'Canada'
      )
 )
 WHERE department_name IN
                          (
                            'Purchasing',
                            'Shipping',
                            'Sales',
                            'Marketing'
                          );

En este ejemplo usamos la Sentencia PIVOT para determinar la cantidad de empleados por país que trabajan en los departamentos Purchasing, Shipping, Sales, Marketing. Notar que limitamos los resultados solo para que contenga el conteo de los empleados en países como United States of America, United Kingdom y Canada.

SELECT *
FROM
 (
    SELECT
          e.employee_id, 
          d.department_name,
          c.country_name
    FROM
          hr.employees e,
          hr.departments d,
          hr.locations l,
          hr.countries c
    WHERE
          e.department_id = d.department_id
    AND   d.location_id = l.location_id
    AND   l.country_id = c.country_id
 )
 WHERE department_name IN
                          (
                            'Purchasing',
                            'Shipping',
                            'Sales',
                            'Marketing'
                          );

Para percibir la utilidad de PIVOT, ejecutamos la misma consulta, pero sin esta cláusula.

UNPIVOT

La cláusula UNPIVOT, también introducida en Oracle 11g, tiene como función rotar datos de columnas a filas. Su nombre sugiere una acción opuesta a la cláusula PIVOT; sin embargo, UNPIVOT no revierte los cambios realizados por esta.

En síntesis, UNPIVOT transforma columnas pivotadas en filas, generando una fila de datos por cada columna despivotada.

Sintaxis:

SELECT *
FROM
 (
   SELECT column1, column2, ... columnN
   FROM tables
   WHERE conditions
 )
UNPIVOT [INCLUDE|EXCLUDE NULLS]
 (
   unpivot_clause
   FOR unpivot_for_clause
   IN ( column1, column2, ... columnN) 
 )
ORDER BY expression [ ASC | DESC ];

Ejemplo:

CREATE TABLE hr.ventas
(codigo_emp      NUMBER(5)   NOT NULL,
  mes             NUMBER(2)   NOT NULL,
  semana          NUMBER(1)   NOT NULL,
  lunes           NUMBER(7),
  martes          NUMBER(7),
  miercoles       NUMBER(7),
  jueves          NUMBER(7),
  viernes         NUMBER(7));

Para percibir el uso de la cláusula UNPIVOT, creamos una tabla para registrar las ventas que realicen los empleados por cada día laborable de la semana. Tabla usada más adelante.

INSERT INTO hr.ventas
VALUES(150,1,1,5000,350,10000,6000,50560);

INSERT INTO hr.ventas
VALUES(150,1,2,5800,8850,16000,60,560);

INSERT INTO hr.ventas
VALUES(111,1,2,8964,350,6621,471,962);

INSERT INTO hr.ventas
VALUES(111,1,4,4756,4514,894,6000,7852);

COMMIT;
SELECT
      codigo_emp,
      lunes,
      martes,
      miercoles,
      jueves,
      viernes
FROM hr.ventas;

Insertamos algunas ventas realizadas por los empleados 150 y 111 durante algunas semanas del mes de enero.

SELECT  *
FROM
(
    (
        SELECT
              codigo_emp,
              lunes,
              martes,
              miercoles,
              jueves,
              viernes
        FROM hr.ventas
    )
    UNPIVOT
    (
        ventas
        FOR dia  IN
                        (
                          lunes,
                          martes,
                          miercoles,
                          jueves,
                          viernes
                        )
    )
)
ORDER   BY codigo_emp, dia, ventas;

En este ejemplo, con el uso de UNPIVOT convertimos los datos almacenados en columnas separadas en registros.

SYS_CONTEXT

La función SYS_CONTEXT permite obtener información relevante sobre el entorno de ejecución de la base de datos Oracle, como datos de sesión, usuario y configuración del sistema.

En términos generales, SYS_CONTEXT devuelve valores asociados a un namespace del sistema, proporcionando acceso dinámico a atributos del contexto actual dentro de una sesión.

Sintaxis:

SYS_CONTEXT('namespace', 'parameter' [, length ])

En la Sintaxis:

  • namespace: Es un namespace de Oracle previamente creado. Para obtener los atributos que describen la sesión actual de Oracle puede usar el namespace‘USERENV’.
  • parameter: Es un Atributo válido previamente establecido mediante el procedimiento DBMS_SESSION.set_context.
  • length: Opcional. Es la longitud del valor de retorno en bytes. Si se omite este parámetro o si se proporciona una entrada no válida, la longitud seria 256 bytes por defecto.

Nota: Los parámetros válidos para el namespace llamado ‘USERENV’ son los siguientes: (Tenga en cuenta que no todos los parámetros son válidos en todas las versiones de Oracle).

ParámetroValor de Retorno
ACTIONIdentifica la posición en el módulo (nombre de la aplicación).
AUDITED_CURSORIDDevuelve el ID del cursor de SQL que activó la auditoría. Este parámetro no es válido en un entorno de auditoría de grano fino. Si lo especifica en dicho entorno, la Base de Datos Oracle siempre devuelve NULL.
AUTHENTICATED_IDENTITYDevuelve la identidad utilizada en la autenticación.
AUTHENTICATION_DATARetorna los datos que se utilizan para autenticar al usuario de inicio de sesión.
AUTHENTICATION_METHODDevuelve el método de autenticación. De manera adicional puede usar AUTHENTICATION_TYPE para distinguir entre usuarios externos y enterprise.
BG_JOB_IDSi la sesión se estableció mediante un proceso de background de Oracle, este parámetro devolverá el JOB ID. De lo contrario, devolverá NULL.
CLIENT_IDENTIFIERDevuelve el identificador de cliente. Este atributo es utilizado para identificar usuarios de aplicaciones que se autentican como el mismo Usuario de la Base de Datos.
CLIENT_INFOInformación sobre la sesión del usuario.
CURRENT_BINDVariables BIND para auditorías de grano fino.
CURRENT_SCHEMANombre del esquema predeterminado que utiliza el usuario actual. Es posible cambiar dicho valor en la sesión con la sentencia: ALTER SESSION SET CURRENT_SCHEMA.
CURRENT_SCHEMAIDDevuelve el identificador del esquema predeterminado utilizado por el usuario actual.
CURRENT_SQLDevuelve el SQL que activó el evento de auditoría.
CURRENT_SQL_LENGTHDevuelve la longitud de la instrucción SQL actual que desencadenó el evento de auditoría.
DB_DOMAINDominio de la Base de Datos especificado en el parámetro de inicialización DB_DOMAIN.
DB_NAMENombre de la Base de Datos especificado en el parámetro de inicialización DB_ NAME.
DB_UNIQUE_NAMENombre de la Base de Datos especificado en el parámetro de inicialización DB_ UNIQUE_NAME.
ENTRYIDIdentificador de entrada de la auditoría.
ENTERPRISE_IDENTITYRetorna la identidad enterprise-wide del usuario.
FG_JOB_IDSi la sesión fue establecida mediante un proceso foreground del cliente, este parámetro devolverá el JOB ID. De lo contrario, devolverá NULL.
GLOBAL_CONTEXT_MEMORYEs el número utilizado en el Área Global del Sistema (System Global Area) por el contexto de acceso global.
GLOBAL_UIDRetorna el ID de usuario global de Oracle Internet Directory para los inicios de sesión de seguridad empresarial. Devuelve NULL para todos los demás inicios de sesión.
HOSTNombre de la máquina host desde la cual se ha conectado el cliente.
IDENTIFICATION_TYPEDevuelve la forma en que se creó el esquema del usuario en la Base de Datos.
INSTANCEEs el número de identificación de la instancia actual.
INSTANCE_NAMEEs el nombre de la instancia actual.
IP_ADDRESSDirección IP de la máquina desde la cual el cliente está conectado.
ISDBADevuelve TRUE si el usuario tiene privilegios DBA. De lo contrario, devolverá FALSE.
LANGLa abreviatura ISO para el nombre idioma.
LANGUAGERetorna el idioma, territorio y el conjunto de caracteres de la sesión. En el formato:language_territory.characterset
MODULEDevuelve el nombre de la aplicación en uso, dicho valor es establecido a través del paquete DBMS_APPLICATION_INFO o OCI.
NETWORK_PROTOCOLRetorna el Protocolo de Red utilizado.
NLS_CALENDAREl calendario actual de la sesión.
NLS_CURRENCYEs la moneda de la sesión actual.
NLS_DATE_FORMATRetorna e l formato de fecha para la sesión actual.
NLS_DATE_LANGUAGEEl lenguaje utilizado para expresar las fechas.
NLS_SORTRetorna BINARY o la base de clasificación lingüística.
NLS_TERRITORYRetorna el territorio de la sesión actual.
OS_USERRetorna el nombre de usuario del sistema operativo del proceso cliente que inició la sesión de Base de Datos.
POLICY_INVOKERInvocador de la política de seguridad a nivel de fila.
PROXY_ENTERPRISE_IDENTITYDevuelve el DN de Oracle Internet Directory cuando el usuario proxy es un usuario enterprise.
PROXY_GLOBAL_UIDDevuelve el ID de usuario global de Oracle Internet Directory para usuarios de proxy enterprise. Devuelve NULL para todos los demás usuarios proxy.
PROXY_USERNombre de usuario de la Base de Datos que abrió la sesión actual en nombre de SESSION_USER.
PROXY_USERIDIdentificador de usuario de la Base de Datos que abrió la sesión actual en nombre de SESSION_USER.
SERVER_HOSTRetorna el nombre host de la máquina en la que se ejecuta la instancia.
SERVICE_NAMERetorna el nombre del servicio al cual está conectada la sesión.
SESSION_USERPara usuarios enterprise, devuelve el esquema. Para otros usuarios, devuelve el nombre de usuario de la Base de Datos.
SESSION_USERIDIdentificador de usuario de la Base de Datos por el cual fue autenticado.
SESSIONIDEl identificador de sesión de auditoría. Nota: no puede utilizar este atributo en sentencias SQL distribuidas.
SIDEs el número de sesión (No es lo mismo que SESSIONID).
STATEMENTIDEl identificador de la sentencia de auditoría. STATEMENTID representa el número de sentencias SQL auditadas en una sesión determinada.
TERMINALEl identificador del sistema operativo para el cliente de la sesión actual. En sentencias SQL distribuidas, este atributo devuelve el identificador de su sesión local. En un entorno distribuido, esto sólo se admite para las sentencias SELECT remotas, no para las operaciones remotas INSERTUPDATE DELETE. (La longitud de retorno de este parámetro puede variar según el sistema operativo).

Ejemplo:

SELECT
       SYS_CONTEXT('USERENV', 'HOST')                       AS HOST,
       SYS_CONTEXT('USERENV', 'OS_USER')                    AS OS_USER,
       SYS_CONTEXT('USERENV', 'INSTANCE')                   AS INSTANCE,
       SYS_CONTEXT('USERENV', 'DB_NAME')                    AS DB_NAME,
       SYS_CONTEXT('USERENV', 'SESSION_USER')               AS SESSION_USER,
       SYS_CONTEXT('USERENV', 'AUTHENTICATION_METHOD')      AS AUTHENTICATION_METHOD,
       SYS_CONTEXT('USERENV', 'ISDBA')                      AS ISDBA
FROM dual;