validar repitan repetir registros que evitar duplicados datos consulta php sql mysql

php - repitan - ¿Cómo verificar si ya existe un valor para evitar duplicados?



no repetir registros en consulta sql (17)

¿Le preocupan exclusivamente las URL que son exactamente la misma cadena? En caso afirmativo, hay muchos consejos útiles en otras respuestas. ¿O también tienes que preocuparte por la canonización?

Por ejemplo: http://google.com y http: //go%4fgle.com son exactamente la misma URL, pero se permiten como duplicados por cualquiera de las técnicas de solo base de datos. Si esto es un problema, debe preprocesar las URL para resolver y las secuencias de escape de caracteres.

Dependiendo de dónde provengan las URL, también tendrá que preocuparse por los parámetros y si son importantes en su aplicación.

Tengo una tabla de URL y no quiero ninguna URL duplicada. ¿Cómo verifico si una URL dada ya está en la tabla usando PHP / MySQL?


Para garantizar la exclusividad, debe agregar una restricción única. Suponiendo que el nombre de su tabla es "urls" y el nombre de la columna es "url", puede agregar la restricción única con este comando alter table:

alter table urls add constraint unique_url unique (url);

La tabla alter probablemente fallará (quién realmente sabe con MySQL) si ya tienes URL duplicadas en tu tabla.


Si no desea tener duplicados, puede hacer lo siguiente:

Si múltiples usuarios pueden insertar datos en DB, el método sugerido por @Jeremy Ruten, puede llevar a un error : después de realizar un control, alguien puede insertar datos similares en la tabla.


Si solo quiere asegurarse de que no hay duplicados, agregue un índice único al campo de la url, de esa manera no hay necesidad de verificar explícitamente si la url existe, solo inserte como es normal, y si ya está allí, la inserción se realizará. fallar con un error de clave duplicado.


Si solo quieres una respuesta de sí o no, esta sintaxis debería darte el mejor rendimiento.

select if(exists (select url from urls where url = ''http://asdf.com''), 1, 0) from dual


Usted puede hacer esta consulta:

SELECT url FROM urls WHERE url = ''http://asdf.com'' LIMIT 1

Luego, compruebe si mysql_num_rows () == 1 para ver si existe.


no conozco la sintaxis de MySQL, pero todo lo que tiene que hacer es ajustar su INSERT con la instrucción IF que consultará la tabla y verá si el registro con la URL dada EXISTE, si existe, no inserte un nuevo registro.

si MSSQL puede hacer esto:

IF NOT EXISTS (SELECT 1 FROM YOURTABLE WHERE URL = ''URL'') INSERT INTO YOURTABLE (...) VALUES (...)


La respuesta depende de si desea saber cuándo se realiza un intento para ingresar un registro con un campo duplicado. Si no te importa, utiliza la sintaxis "INSERTAR ... EN LA CLAVE DUPLICADA", ya que esto hará que tu intento sea exitoso sin crear un duplicado.

Si, por otro lado, desea saber cuándo ocurre un evento de ese tipo y evitarlo, debe usar una restricción de clave única que hará que el intento de inserción / actualización falle con un error significativo.


Si desea insertar URL en la tabla, pero solo aquellas que ya no existen, puede agregar un CONTRASEÑO ÚNICO en la columna y en su consulta INSERTAR, agregue IGNORRO para que no obtenga un error.

Ejemplo: INSERT IGNORE INTO urls SET url = ''url-to-insert''


$url = "http://www.scroogle.com"; $query = "SELECT `id` FROM `urls` WHERE `url` = ''$url'' "; $resultdb = mysql_query($query) or die(mysql_error()); list($idtemp) = mysql_fetch_array($resultdb) ; if(empty($idtemp)) // if $idtemp is empty the url doesn''t exist and we go ahead and insert it into the db. { mysql_query("INSERT INTO urls (`url` ) VALUES(''$url'') ") or die (mysql_error()); }else{ //do something else if the url already exists in the DB }


Convierta la columna en la primary key


Para responder a su pregunta inicial, la manera más fácil de verificar si hay un duplicado es ejecutar una consulta SQL en comparación con lo que está intentando agregar.

Por ejemplo, si desea consultar la URL http://www.example.com/ en los links la tabla, su consulta se vería como

SELECT * FROM links WHERE url = ''http://www.example.com/'';

Su código PHP se vería como

$conn = mysql_connect(''localhost'', ''username'', ''password''); if (!$conn) { die(''Could not connect to database''); } if(!mysql_select_db(''mydb'', $conn)) { die(''Could not select database mydb''); } $result = mysql_query("SELECT * FROM links WHERE url = ''http://www.example.com/''", $conn); if (!$result) { die(''There was a problem executing the query''); } $number_of_rows = mysql_num_rows($result); if ($number_of_rows > 0) { die(''This URL already exists in the database''); }

Lo he escrito aquí a mano, con todas las conexiones a la base de datos, etc. Es probable que ya tenga una conexión a una base de datos, por lo que debe usar eso en lugar de comenzar una nueva conexión (reemplace $conn en mysql_query command y eliminar las cosas que hacer con mysql_connect y mysql_select_db )

Por supuesto, hay otras maneras de conectarse a la base de datos, como PDO, o usar un ORM, o similar, por lo que si ya los está utilizando, esta respuesta puede no ser relevante (y probablemente sea un poco más allá del alcance de dar respuestas relacionadas con esto aquí!)

Sin embargo, MySQL ofrece muchas maneras de evitar que esto suceda en primer lugar.

En primer lugar, puede marcar un campo como "único".

Digamos que tengo una tabla en la que quiero almacenar todas las URL a las que se vinculó desde mi sitio y la última vez que fueron visitadas.

Mi definición podría verse más o menos así:

CREATE TABLE links ( url VARCHAR(255) NOT NULL, last_visited TIMESTAMP )

Esto me permitiría agregar la misma URL una y otra vez, a menos que escribiera algún código PHP similar al anterior para evitar que esto suceda.

Sin embargo, si mi definición cambiara a

CREATE TABLE links ( url VARCHAR(255) NOT NULL, last_visited TIMESTAMP, PRIMARY KEY (url) )

Entonces esto haría que mysql arrojara un error cuando intenté insertar el mismo valor dos veces.

Un ejemplo en PHP sería

$result = mysql_query("INSERT INTO links (url, last_visited) VALUES (''http://www.example.com/'', NOW()", $conn); if (!$result) { die(''Could not Insert Row 1''); } $result2 = mysql_query("INSERT INTO links (url, last_visited) VALUES (''http://www.example.com/'', NOW()", $conn); if (!$result2) { die(''Could not Insert Row 2''); }

Si ejecutó esto, encontraría que en el primer intento, el script moriría con el comentario Could not Insert Row 2 . Sin embargo, en ejecuciones posteriores, moriría con Could not Insert Row 1 .

Esto se debe a que MySQL sabe que la url es la clave principal de la tabla. Una clave principal es un identificador único para esa fila. La mayoría de las veces, es útil establecer el identificador único para una fila como un número. Esto es porque MySQL es más rápido buscando números que buscando texto. Dentro de MySQL, las claves (y especialmente las teclas principales) se utilizan para definir relaciones entre dos tablas. Por ejemplo, si tuviéramos una tabla para usuarios, podríamos definirla como

CREATE TABLE users ( username VARCHAR(255) NOT NULL, password VARCHAR(40) NOT NULL, PRIMARY KEY (username) )

Sin embargo, cuando queríamos almacenar información sobre una publicación que el usuario había hecho, debíamos almacenar el nombre de usuario con esa publicación para identificar que la publicación pertenecía a ese usuario.

Ya he mencionado que MySQL es más rápido en la búsqueda de números que de cadenas, por lo que esto significaría que pasaríamos el tiempo buscando secuencias cuando no era necesario.

Para solucionar esto, podemos agregar una columna adicional, user_id, y hacer que la clave principal (por lo que al buscar el registro del usuario en función de una publicación, podemos encontrarlo más rápido)

CREATE TABLE users ( user_id INT(10) NOT NULL AUTO_INCREMENT, username VARCHAR(255) NOT NULL, password VARCHAR(40) NOT NULL, PRIMARY KEY (`user_id`) )

Notarás que también he agregado algo nuevo aquí: AUTO_INCREMENT. Esto básicamente nos permite dejar que ese campo se cuide a sí mismo. Cada vez que se inserta una nueva fila, agrega 1 al número anterior y la almacena, para que no tengamos que preocuparnos por la numeración, y podemos dejar que lo haga solo.

Entonces, con la tabla anterior, podemos hacer algo como

INSERT INTO users (username, password) VALUES(''Mez'', ''d3571ce95af4dc281f142add33384abc5e574671'');

y entonces

INSERT INTO users (username, password) VALUES(''User'', ''988881adc9fc3655077dc2d4d757d480b5ea0e11'');

Cuando seleccionamos los registros de la base de datos, obtenemos lo siguiente:

mysql> SELECT * FROM users; +---------+----------+------------------------------------------+ | user_id | username | password | +---------+----------+------------------------------------------+ | 1 | Mez | d3571ce95af4dc281f142add33384abc5e574671 | | 2 | User | 988881adc9fc3655077dc2d4d757d480b5ea0e11 | +---------+----------+------------------------------------------+ 2 rows in set (0.00 sec)

Sin embargo, aquí tenemos un problema: ¡aún podemos agregar otro usuario con el mismo nombre de usuario! ¡Obviamente, esto es algo que no queremos hacer!

mysql> SELECT * FROM users; +---------+----------+------------------------------------------+ | user_id | username | password | +---------+----------+------------------------------------------+ | 1 | Mez | d3571ce95af4dc281f142add33384abc5e574671 | | 2 | User | 988881adc9fc3655077dc2d4d757d480b5ea0e11 | | 3 | Mez | d3571ce95af4dc281f142add33384abc5e574671 | +---------+----------+------------------------------------------+ 3 rows in set (0.00 sec)

Vamos a cambiar nuestra definición de mesa!

CREATE TABLE users ( user_id INT(10) NOT NULL AUTO_INCREMENT, username VARCHAR(255) NOT NULL, password VARCHAR(40) NOT NULL, PRIMARY KEY (user_id), UNIQUE KEY (username) )

Veamos qué ocurre cuando intentamos insertar el mismo usuario dos veces.

mysql> INSERT INTO users (username, password) VALUES(''Mez'', ''d3571ce95af4dc281f142add33384abc5e574671''); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO users (username, password) VALUES(''Mez'', ''d3571ce95af4dc281f142add33384abc5e574671''); ERROR 1062 (23000): Duplicate entry ''Mez'' for key ''username''

¡¡¡Hurra !! Ahora obtenemos un error cuando intentamos insertar el nombre de usuario por segunda vez. Usando algo como el anterior, podemos detectar esto en PHP.

Ahora, regresemos a nuestra tabla de enlaces, pero con una nueva definición.

CREATE TABLE links ( link_id INT(10) NOT NULL AUTO_INCREMENT, url VARCHAR(255) NOT NULL, last_visited TIMESTAMP, PRIMARY KEY (link_id), UNIQUE KEY (url) )

e insertemos "http://www.example.com" en la base de datos.

INSERT INTO links (url, last_visited) VALUES (''http://www.example.com/'', NOW());

Si intentamos insertarlo de nuevo ...

ERROR 1062 (23000): Duplicate entry ''http://www.example.com/'' for key ''url''

Pero, ¿qué ocurre si queremos actualizar la hora de la última visita?

Bueno, podríamos hacer algo complejo con PHP, así:

$result = mysql_query("SELECT * FROM links WHERE url = ''http://www.example.com/''", $conn); if (!$result) { die(''There was a problem executing the query''); } $number_of_rows = mysql_num_rows($result); if ($number_of_rows > 0) { $result = mysql_query("UPDATE links SET last_visited = NOW() WHERE url = ''http://www.example.com/''", $conn); if (!$result) { die(''There was a problem updating the links table''); } }

O, incluso, tome la identificación de la fila en la base de datos y úselo para actualizarla.

$ result = mysql_query ("SELECT * FROM links WHERE url = ''http://www.example.com/''", $ conn);

if (!$result) { die(''There was a problem executing the query''); } $number_of_rows = mysql_num_rows($result); if ($number_of_rows > 0) { $row = mysql_fetch_assoc($result); $result = mysql_query(''UPDATE links SET last_visited = NOW() WHERE link_id = '' . intval($row[''link_id''], $conn); if (!$result) { die(''There was a problem updating the links table''); } }

Pero, MySQL tiene una característica incorporada agradable llamada REPLACE INTO

Vamos a ver cómo funciona.

mysql> SELECT * FROM links; +---------+-------------------------+---------------------+ | link_id | url | last_visited | +---------+-------------------------+---------------------+ | 1 | http://www.example.com/ | 2011-08-19 23:48:03 | +---------+-------------------------+---------------------+ 1 row in set (0.00 sec) mysql> INSERT INTO links (url, last_visited) VALUES (''http://www.example.com/'', NOW()); ERROR 1062 (23000): Duplicate entry ''http://www.example.com/'' for key ''url'' mysql> REPLACE INTO links (url, last_visited) VALUES (''http://www.example.com/'', NOW()); Query OK, 2 rows affected (0.00 sec) mysql> SELECT * FROM links; +---------+-------------------------+---------------------+ | link_id | url | last_visited | +---------+-------------------------+---------------------+ | 2 | http://www.example.com/ | 2011-08-19 23:55:55 | +---------+-------------------------+---------------------+ 1 row in set (0.00 sec)

Tenga en cuenta que al usar REPLACE INTO , se actualiza la última vez que se visitó y no se genera un error.

Esto se debe a que MySQL detecta que está intentando reemplazar una fila. Conoce la fila que desea, ya que ha establecido que la URL sea única. MySQL calcula la fila para reemplazar utilizando el bit que pasó en que debe ser único (en este caso, la url) y actualizar para esa fila los otros valores. También se actualizó el link_id - ¡que es un poco inesperado! (De hecho, ¡no me di cuenta de que esto sucedería hasta que lo viera suceder!)

Pero, ¿y si quisieras agregar una nueva URL? ¡Bien, REPLACE INTO estará feliz de insertar una nueva fila si no puede encontrar una fila única que coincida!

mysql> REPLACE INTO links (url, last_visited) VALUES (''http://www..com/'', NOW()); Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM links; +---------+-------------------------------+---------------------+ | link_id | url | last_visited | +---------+-------------------------------+---------------------+ | 2 | http://www.example.com/ | 2011-08-20 00:00:07 | | 3 | http://www..com/ | 2011-08-20 00:01:22 | +---------+-------------------------------+---------------------+ 2 rows in set (0.00 sec)

Espero que esto responda a su pregunta y le brinde un poco más de información sobre cómo funciona MySQL.


Puede ubicar (y eliminar) usando una auto-unión. Su tabla tiene alguna URL y también PK (Sabemos que la PK no es la URL porque de lo contrario no se le permitiría tener duplicados)

SELECT * FROM yourTable a JOIN yourTable b -- Join the same table ON b.[URL] = a.[URL] -- where the URL''s match AND b.[PK] <> b.[PK] -- but the PK''s are different

Esto devolverá todas las filas que tienen URL duplicadas.

Sin embargo, digamos que solo quería seleccionar los duplicados y excluir el original ... Bueno, tendría que decidir qué constituye el original. A los efectos de esta respuesta, supongamos que el PK más bajo es el "original"

Todo lo que necesita hacer es agregar la siguiente cláusula a la consulta anterior:

WHERE a.[PK] NOT IN ( SELECT TOP 1 c.[PK] -- Only grabbing the original! FROM yourTable c WHERE c.[URL] = a.[URL] -- has the same URL ORDER BY c.[PK] ASC) -- sort it by whatever your criterion is for "original"

Ahora tiene un conjunto de todas las filas duplicadas no originales. Puede ejecutar fácilmente un DELETE o lo que quiera de este conjunto de resultados.

Tenga en cuenta que este enfoque puede ser ineficiente, en parte porque mySQL no siempre maneja bien IN pero entiendo por OP que esto es una especie de "limpieza" sobre la mesa, no siempre una verificación.

Si desea comprobar en la hora de INSERT si ya existe un valor, puede ejecutar algo como esto

SELECT 1 WHERE EXISTS (SELECT * FROM yourTable WHERE [URL] = ''testValue'')

Si obtienes un resultado, entonces puedes concluir que el valor ya existe en tu DB al menos una vez.


Lo primero es lo primero. Si aún no ha creado la tabla, o si creó una tabla pero no tiene datos, entonces necesita agregar un constriant único o un índice único. Más información sobre elegir entre índice o restricciones sigue al final de la publicación. Pero ambos logran lo mismo, imponiendo que la columna solo contenga valores únicos.

Para crear una tabla con un índice único en esta columna, puede usar.

CREATE TABLE MyURLTable( ID INTEGER NOT NULL AUTO_INCREMENT ,URL VARCHAR(512) ,PRIMARY KEY(ID) ,UNIQUE INDEX IDX_URL(URL) );

Si solo quiere una restricción única, y ningún índice en esa tabla, puede usar

CREATE TABLE MyURLTable( ID INTEGER NOT NULL AUTO_INCREMENT ,URL VARCHAR(512) ,PRIMARY KEY(ID) ,CONSTRAINT UNIQUE UNIQUE_URL(URL) );

Ahora, si ya tiene una tabla, y no hay datos en ella, puede agregar el índice o la restricción a la tabla con uno de los siguientes fragmentos de código.

ALTER TABLE MyURLTable ADD UNIQUE INDEX IDX_URL(URL); ALTER TABLE MyURLTable ADD CONSTRAINT UNIQUE UNIQUE_URL(URL);

Ahora, es posible que ya tenga una tabla con algunos datos. En ese caso, es posible que ya tenga algunos datos duplicados. Puede intentar crear el compilador o índice que se muestra arriba, y fallará si ya tiene datos duplicados. Si no tiene datos duplicados, genial, si lo hace, tendrá que eliminar los duplicados. Puedes ver un litro de URL con duplicados usando la siguiente consulta.

SELECT URL,COUNT(*),MIN(ID) FROM MyURLTable GROUP BY URL HAVING COUNT(*) > 1;

Para eliminar filas que son duplicadas, y mantener una, haga lo siguiente:

DELETE RemoveRecords FROM MyURLTable As RemoveRecords LEFT JOIN ( SELECT MIN(ID) AS ID FROM MyURLTable GROUP BY URL HAVING COUNT(*) > 1 UNION SELECT ID FROM MyURLTable GROUP BY URL HAVING COUNT(*) = 1 ) AS KeepRecords ON RemoveRecords.ID = KeepRecords.ID WHERE KeepRecords.ID IS NULL;

Ahora que ha eliminado todos los registros, puede continuar y crear su índice o restricción. Ahora, si desea insertar un valor en su base de datos, debe usar algo como.

INSERT IGNORE INTO MyURLTable(URL) VALUES(''http://www.example.com'');

Eso intentará hacer la inserción, y si encuentra un duplicado, no pasará nada. Ahora, digamos que tiene otras columnas, puede hacer algo como esto.

INSERT INTO MyURLTable(URL,Visits) VALUES(''http://www.example.com'',1) ON DUPLICATE KEY UPDATE Visits=Visits+1;

Eso buscará insertar el valor, y si encuentra la URL, actualizará el registro al incrementar el contador de visitas. Por supuesto, siempre puedes hacer un simple inserto antiguo y manejar el error resultante en tu código PHP. Ahora, si debe o no usar restricciones o índices, eso depende de muchos factores. Los índices hacen que las búsquedas sean más rápidas, por lo que su rendimiento será mejor a medida que la tabla aumente, pero almacenar el índice ocupará más espacio. Los índices también suelen hacer que las inserciones y actualizaciones tarden más, porque tienen que actualizar el índice. Sin embargo, dado que el valor tendrá que buscarse de cualquier manera, para hacer cumplir la unicidad, en este caso, puede ser más rápido tener el índice de todos modos. En cuanto a todo lo relacionado con el rendimiento, la respuesta es probar ambas opciones y perfilar los resultados para ver cuál funciona mejor para su situación.


Primero, prepara la base de datos .

  • Los nombres de dominio no distinguen entre mayúsculas y minúsculas, pero debe suponer que el resto de una URL sí lo es. (No todos los servidores web respetan el caso en las URL, pero la mayoría lo hace, y no se puede ver fácilmente al mirar).
  • Suponiendo que necesita almacenar más que un nombre de dominio, use una intercalación que distinga entre mayúsculas y minúsculas.
  • Si decide almacenar la URL en dos columnas, una para el nombre de dominio y otra para el localizador de recursos, considere usar una intercalación que no distinga entre mayúsculas y minúsculas para el nombre de dominio y una intercalación de mayúsculas y minúsculas para el localizador de recursos. Si yo fuera tú, probaría en ambos sentidos (URL en una columna vs. URL en dos columnas).
  • Ponga una restricción ÚNICA en la columna URL. O en el par de columnas, si almacena el nombre de dominio y el localizador de recursos en columnas separadas, como UNIQUE (url, resource_locator) .
  • Use una restricción CHECK () para mantener las URL codificadas fuera de la base de datos. Esta restricción CHECK () es esencial para evitar que ingresen datos incorrectos a través de una copia masiva o mediante el shell de SQL.

Segundo, prepare la URL .

  • Los nombres de dominio no distinguen entre mayúsculas y minúsculas. Si almacena la URL completa en una columna, ponga el nombre de dominio en minúscula en todas las URL. Pero tenga en cuenta que algunos idiomas tienen letras mayúsculas que no tienen un equivalente en minúsculas.
  • Piense en recortar los caracteres finales. Por ejemplo, estas dos URL de amazon.com apuntan al mismo producto. Probablemente desee almacenar la segunda versión, no la primera.

    http://www.amazon.com/Systemantics-Systems-Work-Especially-They/dp/070450331X/ref=sr_1_1?ie=UTF8&qid=1313583998&sr=8-1

    http://www.amazon.com/Systemantics-Systems-Work-Especially-They/dp/070450331X

  • Descodificar URL codificadas (Consulte la función urldecode () de php . Observe cuidadosamente sus deficiencias, tal como se describe en los comentarios de esa página). Personalmente, preferiría manejar este tipo de transformaciones en la base de datos en lugar de en el código del cliente. Eso implicaría revocar permisos en las tablas y vistas, y permitir inserciones y actualizaciones solo a través de procedimientos almacenados; los procedimientos almacenados manejan todas las operaciones de cadena que ponen la URL en una forma canónica. Pero fíjate en el rendimiento cuando lo intentes. Las restricciones CHECK () (ver arriba) son su red de seguridad.

En tercer lugar , si está insertando solo la URL, primero no pruebe su existencia . En su lugar, intente insertar y atrapar el error que obtendrá si el valor ya existe. Las pruebas y las inserciones golpean la base de datos dos veces por cada nueva URL. Insertar y atrapar solo golpea la base de datos una vez. Observe cuidadosamente que insert-and-trap no es lo mismo que insert-and-ignore-errors. Solo un error en particular significa que violó la restricción única; otros errores significan que hay otros problemas.

Por otro lado, si está insertando la URL junto con otros datos en la misma fila, debe decidir de antemano si manejará direcciones URL duplicadas

REPLACE elimina la necesidad de atrapar errores clave duplicados, pero puede tener efectos secundarios desafortunados si hay referencias de claves externas.


Al considerar una solución a este problema, primero debe definir qué significa una "URL duplicada" para su proyecto. Esto determinará cómo canonicalizar las URL antes de agregarlas a la base de datos.

Hay al menos dos definiciones:

  1. Dos URL se consideran duplicadas si representan el mismo recurso sin saber nada sobre el servicio web correspondiente que genera el contenido correspondiente. Algunas consideraciones incluyen:
    • El esquema y la porción del nombre de dominio de las URL no distinguen entre mayúsculas y minúsculas, por lo que HTTP://WWW..COM/ es el mismo que http://www..com/ .
    • Si una URL especifica un puerto, pero es el puerto convencional para el esquema y son equivalentes, entonces son iguales ( http://www..com/ y http://www..com:80 / ).
    • Si los parámetros en la cadena de consulta son reordenamientos simples y los nombres de los parámetros son todos diferentes, entonces son los mismos; por ejemplo, http: // authority /? a = test & b = test y http: // authority /? b = test & a = test . Tenga en cuenta que http: // authority /? A% 5B% 5D = test1 & a% 5B% 5D = test2 no es lo mismo, según esta primera definición de sameness, como http: // authority /? A% 5B% 5D = test2 & a% 5B% 5D = prueba1 .
    • Si el esquema es HTTP o HTTPS, las partes hash de las URL se pueden eliminar, ya que esta parte de la URL no se envía al servidor web.
    • Se puede expandir una dirección IPv6 acortada.
    • Agregue una barra inclinada hacia adelante a la autoridad solo si falta.
    • La canonicalización de Unicode cambia el recurso al que se hace referencia; por ejemplo, no puede concluir que http://google.com/?q=%C3%84 ( %C3%84 representa ''Ä'' en UTF-8) es lo mismo que http://google.com/?q = A% CC% 88 ( %CC%88 representa U + 0308, COMBINACIÓN DE DIAESIS).
    • Si el esquema es HTTP o HTTPS, '' www. ''en la autoridad de una URL no se puede eliminar simplemente si las dos URL son equivalentes, ya que el texto del nombre de dominio se envía como el valor del encabezado HTTP del Host , y algunos servidores web utilizan hosts virtuales para enviar contenido diferente en función de este encabezado En términos más generales, incluso si los nombres de dominio se resuelven en la misma dirección IP, no puede concluir que los recursos a los que se hace referencia son los mismos.
  2. Aplicar canonicalización de URL básica (por ejemplo, minúsculas, esquema y nombre de dominio, suministrar el puerto predeterminado, parámetros de consulta de ordenación estables por nombre de parámetro, eliminar la porción de hash en el caso de HTTP y HTTPS, ...), y tener en cuenta el conocimiento de el servicio web. Tal vez suponga que todos los servicios web son lo suficientemente inteligentes como para canonicalizar la entrada Unicode (Wikipedia es, por ejemplo), por lo que puede aplicar la Composición Canonical (NFC) del Formulario de Normalización Unicode . Usted se desnudaría '' www. ''desde todas las URL de desbordamiento de pila. Podrías usar el código postrank-uri de PostRank , portado a PHP, para eliminar todo tipo de fragmentos de las URL innecesarias (por ejemplo, &utm_source=... ).

La definición 1 conduce a una solución estable (es decir, no se puede realizar una canonización adicional y la canonización de una URL no cambiará). La definición 2, que creo que es lo que un humano considera la definición de canonicalización de URL, conduce a una rutina de canonización que puede producir diferentes resultados en diferentes momentos en el tiempo.

Cualquiera que sea la definición que elijas, te sugiero que uses columnas separadas para las partes del esquema, inicio de sesión, host, puerto y ruta. Esto le permitirá usar índices inteligentemente. Las columnas para el esquema y el host pueden usar una intercalación de caracteres (todas las intercalaciones de caracteres no distinguen entre mayúsculas y minúsculas en MySQL), pero las columnas para el inicio de sesión y la ruta necesitan usar una intercalación binaria que no distinga entre mayúsculas y minúsculas. Además, si utiliza la Definición 2, debe conservar el esquema original, la autoridad y las partes de ruta, ya que ciertas reglas de canonización pueden agregarse o eliminarse de vez en cuando.

EDITAR: Aquí hay definiciones de tabla de ejemplo:

CREATE TABLE `urls1` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `scheme` VARCHAR(20) NOT NULL, `canonical_login` VARCHAR(100) DEFAULT NULL COLLATE ''utf8mb4_bin'', `canonical_host` VARCHAR(100) NOT NULL COLLATE ''utf8mb4_unicode_ci'', /* the "ci" stands for case-insensitive. Also, we want ''utf8mb4_unicode_ci'' rather than ''utf8mb4_general_ci'' because ''utf8mb4_general_ci'' treats accented characters as equivalent. */ `port` INT UNSIGNED, `canonical_path` VARCHAR(4096) NOT NULL COLLATE ''utf8mb4_bin'', PRIMARY KEY (`id`), INDEX (`canonical_host`(10), `scheme`) ) ENGINE = ''InnoDB''; CREATE TABLE `urls2` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `canonical_scheme` VARCHAR(20) NOT NULL, `canonical_login` VARCHAR(100) DEFAULT NULL COLLATE ''utf8mb4_bin'', `canonical_host` VARCHAR(100) NOT NULL COLLATE ''utf8mb4_unicode_ci'', `port` INT UNSIGNED, `canonical_path` VARCHAR(4096) NOT NULL COLLATE ''utf8mb4_bin'', `orig_scheme` VARCHAR(20) NOT NULL, `orig_login` VARCHAR(100) DEFAULT NULL COLLATE ''utf8mb4_bin'', `orig_host` VARCHAR(100) NOT NULL COLLATE ''utf8mb4_unicode_ci'', `orig_path` VARCHAR(4096) NOT NULL COLLATE ''utf8mb4_bin'', PRIMARY KEY (`id`), INDEX (`canonical_host`(10), `canonical_scheme`), INDEX (`orig_host`(10), `orig_scheme`) ) ENGINE = ''InnoDB'';

La tabla `urls1` es para almacenar URLs canónicas de acuerdo con la definición 1. La tabla` urls2` es para almacenar URLs canónicas de acuerdo con la definición 2.

Desafortunadamente no podrá especificar una restricción UNIQUE en la tupla (`scheme` /` canonical_scheme`, `canonical_login`,` canonical_host`, `port`,` canonical_path`) ya que MySQL limita la longitud de las teclas InnoDB a 767 bytes .


Las soluciones SQL simples requieren un campo único; las soluciones lógicas no.

Debe normalizar sus URL para asegurarse de que no haya duplicaciones. Funciones en PHP como strtolower () y urldecode () o rawurldecode () .

Suposiciones: el nombre de su tabla es ''sitios web'', el nombre de la columna de su url es ''url'' y los datos arbitrarios que se asociarán con la url se encuentran en la columna ''datos''.

Soluciones lógicas

SELECT COUNT(*) AS UrlResults FROM websites WHERE url=''http://www.domain.com''

Pruebe la consulta anterior con sentencias if en SQL o PHP para asegurarse de que sea 0 antes de continuar con una instrucción INSERT.

Declaraciones SQL simples

Escenario 1: su base de datos es la que llega primero y no desea tener entradas duplicadas en el futuro.

ALTER TABLE websites ADD UNIQUE (url)

Esto evitará que cualquier entrada se pueda ingresar a la base de datos si el valor de la URL ya existe en esa columna.

Escenario 2: desea la información más actualizada para cada url y no desea duplicar el contenido. Hay dos soluciones para este escenario. (Estas soluciones también requieren que ''url'' sea único, por lo que la solución en el Escenario 1 también deberá llevarse a cabo).

REPLACE INTO websites (url, data) VALUES (''http://www.domain.com'', ''random data'')

Esto disparará una acción DELETE si existe una fila seguida de un INSERT en todos los casos, así que tenga cuidado con las declaraciones ON DELETE.

INSERT INTO websites (url, data) VALUES (''http://www.domain.com'', ''random data'') ON DUPLICATE KEY UPDATE data=''random data''

Esto disparará una acción ACTUALIZAR si existe una fila y un INSERTAR si no existe.