esofitec. CoreDocs

esofitec. CoreDocs

Vistas SQL

Vistas SQL

Las Vistas SQL (o Vistas personalizadas) son una pantalla de a3ERP en la que el usuario puede ejecutar consultas o procesos sobre la base de datos sin salir de la aplicación. El funcionamiento es sencillo: el usuario abre la vista desde el menú y pulsa el botón de ejecutar; si la vista tiene parámetros, aparece entonces una ventana para rellenarlos (fechas, códigos, filtros...), y al aceptar se lanza el SQL.

A partir de ahí, la vista se comporta de una de estas dos maneras según lo que contenga:

  • Consulta (SELECT): devuelve una tabla de resultados que el usuario puede revisar, exportar a Excel, etc. Funciona como cualquier listado, pero sin diseño de impresión.
  • Proceso (DML): ejecuta una operación sobre los datos — actualizar campos, marcar registros... — sin devolver filas. Es el equivalente a un botón de "ejecutar proceso masivo".

Hay esqueletos completos de ambos tipos en las plantillas.

Las vistas de proceso son destructivas

Una vista de proceso modifica la base de datos en el momento en que el usuario acepta la ventana de parámetros. Debe llevar un comentario de advertencia al principio y seguir el patrón de salida descrito más abajo, para que quien la lance sepa siempre qué ha pasado.

Parámetros#

El intérprete de a3ERP sustituye los marcadores [...] por los valores que el usuario introduce en la ventana de parámetros antes de ejecutar.

El mismo mecanismo funciona en listados y parrillas

Los parámetros de usuario no son exclusivos de las vistas: un listado de impresión o una parrilla de búsqueda también pueden llevarlos, aunque es poco común. Se documentan aquí porque las vistas son su hábitat natural — son su única forma de recibir datos del usuario.

Forma básica#

[Nombre humano,TIPO]
[Nombre humano,TIPO,ValorPorDefecto]
SET @MES   = [Mes,VARCHAR(2),01];
SET @FECHA = [Fecha Mínima,DATETIME,01/01/2021];

Solo el nombre y el tipo son obligatorios; el valor por defecto, si se indica, es lo que aparece precargado en la ventana de parámetros. Un detalle casi obvio, pero que conviene dejar dicho: el nombre humano no puede contener comas — la coma es precisamente lo que separa los bloques del marcador.

Con selector de tabla#

Se puede añadir un cuarto bloque que indica a a3ERP qué tabla y campo usar para abrir una pantalla de selección cuando el usuario hace doble clic en el parámetro — así no tiene que saberse los códigos de memoria:

[Nombre humano,TIPO,ValorPorDefecto,(TABLA,CAMPO,FILTRO_OPCIONAL)]
SET @TARIFA = [Tarifa,CUADRADO(8), ,(TARIFAS,TARIFA,TARIFA.TIPO = 'V')];
SET @CAR1   = [Fabricante,CUADRADO(8), ,(CARACTERISTICAS,CODCAR,CARACTERISTICAS.NUMCAR = 1 AND CARACTERISTICAS.TIPCAR = 'A')];

El tercer elemento del filtro es opcional y acota qué registros ofrece la pantalla de selección (en los ejemplos, solo tarifas de venta y solo características de artículo de la posición 1).

Tipos de parámetro#

Tipo Comportamiento
VARCHAR(n) Cadena libre de hasta n caracteres, sin transformar
INT Número entero
MONEY Importe con decimales
DATETIME Fecha; el usuario la introduce en formato DD/MM/AAAA
CUADRADO(n) Cadena de exactamente n caracteres, mayúsculas y completada con espacios por la izquierda

Cuándo usar CUADRADO

Los códigos de a3ERP están "cuadrados": guardados con padding de espacios por la izquierda a longitud fija, normalmente 8 caracteres (CODPRO = ' 1770', TARIFA = ' 1'); las excepciones (CODART a 15, lotes a 25...) están en la visión general. Con CUADRADO(n) la aplicación genera ese padding automáticamente. Si cambias el tipo a VARCHAR sin ajustar el WHERE, la consulta no encontrará nada.

Directos en la consulta o asignados a variables#

Los marcadores pueden ir directamente en el WHERE:

WHERE ART.CAR1 = [Fabricante,CUADRADO(8)]
  AND TV.FECMIN = [Fecha Mínima,DATETIME,01/01/2021]

O asignarse a variables, que es lo cómodo cuando el valor se usa varias veces o sirve para calcular otros:

SET @MES = [Mes,VARCHAR(2),01];
SET @ANO = [Año,VARCHAR(4),2025];
SET @FECHAINI = '01-' + @MES + '-' + @ANO;
SET @FECHAFIN = DATEADD(DD, -1, DATEADD(MM, 1, @FECHAINI));

Trampas frecuentes#

  • No usar : ni [...] en comentarios SQL. El intérprete lee :texto como parámetro runtime y [texto] como marcador de parámetro estén donde estén, comentarios incluidos (-- y /* */), y la vista peta en ambos casos. Cuidado especial con el dos puntos al final de la línea: un : justo antes del salto también lo trata como parámetro. Reformular sin esos caracteres:
  • -- Solo afecta a periodicidad distinta de M (mensual):
  • -- Solo afecta a periodicidad distinta de M (mensual) — es decir,
  • -- Pasos: 1) ...
  • -- Pasos. 1) ...
  • No usar corchetes como alias de columna. Por el mismo motivo, SELECT col AS [Nombre] rompe la vista. Los alias van siempre con comillas simples: SELECT col 'Nombre'.
  • No hay transacción implícita. a3ERP lanza el SQL sin envolverlo en una transacción propia. Si el proceso hace varios UPDATE y el segundo falla, el primero ya está confirmado y los datos quedan a medias. Si el proceso necesita atomicidad, hay que abrir la transacción dentro de la propia vista (BEGIN TRANSACTION / COMMIT / ROLLBACK).
  • SET NOCOUNT ON en vistas de proceso. Sin él, cada sentencia DML devuelve su mensaje de "N filas afectadas" y a3ERP abre una pestaña de resultado por cada uno: el usuario acaba ante varias pestañas con números sueltos, sin saber qué significa cada una. Se desactiva (SET NOCOUNT OFF) justo antes del SELECT final para que el resultado que ve sea solo ese.

Patrón recomendado para vistas de proceso#

Una vista de proceso, tal cual, tiene un problema de experiencia: el usuario la ejecuta y no recibe una respuesta clara. Si el DML va sin SET NOCOUNT ON, le aparecen varias pestañas de "N filas afectadas" sin contexto; si va con él, no ve nada en absoluto. En ninguno de los dos casos sabe si el proceso ha funcionado, ha fallado o cuántos registros ha tocado.

La solución es que toda vista de proceso envuelva su DML en TRY/CATCH y termine con un SELECT que cuente el resultado. a3ERP renderiza ese SELECT como la parrilla de salida: si todo fue bien, el usuario ve el contador de filas afectadas; si algo falló, ve el mensaje de error con el detalle para depurar.

Así se ve una vista de proceso real que sigue el patrón, en la pantalla de edición de Vistas personalizadas — con su comentario de advertencia al principio, los parámetros de usuario en el WHERE y los dos SELECT de salida:

Editor de Vistas personalizadas con una vista de proceso que aplica el patrón TRY/CATCH

Plantilla básica (un solo UPDATE o INSERT)#

Cuando el proceso es una única sentencia DML no hace falta transacción explícita — la sentencia ya es atómica por sí misma:

SET NOCOUNT ON;

BEGIN TRY
    UPDATE ...   -- la lógica del proceso

    DECLARE @filas INT = @@ROWCOUNT;

    SET NOCOUNT OFF;
    SELECT
        'OK'                              'Estado',
        'Proceso finalizado sin errores'  'Mensaje',
        @filas                            'Líneas actualizadas';
END TRY
BEGIN CATCH
    SET NOCOUNT OFF;
    SELECT
        'ERROR'             'Estado',
        ERROR_MESSAGE()     'Mensaje',
        ERROR_NUMBER()      'Número',
        ERROR_SEVERITY()    'Severidad',
        ERROR_STATE()       'Estado SQL',
        ERROR_LINE()        'Línea',
        ERROR_PROCEDURE()   'Procedimiento';
END CATCH

Plantilla con transacción explícita (varios DML)#

Si el proceso ejecuta más de una sentencia DML, hay que envolverlas en una transacción para que sean atómicas — sin ella, un fallo a mitad deja confirmadas las anteriores y el estado queda inconsistente:

SET NOCOUNT ON;

BEGIN TRY
    BEGIN TRANSACTION;

    UPDATE ... ;
    UPDATE ... ;
    DECLARE @filas INT = @@ROWCOUNT;   -- la cuenta del UPDATE que interesa al usuario

    COMMIT TRANSACTION;

    SET NOCOUNT OFF;
    SELECT
        'OK'                              'Estado',
        'Proceso finalizado sin errores'  'Mensaje',
        @filas                            'Filas actualizadas';
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;

    SET NOCOUNT OFF;
    SELECT
        'ERROR'             'Estado',
        ERROR_MESSAGE()     'Mensaje',
        ERROR_NUMBER()      'Número',
        ERROR_SEVERITY()    'Severidad',
        ERROR_STATE()       'Estado SQL',
        ERROR_LINE()        'Línea',
        ERROR_PROCEDURE()   'Procedimiento';
END CATCH

Reglas a respetar#

  • Mensaje justo después de Estado en el SELECT del CATCH. Es la única columna que el usuario lee de verdad; si queda al final de la fila, tendrá que hacer scroll horizontal y no la verá.
  • @@ROWCOUNT se captura inmediatamente después del UPDATE que interesa. Cualquier sentencia intermedia — otro UPDATE, una asignación — lo pisa.
  • Etiqueta del contador descriptiva del dominio, no genérica: Tramos actualizados, Facturas marcadas OK... Si el usuario ve "Filas: 0" no sabe si eso es bueno o malo; si ve "Facturas marcadas OK: 0", entiende lo que ha pasado.
  • Alias con comillas simples, nunca corchetes ('Estado', no [Estado]) — la regla general de las vistas, aplicada a las columnas del SELECT final.
  • SET NOCOUNT OFF antes de cada SELECT final (uno en el TRY, otro en el CATCH), para que a3ERP renderice la parrilla limpia.
  • IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; en el CATCH de la versión con transacción. Sin el IF, si el error rompe la transacción antes de llegar al ROLLBACK — raro, pero pasa — el propio ROLLBACK también peta.