Alejandro Schwegler
Alejandro Schwegler
General
Comparte:

Procedimientos almacenados en MySQL

Buenas Noches argentinas, me gustaría preguntarte/solicitarte si es posible que publiques unos tutoriales sobre triggers o procedimientos almacenados en la base de datos ya que actualmente estoy con un problema que tengo que resolver y es el siguiente:
- Tengo profesionales que elijen ponerse de guardia, seleccionan cuando inicia y cuando finalizan sus guardias laborales (son independientes).
- A su vez ellos pueden desactivar sus guardias o volverlas a activar si así lo quisieran... pero el flujo normal de trabajo es que no toquen nada luego de registrada su guardia (a la cual otros usuarios pueden solicitarles una emergencia).
El problema viene cuando: llega la fecha y hora en la que finaliza la guardia, ya que si bien hago un filtro para que no se muestren esas guardias porque ya finalizaron... en la base de datos siguen marcadas como "activas". Me gustaría tener un procedimiento almacenado en mi base de datos que cada "x" tiempo se ejecute y controle el "estado" en el que se encuentran las guardias ya finalizadas, y si están activas que las pase a desactivadas.
¿Es posible? ¿Podrías darme una mano con éso?
Jorge Davila
Jorge Davila (838 xp)
Primero que nada creo que estas confundiendo 2 conceptos diferentes, un stored procedure es simplemente un conjunto de metodos encapsulados que realizan cierta funcion y los puedes mandar llamar cuando los necesites. Piensalo en si como una especie de clase o funcion de PHP pero del lado de tu gestor de base de datos. Lo que intentas hacer se ejecutaria haciendo un job en SQL server, lamentablemente , si mal no recuerdo, tanto MYSQL como MariaDB carecen de jobs para realizar este tipo de acciones. Si estas siguiendo este curso lo mas probable es que estes utilizando Laravel por lo que podrias lograr dicho cometido de otra manera. Laravel utiliza una libreria llamada Carbon para la manipulacion de fechas, por lo que  podrias usar un scope para filtrar las guardias que esten "terminadas". Dicho de otra manera le indicarias a eloquent que filtrara los registros donde la fecha de termino de dicha guardia sea posterior a la fecha actual.
Para hacer eso simplemente tendrias que montar un scope global, te dejo aqui la documentacion:
https://laravel.com/docs/5.8/eloquent#global-scopes
El unico incoveniente que le veo a dicho scope es que funcionaria a nivel de codigo, por lo cual si accedes a dichos registros desde fuera de tu aplicacion de Laravel , no te respetaria dicho filtro. Segun lo que comentabas en tu post anterior la idea era desarrollar una aplicacion para movil, Laravel al tener una funconalidad "orientada a API's" puede cumplir dicha funcion. Si observas un poco el curso de la red social podras notar que todos son llamados asincronos por medio de axios o ajax , cosa que puedes usar tu en tu aplicacion para obtener informacion de tu "webservice" montado en Laravel por lo que no tendrias que desarrollar dicha logica en tu aplicacion movil , si no usarla como una especie de carcaza que simplemente tenga encapsulada la logica de "Front End". Dicho esto,  con algo asi deberia bastar para que funcione tu global scope y ese scope seria un filtro ejecutado en cada llamado a dicho modelo por lo que siempre se ejecutaria ahorrandote tener un worker o un job que haga dichas tareas.

Edit 1: Ya revise y parece que mysql si cuenta con jobs pero te recomiendo hacerlo por medio de Laravel para evitar meter carga a tu servidor por algo tan simple.
 
 /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('fecha_fin', '<',Carbon::now());
    }
 Edit 2: Otra forma de lograrlo seria usando carbon para hacer dicha comparacion y no renderizar en tu vista los objetos que no debas, aunque el scope me parece mejor idea.
 @forelse($guardias as $guardia)
@if(!$guardia->fecha_fin->isPast())
//aqui tus datos de la guardia
@endif diffInSeconds 
@empty
<li> No hay guardias activas</li>
@endforelse
Si tu campo de fecha es un campo date que reconoce eloquent, te crea una instancia de carbon por lo que puedes utilizar sus metodos directamente. Espero que esto te sirva.


1
Alejandro Schwegler
Alejandro Schwegler (90 xp)
 Si me sirve. El filtrado de las guardias ya lo hago con Carbon en el GuardiaController, pero leyendo tu respuesta pude pensar en otra forma de poner el campo (de tipo boolean) que indica que esta activa o no en "false" al mismo tiempo que realizo las consultas para mostrarlas. Es decir, al realizar la consulta, en el "where" le indico que quiero todas las guardias activas y me pregunto si la fecha de finalizacion es menor a la fecha actual, si las dos condiciones se cumplen debería desactivarla. 
Jorge Davila
Jorge Davila (838 xp)
En lo personal prefiero usar scopes ya que metes menos codigo en tu controlador y al tener un transtorno casi obsesivo-compulsivo de perfeccionismo me gustan las cosas simples pero tu puedes hacerlo de la manera que mas te guste. Yo en general al usar una bandera binaria de activo e inactivo utilizo los llamados softDelete, Eloquent los filtra por defecto, ya que usa un scope para omitir todos los registros "borrados", lo cual ya te quita a ti el trabajo. Sin embargo al usar una bandera de esta manera, tendrias que estar actualizando cada campo por lo que tendrias que usar un job o un evento para hacer esto. Si realmente necesitas marcarlo como inactiva podrias usar un evento de modelo para actualizar dichos valores despues de cada consulta.

Esto ya es Laravel intermedio/avanzado pero son herramientas muy utiles. Tambien puedes definir tus propios eventos, aqui hay un post acerca de eso:
https://translate.google.com/translate?hl=es-419&sl=en&u=https://gist.github.com/GhazanfarMir/2a4a2cbaa45c5192cf37847e206cf208&prev=search

1