====== Snippets MySQL ====== Colección de consultas u operaciones útiles o interesantes de [[informatica:bases_de_datos:mysql|MySQL]]. ===== Filtrar con expresiones regulares ===== Buscar registros cuyo campo ''campo1'' comience un numero: SELECT * FROM tabla WHERE campo1 regexp '^[0-9]+' Buscar registros cuyo campo ''campo1'' comience por alguno de los números indicados: SELECT * FROM tabla WHERE campo1 regexp '^(15001|15002)+' ===== Agrupar ===== ==== Agrupar por un valor y concatenar los demás en una columna ==== Por ejemplo, si tenemos: ^ servicio_web ^ email ^ | 11111 | mail@mail.com | | 22222 | mail@mail.com | | 33333 | mail@mail.com | | 44444 | mail@mail.com | Y queremos obtener el siguiente resultado: ^ email ^ servicio_web ^ | mail@mail.com | 11111, 22222, 33333, 44444 | Usaremos la función [[https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html#function_group-concat|GROUP_CONCAT]]: SELECT email, GROUP_CONCAT(servicio_web ORDER BY servicio_web ASC SEPARATOR ', ') FROM mitabla GROUP BY email ==== Búsqueda de valores duplicados ==== Si queremos ver qué valores están duplicados en cierto campo, podemos hacer la siguiente consulta: SELECT campo1, COUNT(*) c FROM mitabla GROUP BY campo1 HAVING c > 1 Nos devolverá los valores de ''campo1'' que se repiten (de 1 a más veces) * [[https://stackoverflow.com/questions/688549/finding-duplicate-values-in-mysql|Finding duplicate values in MySQL]] (Stack Overflow) ===== Fechas ===== ==== Conversiones ==== Pasar de marca de tiempo UNIX a formato ISO: SELECT FROM_UNIXTIME(fecha) as fecha_iso Salida: fecha_iso --------- 2020-08-12 00:35:40 El tiempo UNIX (Epoch Time) es el número de segundos transcurridos desde el 01/01/1970 (UTC). Por ejemplo, las 10:00 del 01/08/2020 UTC, serían 1596276000 en tiempo UNIX. Para convertir una fecha en tiempo UNIX: SELECT UNIX_TIMESTAMP('2020-08-01 10:00') Para convertir UTC en cierta zona horaria: SELECT CONVERT_TZ(fecha_en_utc, 'UTC', 'Europe/Madrid') AS fecha_madrid FROM tabla Convertir segundos a formato de tiempo (tipo de dato TIME): SELECT SEC_TO_TIME(3600) -- Devolverá '01:00:00' Convertir un string a tipo fecha: SELECT str_to_date('12/12/2022 9:04:12', '%d/%m/%Y %k:%i:%s') Si partimos de un string como ''6/25/2024 2:25:42 AM'', para pasarlo a formato fecha: SELECT str_to_date('6/25/2024 2:25:42 AM', '%c/%e/%Y %l:%i:%s %p') * ''%c'': número del mes sin cero inicial (del 1 al 12) * ''%e'': número del día del mes sin cero inicial (del 1 al 31) * ''%Y'': número del año * ''%l'': hora sin cero inicial (de 1 a 12) * ''%i'': minutos (de 00 a 59) * ''%s'': segundos (de 00 a 59) * ''%p'': AM o PM. [[https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format|Documentación oficial de formateadores de fecha admitidos en MySQL]] ==== Otros ==== Fecha de hoy: SELECT CURDATE() También se puede utilizar la función ''CURRENT_DATE'' Fecha de ayer: SELECT SUBDATE(CURRENT_DATE, 1) Hace dos semanas: select DATE_SUB(curdate(), INTERVAL 2 WEEK) Lunes de la semana actual: SELECT DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) as fecha Lunes de la semana pasada: SELECT DATE_SUB(DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY), INTERVAL 7 DAY) AS fecha Agrupar por semanas: SELECT fecha, DATE_FORMAT(fecha, "%x-%v") AS ano_semana FROM tabla GROUP BY ano_semana ORDER BY fecha * ''%x'': año de la semana donde el lunes es el primer día de la semana. Se usa con ''%v''. * ''%v'': número de la semana (de 01 a 53) donde el lunes es el primer día de la semana. Se usa con ''%x''. Si se usa ''WEEK'', hay un problema con la última semana y primera del año. Si no es una semana completa, crea dos registros: una semana con los últimos días del año y otra semana con los primeros días del año siguiente. [[https://en.wikipedia.org/wiki/ISO_8601|Más información sobre la ISO 8601]]. ==== Operaciones ==== Sumar/restart tiempo: -- Añadir 1 día a la fecha SELECT DATE_ADD(fecha, INTERVAL 1 DAY) -- Restar 1 día a la fecha SELECT DATE_SUB(fecha, INTERVAL 1 DAY) Para restar tiempo de una expresión de tiempo o fecha+tiempo: SELECT SUBTIME('12:35:00', '1:30:00'); // 11:05:00 * [[https://database.guide/subtime-examples-mysql/|SUBTIME() Examples – MySQL]] Para ordenar, dejando los valores NULL al final: SELECT * FROM mitabla WHERE ... ORDER BY CASE WHEN mifecha IS NULL THEN 1 ELSE 0 END, mifecha Diferencia entre fechas: SELECT TIMEDIFF(fecha_fin, fecha_inicio) FROM mitabla -- fecha_fin: 2021-03-30 09:09:40 -- fecha_inicio: 2021-03-30 08:30:01 -- TIMEDIFF = 00:39:39 Diferencia en horas: SELECT TIMESTAMPDIFF(HOUR, fecha_inicio, fecha_fin) FROM mitabla ==== Comparaciones ==== Registros de hace más de una hora: SELECT * FROM tabla WHERE fecha_registro < DATE_SUB(NOW(), INTERVAL '1' HOUR) ===== Idioma ===== ==== Fechas ==== Para que el nombre del día, mes y sus abreviaturas aparezcan en cierto idioma: SET lc_time_names = 'es_ES' SELECT DATE_FORMAT(fecha, '%b') as mes_abreviado FROM tabla Salida: mes_abreviado ------------- nov abr may jun dic El cambio durará hasta que finalice la sesión. Si queremos ver el valor actual de esa variable: SELECT @@lc_time_names; * [[https://dev.mysql.com/doc/refman/8.0/en/locale-support.html|MySQL Server Locale Support]] ===== Extracción de texto ===== ==== E-mail ==== Extraer una dirección de e-mail de un campo de texto: SELECT REGEXP_SUBSTR(campo_texto, '([a-zA-Z0-9._%+\-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,4})') as email FROM tabla ==== Eliminar saltos de línea ==== Si tenemos algún campo con saltos de línea (''\n'' en sistemas UNIX y ''\r\n'' en Windows), podemos borrarlos con: UPDATE test SET log = REPLACE(REPLACE(log, '\r', ''), '\n', ''); ==== Concatenar campos que pueden ser NULL ==== Si usamos la función ''CONCAT'' y algún campo puede tener valor NULL, la función devolverá NULL. Si este no es el comportamiento que queremos, debemos usar ''CONCAT_WS'' cuyo primer argumento es el separador: SELECT CONCAT_WS(" ", campo1, campo2, campo3_que_puede_tener_null, campo4) FROM tabla CONCAT_WS viene de //Concatenate With Separator//. * [[https://es.stackoverflow.com/questions/86721/usar-concat-o-concat-ws-en-mysql|¿Usar CONCAT o CONCAT_WS en MySQL?]] ===== Sistema ===== ==== Tamaño bases de datos ==== SELECT table_schema "Base de datos", ROUND(SUM(data_length + index_length) / 1024 / 1024, 1) "Tamaño (MB)" FROM information_schema.tables GROUP BY table_schema ===== Usuarios ===== ==== Crear usuario ==== CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password'; ==== Dar permisos ==== GRANT ALL PRIVILEGES ON base_datos.tabla TO 'newuser'@'localhost'; FLUSH PRIVILEGES; ==== Mostrar usuarios ==== SELECT user, host FROM mysql.user; ===== Modificaciones ===== ==== Último ID insertado ==== Si hacemos una inserción/modificación en una tabla donde una columna tiene el atributo ''AUTO_INCREMENT'', podemos utilizar la función ''mysqli_insert_id()'' para obtener el ID generado por la consulta de inserción/modificación: (...) $query = "INSERT INTO myCity VALUES (NULL, 'Stuttgart', 'DEU', 'Stuttgart', 617000)"; mysqli_query($link, $query); printf ("Nuevo registro con el id %d.\n", mysqli_insert_id($link)); ==== Modificar valor inicial AUTO_INCREMENT ==== Si queremos establecer un valor para la clave que contiene AUTO_INCREMENT: ALTER TABLE mitabla AUTO_INCREMENT=1001; En las próximas inserciones, la columna con AUTO_INCREMENT se rellenará desde 1001 y siguientes. ==== Insertar varios registros a la vez ==== INSERT INTO nombre_tabla (a,b,c) VALUES (1,2,3), (4,5,6), (7,8,9); ===== Tablas ===== ==== Duplicar tabla ==== Para duplicar una tabla a partir de otra (conservando índices y estructura) se hace en dos consultas pasos: primero haremos crearemos una tabla a partir de la que nos interesa copiar: CREATE TABLE tabla_copia LIKE tabla_origen Y ahora añadimos todo lo que había en la tabla origen a su copia: INSERT INTO tabla_copia SELECT * FROM tabla_origen ==== Modificar una tabla con valores de otra tabla ==== UPDATE tabla_a_actualizar INNER JOIN tabla_de_la_que_copiar ON (tabla_a_actualizar.valor = tabla_de_la_que_copiar.valor) SET tabla_a_actualizar.campo1 = tabla_de_la_que_copiar.campo1 * [[https://stackoverflow.com/questions/5727827/update-one-mysql-table-with-values-from-another|Update one MySQL table with values from another]] (Stack Overflow) ==== Listar tablas de una base de datos ==== SELECT table_name FROM information_schema.tables WHERE table_schema = '' ==== Eliminar tabla ==== DROP TABLE IF EXISTS Si queremos eliminar más de una a la vez: DROP TABLE IF EXISTS , , ==== Obtener nombre columnas ==== Para ver el listado de campos de una tabla y su tipo: DESCRIBE Si queremos obtener el listado de campos separados por coma: -- Aumentamos la longitud máxima de 'group_concat' (por defecto, 1024 caracteres) -- Esto solo se mantiene durante la sesión SET SESSION group_concat_max_len = 1000000; SELECT group_concat(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '' AND TABLE_NAME = ''; * [[https://stackoverflow.com/a/1526722|Get table column names in MySQL?]] ===== Administración ===== ==== Mostrar lista de procesos ==== show full processlist; Ejemplo de salida: +---------+-----------+-------------------+-----------------------+---------+------+-------+-----------------------+ | Id | User | Host | db | Command | Time | State | Info | +---------+-----------+-------------------+-----------------------+---------+------+-------+-----------------------+ | 1195431 | postventa | 10.0.42.185:52702 | tiempos_provision_krt | Sleep | 3559 | | NULL | | 1195818 | postventa | localhost | NULL | Query | 0 | init | show full processlist | +---------+-----------+-------------------+-----------------------+---------+------+-------+-----------------------+ ==== Detener un proceso ==== Primero buscamos los procesos en ejecución: SHOW PROCESSLIST; Y luego, cuando tengamos identificada la ID del proceso que nos interesa, lo detenemos: KILL ===== Eventos ===== * [[https://codigofacilito.com/articulos/eventos-mysql|Eventos MySQL]] ==== Crear ==== Ejemplo de evento que elimina registros distintos de la fecha actual diariamente a las 00:01: CREATE EVENT `eliminar_antiguas_tabla_incidencias_hoy` ON SCHEDULE EVERY 1 DAY STARTS (TIMESTAMP(CURRENT_DATE) + INTERVAL 1 DAY + INTERVAL 1 MINUTE) ON COMPLETION PRESERVE ENABLE COMMENT 'Elimina incidencias antiguas de la tabla que guarda incidencias del día en curso' DO DELETE FROM qep_tbook.incidencias_hoy WHERE DATE_FORMAT(fecha_creacion, '%Y-%m-%d') <> CURDATE() ==== Mostrar ==== Todos los eventos: SHOW EVENTS; ==== Deshabilitar ==== ALTER EVENT DISABLE ==== Eliminar ==== DROP EVENT ==== Última ejecución ==== Mostrar los eventos y la última vez que se ejecutaron: SELECT EVENT_NAME, INTERVAL_VALUE, INTERVAL_FIELD, LAST_EXECUTED FROM INFORMATION_SCHEMA.events ==== Programador de eventos ==== Activar: SET GLOBAL event_scheduler = ON; Desactivar: SET GLOBAL event_scheduler = OFF; Consultar estado: SHOW VARIABLES WHERE VARIABLE_NAME = 'event_scheduler'