Как проверить, существует ли уже существующее значение, чтобы избежать дублирования?

У меня есть таблица URL-адресов, и я не хочу дублировать URL-адреса. Как проверить, есть ли данный URL-адрес в таблице с помощью PHP / MySQL?

Если вы не хотите иметь дубликаты, вы можете сделать следующее:

  • добавить ограничение уникальности
  • используйте синтаксис « ЗАМЕНИТЬ » или « ВСТАВИТЬ … НА ПОДКЛЮЧЕНИЕ КЛЮЧА КЛЮЧА »

Если несколько пользователей могут вставлять данные в БД, метод, предложенный @Jeremy Ruten, может привести к ошибке : после выполнения проверки кто-то может вставить аналогичные данные в таблицу.

Чтобы ответить на ваш первоначальный вопрос, самый простой способ проверить, есть ли дубликат, – запустить SQL-запрос против того, что вы пытаетесь добавить!

Например, хотите ли вы проверить URL-адрес http://www.example.com/ в links на таблицу, тогда ваш запрос будет выглядеть примерно так:

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

Ваш PHP-код будет выглядеть примерно так:

 $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'); } 

Я написал это здесь, со всем подключением к базе данных и т. Д. Вероятно, у вас уже будет соединение с базой данных, поэтому вы должны использовать это вместо того, чтобы начинать новое соединение (замените $conn на mysql_query и удалите материал, который нужно использовать с mysql_connect и mysql_select_db )

Конечно, есть и другие способы подключения к базе данных, такие как PDO или ORM или аналогичные, поэтому, если вы уже используете их, этот ответ может быть неактуальным (и это, вероятно, немного выходит за рамки, чтобы дать ответы, связанные с этим здесь!)

Однако MySQL предоставляет множество способов предотвратить это в первую очередь.

Во-первых, вы можете пометить поле как «уникальное».

Допустим, у меня есть таблица, где я хочу просто сохранить все URL-адреса, связанные с моим сайтом, и последний раз, когда они были посещены.

Мое определение может выглядеть примерно так:

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

Это позволило бы мне добавить один и тот же URL-адрес снова и снова, если я не написал код PHP, подобный приведенному выше, чтобы остановить это.

Однако было ли мое определение изменяться на

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

Тогда это заставит mysql выдать ошибку, когда я попытался вставить одно и то же значение дважды.

Примером в PHP будет

 $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'); } 

Если вы запустили это, вы обнаружите, что с первой попытки скрипт умрет вместе с комментарием « Could not Insert Row 2 . Тем не менее, на последующих запусках он умирает с Could not Insert Row 1 .

Это связано с тем, что MySQL знает, что URL-адрес является основным ключом таблицы. Первичный ключ является уникальным идентификатором для этой строки. В большинстве случаев полезно установить уникальный идентификатор строки как число. Это связано с тем, что MySQL быстрее просматривает цифры, чем ищет текст. Внутри MySQL ключи (и первичные первичные ключи) используются для определения отношений между двумя таблицами. Например, если бы у нас была таблица для пользователей, мы могли бы определить ее как

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

Однако, когда мы хотели хранить информацию о записи, которую сделал пользователь, нам нужно будет сохранить имя пользователя с этим сообщением, чтобы определить, что сообщение принадлежит этому пользователю.

Я уже упоминал, что MySQL быстрее просматривает цифры, чем строки, поэтому это будет означать, что мы будем тратить время на поиск строк, когда нам это не нужно.

Чтобы решить эту проблему, мы можем добавить дополнительный столбец user_id и сделать это первичным ключом (поэтому при поиске записи пользователя на основе сообщения мы можем быстрее ее найти)

 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`) ) 

Вы заметите, что я также добавил здесь что-то новое – AUTO_INCREMENT. Это в основном позволяет нам позволить этому полю заботиться о себе. Каждый раз, когда вставлена ​​новая строка, она добавляет 1 к предыдущему числу и сохраняет это, поэтому нам не нужно беспокоиться о нумерации и просто позволить ей сделать это сама.

Итак, с приведенной выше таблицей мы можем сделать что-то вроде

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

а потом

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

Когда мы выбираем записи из базы данных, получаем следующее:

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

Однако здесь – у нас есть проблема – мы можем добавить еще одного пользователя с тем же именем пользователя! Очевидно, это то, что мы не хотим делать!

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

Позволяет изменить определение таблицы!

 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) ) 

Давайте посмотрим, что произойдет, когда мы попытаемся дважды вставить одного и того же пользователя.

 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' 

Ура !! Теперь мы получаем ошибку, когда пытаемся вставить имя пользователя во второй раз. Используя что-то вроде выше, мы можем обнаружить это в PHP.

Теперь вернемся к нашей таблице ссылок, но с новым определением.

 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) ) 

и давайте вставим «http://www.example.com» в базу данных.

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

Если мы попытаемся снова вставить его …

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

Но что произойдет, если мы хотим обновить время последнего посещения?

Ну, мы могли бы сделать что-то сложное с PHP, например:

 $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'); } } 

Или даже захватите идентификатор строки в базе данных и используйте ее для ее обновления.

$ 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'); } } 

Но у MySQL есть хорошая встроенная функция REPLACE INTO

Давайте посмотрим, как это работает.

 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) 

Обратите внимание, что при использовании REPLACE INTO оно обновляется в последний раз, а не выдает ошибку!

Это связано с тем, что MySQL обнаруживает, что вы пытаетесь заменить строку. Он знает строку, которую вы хотите, поскольку вы установили URL-адрес уникальным. MySQL вычисляет заменяемую строку, используя бит, который вы передали, который должен быть уникальным (в данном случае, url) и обновлять для этой строки другие значения. Он также обновил link_id – это немного неожиданно! (На самом деле, я не понимал, что это произойдет, пока я просто не увижу, что это произойдет!)

Но что, если вы хотите добавить новый URL? Ну, REPLACE INTO радостью добавит новую строку, если не найдет подходящую уникальную строку!

 mysql> REPLACE INTO links (url, last_visited) VALUES ('http://www.stackoverflow.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.stackoverflow.com/ | 2011-08-20 00:01:22 | +---------+-------------------------------+---------------------+ 2 rows in set (0.00 sec) 

Надеюсь, это ответ на ваш вопрос и даст вам немного больше информации о том, как работает MySQL!

Вас беспокоит только URL-адреса, которые являются одной и той же строкой. Если это так, есть много хороших советов в других ответах. Или вам также нужно беспокоиться о канонизации?

Например: http://google.com и http: //go%4fgle.com – это один и тот же URL-адрес, но будут разрешены как дубликаты с помощью любой из методов только базы данных. Если это проблема, вы должны предварительно обработать URL-адреса для разрешения и последовательности escape-символов.

В зависимости от того, где URL-адреса поступают от вас, вам также придется беспокоиться о параметрах и важны ли они в вашем приложении.

Сначала подготовьте базу данных .

  • Доменные имена не чувствительны к регистру, но вы должны принять остальную часть URL-адреса. (Не все веб-серверы относятся к делу в URL-адресах, но большинство из них, и вы не можете легко сказать, глядя.)
  • Предполагая, что вам нужно хранить больше, чем доменное имя, используйте сортировку с учетом регистра.
  • Если вы решите сохранить URL-адрес в двух столбцах: один для имени домена и один для локатора ресурсов, – рассмотрите возможность сортировки без учета регистра для имени домена и сортировку с учетом регистра для локатора ресурсов. Если бы я был вами, я бы тестировал оба пути (URL-адрес в одном столбце и URL-адрес в двух столбцах).
  • Поместите ограничение UNIQUE в столбец URL. Или в паре столбцов, если вы храните имя домена и локатор ресурсов в отдельных столбцах, как UNIQUE (url, resource_locator) .
  • Используйте ограничение CHECK () для сохранения кодированных URL-адресов из базы данных. Это ограничение CHECK () имеет важное значение для предотвращения попадания плохих данных через массовую копию или через оболочку SQL.

Во-вторых, подготовьте URL-адрес .

  • Доменные имена не чувствительны к регистру. Если вы сохраняете полный URL-адрес в одном столбце, введите имя домена по всем URL-адресам. Но имейте в виду, что некоторые языки имеют прописные буквы, которые не имеют эквивалента в нижнем регистре.
  • Подумайте об обрезке завершающих символов. Например, эти два URL-адреса от amazon.com указывают на один и тот же продукт. Вероятно, вы захотите сохранить вторую версию, а не первую.

    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

  • Декодирование кодированных URL. (См . Функцию php's urldecode () . Внимательно обратите внимание на ее недостатки, как описано в комментариях этой страницы.) Лично я предпочитаю обрабатывать такие виды преобразований в базе данных, а не в клиентском коде. Это будет включать отмену разрешений на таблицы и представления и возможность вставки и обновления только через хранимые процедуры; хранимые процедуры обрабатывают все операции с строкой, которые помещают URL в каноническую форму. Но следите за тем, как вы это делаете. Ограничения CHECK () (см. Выше) являются вашей защитой.

В-третьих , если вы вставляете только URL-адрес, сначала не проверяйте его существование . Вместо этого попробуйте вставить и уловить ошибку, которую вы получите, если значение уже существует. Тестирование и вставка дважды попадает в базу данных для каждого нового URL-адреса. Вставка-и-ловушка просто попадает в базу данных один раз. Обратите внимание, что вставка-и-ловушка – это не то же самое, что вставка-и-игнорировать-ошибки. Только одна конкретная ошибка означает, что вы нарушили уникальное ограничение; другие ошибки означают, что есть и другие проблемы.

С другой стороны, если вы вставляете URL-адрес вместе с некоторыми другими данными в одну строку, вам нужно заранее решить, будете ли вы обрабатывать повторяющиеся URL-адреса

  • удаление старой строки и вставка нового (см. расширение REPLACE MySQL в SQL )
  • обновление существующих значений (см. ОБНОВЛЕНИЕ КЛЮЧА DUPLICATE )
  • игнорирование проблемы
  • требуя от пользователя принятия дальнейших мер

REPLACE устраняет необходимость улавливать повторяющиеся ключевые ошибки, но может иметь неприятные побочные эффекты, если есть ссылки на внешние ключи.

Чтобы гарантировать уникальность, вам нужно добавить уникальное ограничение. Предполагая, что ваше имя таблицы является «urls», а имя столбца – «url», вы можете добавить уникальное ограничение с помощью этой команды alter table:

 alter table urls add constraint unique_url unique (url); 

Если вы уже получили дублирующие URL-адреса в таблице, таблица alter скорее всего не удастся (кто действительно знает с MySQL).

Для простых SQL-решений требуется уникальное поле; логических решений нет.

Вы должны нормализовать свои URL-адреса, чтобы избежать дублирования. Функции в PHP, такие как strtolower () и urldecode () или rawurldecode () .

Предположения. Имя вашей таблицы – «веб-сайты», имя столбца для вашего URL-адреса – «url», а произвольные данные, которые должны быть связаны с URL-адресом, находятся в столбце «данные».

Логические решения

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

Проверьте предыдущий запрос с операторами if в SQL или PHP, чтобы убедиться, что он равен 0, прежде чем продолжить с инструкцией INSERT.

Простые выражения SQL

Сценарий 1: Ваш db – это первая таблица с первой подачей, и у вас нет желания дублировать записи в будущем.

 ALTER TABLE websites ADD UNIQUE (url) 

Это предотвратит возможность ввода любых записей в базу данных, если значение url уже существует в этом столбце.

Сценарий 2. Вы хотите получить самую последнюю информацию для каждого URL-адреса и не хотите дублировать контент. Для этого сценария есть два решения. (Эти решения также требуют, чтобы «url» был уникальным, поэтому решение в Сценарии 1 также необходимо будет выполнить.)

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

Это вызовет действие DELETE, если строка существует, а затем INSERT во всех случаях, поэтому будьте осторожны с объявлениями ON DELETE.

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

Это вызовет действие UPDATE, если существует строка, и INSERT, если это не так.

При рассмотрении решения этой проблемы вам нужно сначала определить, что означает «дублированный URL» для вашего проекта. Это определит, как канонизировать URL-адреса перед их добавлением в базу данных.

Существует по крайней мере два определения:

  1. Два URL-адреса считаются дублирующимися, если они представляют один и тот же ресурс, ничего не зная о соответствующей веб-службе, которая генерирует соответствующий контент. Некоторые соображения включают:
    • Схема и доменное имя URL-адресов нечувствительны к регистру, поэтому http://WWW.STACKOVERFLOW.COM/ совпадает с http://www.stackoverflow.com/ .
    • Если один URL указывает порт, но это обычный порт для схемы, и они в противном случае эквивалентны, то они одинаковы ( http://www.stackoverflow.com/ и http://www.stackoverflow.com:80 / ).
    • Если параметры в строке запроса являются простыми перестановками, а имена параметров все разные, то они одинаковы; например, http: // authority /? a = test & b = test и http: // authority /? b = test & a = test . Обратите внимание, что http: // authority /? A% 5B% 5D = test1 & a% 5B% 5D = test2 не совпадает с этим первым определением одинаковости, поскольку http: // авторитет /? A% 5B% 5D = test2 & a% 5B% 5D = test1 .
    • Если схема является HTTP или HTTPS, то хэш-части URL-адресов могут быть удалены, так как эта часть URL-адреса не отправляется на веб-сервер.
    • Сокращенный адрес IPv6 может быть расширен.
    • Добавьте конечную косую черту к авторитету, только если она отсутствует.
    • Канонизация в Unicode изменяет ссылочный ресурс; например, вы не можете заключить, что http://google.com/?q=%C3%84 ( %C3%84 представляет «Ä» в UTF-8) совпадает с http://google.com/?q = A% CC% 88 ( %CC%88 представляет U + 0308, КОМБИНИРОВАННАЯ ДИНАМИКА).
    • Если схема является HTTP или HTTPS, « www. 'в авторитете одного URL-адреса нельзя просто удалить, если оба URL-адреса в противном случае эквивалентны, поскольку текст имени домена отправляется как значение заголовка HTTP- Host , а некоторые веб-серверы используют виртуальные хосты для отправки другого контента на основе этот заголовок. В более общем плане, даже если доменные имена разрешены на один и тот же IP-адрес, вы не можете заключить, что указанные ресурсы одинаковы.
  2. Примените базовую URL-схему канонизации (например, нижний регистр схемы и имени домена, поставьте порт по умолчанию, стабильные параметры запроса сортировки по имени параметра, удалите хэш-часть в случае HTTP и HTTPS, …) и учтите веб-службы. Возможно, вы предположите, что все веб-службы достаточно умен, чтобы канонизировать вход Unicode (например, Wikipedia), поэтому вы можете применить форму Unicode Normalization Form Canonical Composition (NFC). Вы бы разделили « www. 'из всех URL-адресов переполнения стека. Вы можете использовать Postrank's postrank-uri code, портированный на PHP, для удаления всех видов ненужных URL-адресов (например, &utm_source=... ).

Определение 1 приводит к устойчивому решению (т. Е. Дальнейшая канонизация не может быть выполнена, и канонизация URL-адреса не изменится). Определение 2, которое, по моему мнению, является тем, что человек считает определением канонизации URL, приводит к рутинной процедуре канонизации, которая может давать разные результаты в разные моменты времени.

Какое бы определение вы ни выбрали, я предлагаю вам использовать отдельные столбцы для частей схемы, входа, хоста, порта и пути. Это позволит вам использовать индексы разумно. Столбцы схемы и хоста могут использовать сортировку символов (все сопоставления символов не зависят от регистра в MySQL), но столбцы для входа и пути должны использовать двоичную, не зависящую от регистра сортировку. Кроме того, если вы используете определение 2, вам нужно сохранить исходную схему, полномочия и части пути, так как некоторые правила канонизации могут время от времени добавляться или удаляться.

EDIT: Ниже приведены примеры таблиц:

 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'; 

Таблица `urls1` предназначена для хранения канонических URL-адресов в соответствии с определением 1. Таблица` urls2` предназначена для хранения канонических URL-адресов в соответствии с определением 2.

К сожалению, вы не сможете указать ограничение UNIQUE для кортежа (`schem` /` canonical_scheme`, `canonical_login`,` canonical_host`, `port`,` canonical_path`), поскольку MySQL ограничивает длину ключей InnoDB до 767 байт ,

Я не знаю синтаксиса для MySQL, но все, что вам нужно сделать, это обернуть ваш INSERT с помощью оператора IF, который будет запрашивать таблицу и посмотреть, не будет ли запись с указанным url EXISTS, если она существует, – не вставляйте новую запись.

если MSSQL вы можете сделать это:

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

Если вы хотите вставлять URL-адреса в таблицу, но только те, которые не существуют, вы можете добавить UNIQUE-контрацепцию в столбец, а в вашем запросе INSERT добавить IGNORE, чтобы вы не получили ошибку.

Пример: INSERT IGNORE INTO urls SET url = 'url-to-insert'

Прежде всего. Если вы еще не создали таблицу или вы создали таблицу, но у вас нет данных, вам нужно добавить уникальный constriant или уникальный индекс. Более подробная информация о выборе между индексом или ограничениями приведена в конце сообщения. Но они оба выполняют одно и то же, соблюдая при этом, что столбец содержит только уникальные значения.

Чтобы создать таблицу с уникальным индексом в этом столбце, вы можете использовать.

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

Если вам просто нужно уникальное ограничение и нет индекса в этой таблице, вы можете использовать

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

Теперь, если у вас уже есть таблица, и в ней нет данных, вы можете добавить индекс или ограничение в таблицу с помощью одного из следующих фрагментов кода.

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

Теперь у вас может быть таблица с некоторыми данными. В этом случае у вас могут быть некоторые дубликаты данных. Вы можете попытаться создать указатель или указатель, показанный выше, и он будет терпеть неудачу, если у вас уже есть повторяющиеся данные. Если у вас нет дубликатов данных, отлично, если вы это сделаете, вам придется удалить дубликаты. Вы можете увидеть освещенные URL-адреса с дубликатами, используя следующий запрос.

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

Чтобы удалить повторяющиеся строки и сохранить их, выполните следующие действия:

 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; 

Теперь, когда вы удалили все записи, вы можете продолжить и создать индекс или ограничение. Теперь, если вы хотите вставить значение в свою базу данных, вы должны использовать что-то вроде этого.

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

Это попытается сделать вставку, и если она найдет дубликат, ничего не произойдет. Теперь, скажем, у вас есть другие столбцы, вы можете сделать что-то вроде этого.

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

Это будет выглядеть, пытаясь вставить значение, и если он найдет URL-адрес, он обновит запись, увеличив счетчик посещений. Конечно, вы всегда можете сделать обычную старую вставку и обрабатывать полученную ошибку в вашем PHP-коде. Теперь о том, следует ли использовать ограничения или индексы, зависит от множества факторов. Индексы делают более быстрый поиск, поэтому ваша производительность будет лучше по мере увеличения таблицы, но сохранение индекса займет дополнительное место. Индексы, как правило, также делают вставки и обновления занимают больше времени, потому что он должен обновить индекс. Однако, поскольку значение нужно искать в любом случае, чтобы обеспечить уникальность, в этом случае, возможно, быстрее будет иметь индекс. Что касается любой производительности, ответ заключается в том, чтобы попробовать обе опции и профилировать результаты, чтобы увидеть, какая из них лучше всего подходит для вашей ситуации.

Если вам просто нужен ответ «да» или «нет», этот синтаксис должен дать вам лучшую производительность.

  выберите if (существует (выберите url из URL-адресов, где url = 'http://asdf.com'), 1, 0) из двойного 

Если вы просто хотите убедиться, что дубликатов нет, добавьте уникальный индекс в поле url, поэтому нет необходимости явно проверять, существует ли URL-адрес, просто вставить как обычно, и если он уже есть, то вставка будет с ошибкой повторяющегося ключа.

Ответ зависит от того, хотите ли вы знать, когда делается попытка ввести запись с дублирующимся полем. Если вам все равно, используйте синтаксис «INSERT … ON DUPLICATE KEY», так как это сделает вашу попытку спокойно успешной без создания дубликата.

Если, с другой стороны, вы хотите знать, когда происходит такое событие, и предотвратить его, тогда вы должны использовать уникальное ограничение ключа, которое приведет к сбою попытки вставки / обновления с существенной ошибкой.

 $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 } 

Сделать столбец primary key

Вы можете найти (и удалить), используя самообучение. В вашей таблице есть URL-адрес, а также некоторые ПК (мы знаем, что ПК не является URL-адресом, потому что в противном случае вам не разрешат дублировать)

 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 

Это вернет все строки с дублируемыми URL-адресами.

Скажите, однако, что вы хотели только выбрать дубликаты и исключить оригинал …. Ну, вам нужно будет решить, что составляет оригинал. Для целей этого ответа предположим, что самый низкий ПК является «оригинальным»,

Все, что вам нужно сделать, это добавить следующее предложение к вышеуказанному запросу:

 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" 

Теперь у вас есть набор всех неоригинальных дублированных строк. Вы легко можете выполнить DELETE или все, что вам нравится, из этого набора результатов.

Обратите внимание, что этот подход может быть неэффективным, отчасти потому, что mySQL не всегда обрабатывает IN хорошо, но я понимаю из OP, что это своего рода «очистка» на столе, а не всегда проверка.

Если вы хотите проверить на время INSERT действительно ли значение уже существует, вы можете запустить что-то вроде этого

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

Если вы получите результат, вы можете заключить, что значение уже существует в вашей БД хотя бы один раз.

Вы можете сделать этот запрос:

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

Затем проверьте, существует ли mysql_num_rows () == 1, если он существует.