6

Teniendo una tabla con datos, por ejemplo:

 id        Name        Team                       
=====    =========   =========
  1        Logan       x-men
  2        Storm       x-men
  3        Beast       x-men

Queremos realizar la inserción de las siguientes filas en la tabla:

INSERT INTO contactos
    (id, name, team )
VALUES
    ('4','Logan','x-men'),
    ('5','Picara','x-men');

Como se puede observar 'Logan' ya existe y, por lo tanto, no nos interesa darlo de alta de nuevo. ¿Cómo podría evitar esto?

La verdad es que mis conocimientos de BBDD y SQL son algo limitados, y la verdad es que no he encontrado manera en una sentencia INSERT INTO. ¿Alguien podría darme una pista?

OscarGarcia
  • 26,999
  • 3
  • 26
  • 61
Piliopan
  • 73
  • 3
  • 2
    Basta con hacer el campo clave única para que no te permita agregar repetido un mismo héroe. https://www.db-fiddle.com/f/ct2Nst9nhb1BGwvFqmmANN/0 – OscarGarcia Jan 17 '20 at 10:10

2 Answers2

7

Basta con hacer el campo nameclave única para que no te permita agregar repetido un mismo héroe:

ALTER TABLE contactos
  ADD UNIQUE(name);

A partir de ese momento cualquier intento de agregar un nombre repetido será cancelado con un mensaje de error:

Error: ER_DUP_ENTRY: Duplicate entry 'Logan' for key 'name'

Ver ejemplo en línea.

Por cierto: un INSERT insertando múltiples registros fallará completamente si uno de sus elementos genera un error por duplicidad de campo.

Para solucionarlo y permitir que los registros no repetidos se inserten, debes usar el parámetro IGNORE de INSERT:

INSERT IGNORE INTO contactos (
  id, name, team
) VALUES (
  '4','Logan','x-men'
), (
  '5','Picara','x-men'
);
SELECT ROW_COUNT();

Ver ejemplo en línea.

En este caso no se genera ningún error, por lo que la única forma de saber si se produjo una colisión durante la inserción es comprobar que el número de filas afectadas (con ROW_COUNT() por ejemplo) coincide con la cantidad de datos facilitados. En este ejemplo ROW_COUNT() devolverá 1 ya que sólo consigue insertar uno de los dos valores facilitados al INSERT.

OscarGarcia
  • 26,999
  • 3
  • 26
  • 61
  • y por qué no id mejor? – Iria Jan 17 '20 at 10:35
  • 1
    @IriaPoncelaBlanco, lo que consigues haciendo `id` clave única es que no se repita ningún valor de `id`. Lo que el OP quiere conseguir es que no se repita ningún nombre de héroe independientemente del `id` que se le vaya a asignar. – OscarGarcia Jan 17 '20 at 10:36
  • entonces name sería la primary key, pero entonces no entiendo el id, en todos los sitios id es único e identifica la fila, o fuera de las bases de datos y de computación, id suele ser único. El que no lo sea me suena raro, cierto es que no estamos tratando sobre esto pero puede darle otro tipo de problemas. – Iria Jan 17 '20 at 10:40
  • creo que es al contrario, puede simplificarle muchas cosas si en su aplicacion utiliza un orm, ya que este podra localizar por el id los registros y gestionarlos. – Jakala Jan 17 '20 at 10:56
  • 1
    @IriaPoncelaBlanco entiendo perfectamente lo que quieres decir. El problema es que desconocemos el esquema de la base de datos del OP, por lo que no sabemos si `id` ya es una clave primaria y si es o no autoincrementable. Ante tal caso, la necesidad mínima para la solución es una clave única. Solo puede haber una clave primaria por tabla, no puede haber más en una misma tabla, así que si la usa para `id` entonces no se puede usar para otro campo, pero las claves únicas pueden ser tantas como se deseen e incluso involucrar a varios campos. – OscarGarcia Jan 17 '20 at 11:36
  • la clave primaria no tiene por qué ser un único campo, puede ser un subconjunto de campos dentro de la tabla siempre y cuando, su combinación sea única. – Iria Jan 17 '20 at 11:43
  • Bueno, olvida la parte de *"e incluso involucrar a varios campos"*, ambos lo permiten. A lo que quería llegar es a que el **requisito mínimo** para conseguir lo que el OP desea es una clave única y, además, puedes usar tantas como desees por lo que no es incompatible con que exista otra en la tabla. Usar una clave primaria es correcto (porque incluye al mismo tiempo ser único), pero no es realmente necesario ni indispensable que sea `PRIMARY KEY` para que se solucione el problema y, además, si existe ya una (por ejemplo, en `id`) no es posible agregar una segunda para esta solución. – OscarGarcia Jan 17 '20 at 11:48
2

Quizás esta no sea la solución más optima le apostaría a la respuesta de @OscarGarcia, pero tienes una alternativa con la clausula WHERE NOT EXISTS.

Nota: Si el id es autoincremental, no necesitas declararlo en el query.

INSERT INTO contactos (name, team)
SELECT * FROM (SELECT 'Logan', 'x-men') AS tmp
WHERE NOT EXISTS (
    SELECT name FROM contactos WHERE name = 'Logan'
) LIMIT 1;

Como Logan ya existe, el resultado es:

0 filas insertadas. (La consulta tardó 0,0000 segundos.)

Pero, si inserto un personaje que no existe...

INSERT INTO contactos (name, team)
SELECT * FROM (SELECT 'Picara', 'x-men') AS tmp
WHERE NOT EXISTS (
    SELECT name FROM contactos WHERE name = 'Picara'
) LIMIT 1;

El resultado es este:

1 fila insertada. La Id de la fila insertada es: 4 (La consulta tardó 0,0000 segundos.)

DjCrazy
  • 4,786
  • 3
  • 13
  • 33