Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

Чтобы ответить на ваш первоначальный вопрос, самый простой способ проверить, есть ли дубликат, - запустить 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');
}

Если вы запустили это, вы обнаружите, что с первой попытки script умрет с комментарием 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!

Ответ 3

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

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

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

Ответ 4

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

  • Доменные имена не чувствительны к регистру, но вы должны принять оставшуюся часть 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 & ср = 8-1

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

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

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

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

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

Ответ 5

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

alter table urls add constraint unique_url unique (url);

Измененная таблица, вероятно, не сработает (кто действительно знает с MySQL), если у вас уже есть повторяющиеся URL-адреса в вашей таблице.

Ответ 6

Для простых 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, если это не так.

Ответ 7

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

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

  • Два 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://authority/?a%5B%5D=test2&a%5B%5D=test1.
    • Если схема представляет собой HTTP или HTTPS, то хэш-части URL-адресов могут быть удалены, так как эта часть URL-адреса не отправляется на веб-сервер.
    • Сокращенный адрес IPv6 может быть расширен.
    • Добавить конечную косую черту только в том случае, если она отсутствует.
    • Unicode canonicalization изменяет ссылочный ресурс; например вы не можете заключить, что 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-адреса в противном случае эквивалентны, поскольку текст имени домена отправляется как значение Host HTTP, а некоторые веб-серверы используют виртуальные хосты для отправки другого контента на основе этого заголовка. В более общем плане, даже если имена доменов разрешены на один и тот же IP-адрес, вы не можете заключить, что ссылочные ресурсы одинаковы.
  • Применить базовую URL-схему канонизации (например, нижний регистр схемы и имени домена, указать порт по умолчанию, стабильные параметры запроса сортировки по имени параметра, удалить хэш-часть в случае HTTP и HTTPS,...) и принять знание учетной записи веб-службы. Возможно, вы предположите, что все веб-сервисы достаточно умен, чтобы канонизировать вход Unicode (например, Wikipedia), поэтому вы можете применить Unicode Normalization Form Canonical Состав (NFC). Вы удаляете 'www.' из всех URL-адресов. Вы можете использовать PostRank postrank-uri код, портированный на 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 байт.

Ответ 8

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

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

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

Ответ 9

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

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

Ответ 10

Прежде всего. Если вы еще не создали таблицу или вы создали таблицу, но у вас нет данных, вам нужно добавить уникальный 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-коде. Теперь о том, следует ли использовать ограничения или индексы, зависит от множества факторов. Индексы делают более быстрый поиск, поэтому ваша производительность будет лучше по мере увеличения таблицы, но сохранение индекса займет дополнительное место. Индексы, как правило, также делают вставки и обновления занимают больше времени, потому что он должен обновить индекс. Однако, поскольку значение нужно искать в любом случае, чтобы обеспечить уникальность, в этом случае, возможно, быстрее будет иметь индекс. Что касается любой производительности, ответ заключается в том, чтобы попробовать обе опции и профилировать результаты, чтобы увидеть, какая из них лучше всего подходит для вашей ситуации.

Ответ 11

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

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

Ответ 12

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

Ответ 13

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

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

Ответ 14

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

Ответ 15

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

Ответ 16

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

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

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

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

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

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

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

Ответ 17

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

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

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