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