2014-07-27 7 views
3

Является ли мой код/​​синтаксис неправильным? Я не уверен, что не так, и я новичок в этом. Я создал таблицу в PHPMyAdmin. Он имеет две колонки. Один из них - «id» и является основным ключом/автоматическим приращением. Другой столбец - «имя_файла».PHP MySQL Вставить Into & On Повторяющиеся проблемы с ключами

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

Имя таблицы в PhpMyAdmin является имена

 <?php 
     // Capture person's name from XML file 
     $profile = simplexml_load_file('UrlGoesHere.Com/?xml=1', 'SimpleXMLElement', LIBXML_NOCDATA); 
     echo (string)$profile->steamID; 

     //Enter name into databse and overwrite it if same/duplicate 
     $con=mysqli_connect("localhost","username","password","databaseName"); 
     // Check connection 
     if (mysqli_connect_errno()) 
     { 
      echo "Failed to connect to MySQL: " . mysqli_connect_error(); 
     } 

     // Perform queries 
     mysqli_query($con,"INSERT INTO names (steamname) VALUES ('$profile') ON DUPLICATE KEY UPDATE steamname = VALUES('$profile')"); 
     mysqli_close($con); 
     ?> 

Я проверил это вручную изменить значение строки в «steamname» в PHPMyAdmin к «woogy» и затем запустить этот сценарий, чтобы увидеть если он обновит значение базы данных ... ничего не происходит. Он должен обновить «woogy» до собственного имени.

----------- --------------- Обновления

Привет всем. Спасибо за вход. Теперь у меня есть мой код следующим образом. Извините, если все еще не так. Я изучаю.

  <?php 
     $profile = simplexml_load_file('http://steamcommunity.com/profiles/76561198006938281/?xml=1', 'SimpleXMLElement', LIBXML_NOCDATA); 
     echo (string)$profile->steamID; 


     $con=mysqli_connect("localhost","userHere","passwordHERE","DBName"); 
     // Check connection 
     if (mysqli_connect_errno()) 
     { 
      echo "Failed to connect to MySQL: " . mysqli_connect_error(); 
     } 

     // Perform queries 
     mysqli_query($con,"INSERT INTO names (steamname) VALUES ('$profile') ON DUPLICATE KEY UPDATE ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname)"); 
     mysqli_close($con); 
     ?> 

Это как база данных выглядит перед запуском скрипта: (woogy должен измениться Chatyak)

Click image here

Теперь, когда я запускаю страницу PHP, это то, что происходит с моей базой данных ,

How database looks after running script

Не знаю, почему он не обновлялся - а также, почему существует такое огромное пространство?

+0

Вы хотите использовать именованные параметры в своих операторах SQL. – FloatingRock

+1

Вам нужно включить 'id' в запрос, так как без него дублирующий ключ никогда не сопоставляется ->' 'INSERT INTO имена (id, steamname) VALUES ($ profile-> steamId, '$ profile-> name') ON DUPLICATE KEY UPDATE steamname = VALUES (имя_файла) ". обратите внимание, что '$ profile-> steamId' /' $ profile-> name' являются догадками относительно того, что означают ваши 'id' и обновленные значения' name'. – Sean

+0

@Sean, 'ID' является автоматическим приращением. В этом случае это не нужно в инструкции 'INSERT'. Правильный запрос INSERT OP. – Rahul

ответ

2

правый синтаксис INSERT ... ON DUPLICATE KEY будет, как показано ниже, вы должны указать имя столбца в VALUES как VALUES(column_name) вместо VALUES('$profile'). Кроме того, вам недостает колонки PK ID в случае UPDATE. Причина, по которой вы хотите обновить значение steamname для значения ID.

INSERT INTO names (steamname) 
VALUES ('$profile') 
ON DUPLICATE KEY UPDATE ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname) 

(ИЛИ)

INSERT INTO names (steamname) 
VALUES ('$profile') 
ON DUPLICATE KEY UPDATE steamname = VALUES(steamname) 

Цитируется MySQL documentation

Если таблица содержит столбец AUTO_INCREMENT и INSERT ... UPDATE вставляет строку, функция LAST_INSERT_ID() возвращает значение AUTO_INCREMENT. Если инструкция обновляет строку, то LAST_INSERT_ID() не имеет смысла. Тем не менее, вы можете обойти это , используя LAST_INSERT_ID(expr).

+0

. Это все еще просто вставляет новую строку, потому что она генерирует новое значение идентификатора автоматического увеличения. –

+0

что @BillKarwin написал. 'ON DUPLICATE KEY UPDATE ID = LAST_INSERT_ID (ID)' это круг ничего. Оператор 'INSERT INTO names (steamname)' всегда будет генерировать новый 'id', поэтому обновление никогда не будет происходить, и если бы оно каким-то образом LAST_INSERT_ID()' было бы бессмысленным. – user1433150

+0

Я изложил то, что, как я считаю, ошибаюсь в вашем ответе в редакции моего ответа, поскольку это слишком долго для комментария. – user1433150

1

Вы не можете использовать INSERT ON KEY UPDATE DUPLICATE (IODKU) для обновления вместо вставки новой строки, если вы попытаетесь вставить значение, которое конфликтует с существующим первичным или уникальным ключом столбцом.

Поскольку вы не указываете значение ID в этом INSERT, оно всегда увеличивает первичный ключ с автоматическим приращением и вставляет новую строку.

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


Re ваш первый комментарий:

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

Вот демо:

mysql> create table names (id serial primary key, steamname text); 

mysql> insert into names (steamname) values ('Woogy') 
    on duplicate key update ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname); 

Игнорируйте ID = LAST_INSERT_ID(ID) часть, это не имеет никакого эффекта. Это не-op. @Rahul предложил это, но, к сожалению, он ошибается. Я собираюсь вынести этот термин в последующих тестах.

Так что происходит в этом INSERT? Вы указываете значение для steamname, но нет значения для ID. Поэтому MySQL генерирует новое значение для ID. Это становится основным значением ключа для новой строки, и эта строка вставлена ​​с именем «Woogy».

mysql> select * from names; 
+----+-----------+ 
| id | steamname | 
+----+-----------+ 
| 1 | Woogy  | 
+----+-----------+ 

Далее мы пытаемся изменить название на 'Chatyak':

mysql> insert into names (steamname) values ('Chatyak') 
    on duplicate key update steamname = VALUES(steamname); 

Какие строки это относится изменение к? INSERT не указывает значение ID, поэтому MySQL автоматически увеличивает другое значение ID. Это значение является первичным ключом для новой строки, и это строка, которая получает имя «Chatyak».

mysql> select * from names; 
+----+-----------+ 
| id | steamname | 
+----+-----------+ 
| 1 | Woogy  | 
| 2 | Chatyak | 
+----+-----------+ 

Что это означает, что вы никогда не можете вызвать дублирование KEY части, если вы позволите автоприращению генерировать новый идентификатор значения, каждый раз, когда вы вставляете. Каждый INSERT приведет к появлению новой строки.

Как я уже говорил, ON DUPLICATE KEY ничего не делает, если вы не попытаетесь вставить значение, которое конфликтует с основным или уникальным ключом для строки, которая уже существует в таблице. Но в этом случае вы не конфликтуете, вы всегда генерируете новое значение ID. Таким образом, он вставляет новую строку.

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

mysql> alter table names add unique key (steamname(20)); 

Затем, если вы попытаетесь вставить steamname же как тот, который уже существует, он не будет вставить новую строку. Он обновит существующую строку.

mysql> insert into names (steamname) values ('Chatyak') 
    on duplicate key update ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname); 
Query OK, 0 rows affected (0.02 sec) 

Обратите внимание, что в нем указано «0 строк».

Но это все еще не позволяет вам изменять существующее имя. Если вы укажете новое имя, оно просто введет новую строку.Если вы укажете имя, которое уже используется, это дубликат, поэтому он не будет вставлять новую строку, но она также не изменит имя.

Как вы ожидаете, что инструкция INSERT применима к существующей строке, если вы позволите ей автоматически увеличивать значение нового идентификатора? С какой из существующих строк вы должны столкнуться?


Re вашего второго комментария:

Вам не нужен второстепенный уникальный ключ, я просто пытаюсь показать вам, как работает IODKU.

Прежде чем думать о синтаксисе SQL, вы должны думать о логике проблемы. Другими словами, если вы укажете новое имя, какую существующую строку вы хотите заменить?

Например:

mysql> insert into names (id, steamname) values (123, 'Chatyak') 
    on duplicate key update steamname = VALUES(steamname); 

Это будет работать, потому что, если строка существует с ID 123, это ВСТАВИТЬ вызовет дубликат ключа конфликта и поэтому KEY положение ON DUPLICATE будет срабатывать. Но где мы получили значение 123 в этом примере? Предположительно в вашем приложении вы знаете, какой идентификатор вы считаете обновленным. Есть ли переменная для этого? Соответствует ли это данным сеанса пользователя?

+0

Привет, Билл. Кажется, я все еще застрял. Пожалуйста, ознакомьтесь с моими изменениями в оригинальном посте с фотографиями. – Chatyak

+0

Билл ... спасибо за учебник. Я думаю, вы пытаетесь показать мне, какие способы задуматься о создании стола? Я понимаю, что если значение ID действительно не указано в инструкции INSERT ... тогда по умолчанию новая строка всегда будет создана, потому что первичный ключ не имеет ничего, чтобы проверить дубликат на правильное? Итак, мой вопрос тогда ... Какова правильная формула для объявления идентификатора в инструкции insert? Я попытался добавить уникальный ключ, как вы предложили, но я не уверен, что он сделал или как его удалить из моей таблицы. Кроме того, почему нам нужен уникальный ключ, если у нас есть первичный ключ? – Chatyak

+0

Привет, Билл. Спасибо за ваше время. Я проверил ваш последний код там, и он работает очень хорошо. Веб-страница, которая будет обновлять это, будет PageName.php, и у меня будет хрон, который запускает его каждые несколько часов. Идентификатор будет введен вручную, поскольку он отслеживает только около 30 человек. Проблема, с которой я столкнулся, заключалась в том, что я заменил «Chatyak» на «$ profile». Он работает, не создавая новую строку (поскольку значение id есть :)), однако столбец паролей теперь является большим пустым пространством снова .... вероятно, связано с тем, что пользователь упомянул вверх с моим неправильным использованием переменной. – Chatyak

1

************************** Редактировать: ***************** ********

В ответ на ответ, предоставленный @Rahul. Это утверждение:

INSERT INTO names (steamname) 
VALUES ('$profile') 
ON DUPLICATE KEY UPDATE ID = LAST_INSERT_ID(ID), steamname = VALUES(steamname) 

технически действует, но всегда будет влиять ровно 0 строк ни на что. На самом деле в нем так много ошибок, что их перечислить сложно (что и является причиной этого редактирования).

Использование ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id), приведенные в MySQL документации в нижней части this page является примером того, как захватить значение строки, которая была обновлена ​​ т.е. не вставлена ​​id, так как в противном случае LAST_INSERT_ID() (без аргумента) будет возвращен последний , вставленный id, что в случае обновление не имеет смысла в терминах рассматриваемой строки.

Так приведенное выше утверждение, если он когда-либо работал, - хотя он не может - было бы эффективно не отличается от этого заявления:

INSERT INTO names (steamname) 
VALUES ('$profile') 
ON DUPLICATE KEY UPDATE steamname = VALUES(steamname) 

Кроме того, что вы бы обновить id значение этой строки к значению это уже было.

Кроме того, причина, по которой оператор не может работать потому, что положение ON DUPLICATE KEY UPDATE никогда не будет оцениваться, если не является дубликат ключа. И такая же ошибка, которая возникла бы без предложения ON DUPLICATE KEY UPDATE, возникнет, когда мы попытаемся обновить steamname, чтобы получить значение steamname, то есть то же самое значение, которое в первую очередь сработало в предложении ON DUPLICATE KEY UPDATE.

***************************** КОНЕЦ ИЗМЕНЕНИЯ ************* **********************

Первый: $profile по-прежнему является экземпляром объекта SimpleXMLElement, когда вы пытаетесь использовать его в своем запросе. Таким образом, вызывается метод SimpleXMLElement::__toString, но метод SimpleXMLElement::__toStringвозвращает текстовое содержимое непосредственно из первого элемента, а не текст от любых потомков. Поэтому, если у вас есть элемент <steamname> и некоторый элемент <steamID>, вложенный в родительский элемент, возвращенный вашим вызовом, simplexml_load_file, их значения не будут возвращены. См. manual.

Во-вторых: при использовании функции VALUES с предложением UPDATE правильный синтаксис относится к названию столбца, например DUPLICATE KEY UPDATE colname = VALUES(some_col_name). Если вы хотите использовать явное значение, синтаксис равен DUPLICATE KEY UPDATE colname = 'value'. См. manual.

Третьего: поскольку у вас есть id набора для AUTO_INCREMENT любых строки, вставленные в names таблицы без явного вставки id значения или используя пункт WHERE указать id значения будет создать новую строку с новым авто увеличивается id значения, независимо от того, используете ли вы DUPLICATE KEY UPDATE или нет, потому что AUTO_INCREMENT гарантирует, что вы никогда не создадите дублирующий ключ.

Я думаю, что вы можете использовать инструкцию mysql REPLACE. Это самый простой запрос, который работает для ваших описанных потребностей.

REPLACE INTO `names` (`id`,`steamname`) 
VALUES ($id, $steamname) 

, где находится $id$profile->steamID и $steamname является новым (или не новый) значение steamname столбца этой строки.

Оператор REPLACE будет просто DELETE, а затем INSERT, где значение id уже существует. Но поскольку вы вставляете тот же id, эффект заключается в обновлении значения steamname в строке, содержащей соответствующее значение id. Просто имейте в виду, что если у вас есть другие столбцы, кроме id и steamname в той же таблице, и вы не укажете их значения в REPLACEVALUES, то эти значения будут потеряны.

В-четвертых: для отладки таких вещей, важных для a), знаете, какие значения вы фактически передаете в строку запроса. b) знают, что основной синтаксис запроса, который вы используете, является правильным, кроме любых конкретных значений, которые вы используете (или не используете) с ним.

И, наконец, облегчите себе жизнь; поскольку вы уже используете объектную нотацию с SimpleXMLElement для доступа к значениям элементов, почему бы и не использовать ее с mysqli? Попробуй это. Это UNTESTED, но он думает, что это сработает для вас.

<?php 
    // Capture person's name and id from XML file 
    $profile = simplexml_load_file('UrlGoesHere.Com/?xml=1', 'SimpleXMLElement', LIBXML_NOCDATA); 
     $profile_id = (string)$profile->steamID; 
     $profile_name = (string)$profile->steamName; 

    //connect to database 
    $mysqli = new mysqli("localhost","username","password","databaseName"); 

    // Check connection 
    if (mysqli_connect_errno()) 
    { 
     echo "Failed to connect to MySQL: " . mysqli_connect_error(); 
    } 

    //build query 
    //IMPROTANT: this will delete other fields(if any) 
    //> in the row, unless they are also refilled by this statement 
    $q = (" 
    REPLACE INTO `names` (`id`,`steamname`) 
    VALUES (?, ?) 
    "); 

    //uncomment to debug query 
     //echo "<pre>$q</pre>"; 

    //uncomment to debug values 
     //echo "<pre>profile_name: \n $profile_name</pre>"; 
     //echo "<pre>profile_id: \n $profile_id</pre>"; 

    //prepare statement using above query 
    $stmt = $mysqli->prepare($q); 

    //fill in '?'s with actual values 
    //first argument is the data types 
    //'i' [integer] 's' [string] 
    //follownig aruments fill in '?'s in order 
    $stmt->bind_param('is', $profle_id, $profile_name); 

    // execute statement 
    $stmt->execute(); 

    //close statement 
    $stmt->close(); 
    //close connection 
    $mysqli->close(); 
?>   
+0

Привет, пользователь - спасибо за ваш вклад и мысль. Я буду уверен и проверю это. Я только начинаю изучать все это, поэтому ваш код немного запутывает меня.Я понимаю, что мы делаем «замену» на переменную .. и используем эту переменную в подготовленном заявлении. Означает ли stmt что-либо или это просто случайная переменная, которую вы выбрали для использования? Я также оставил комментарий на ответ Билла ниже, а также здесь, где его код действительно сработал, но замена «Chatyak» на «$ profile» снова оставляет гигантское пустое пространство ... предположительно, из вашей справки о том, что я использую его неправильно. Этот код исправляет это? – Chatyak

+0

'$ stmt' - подготовленный оператор mysqli. Когда мы делаем этот вызов '$ mysqli = new mysqli ([...]), возвращается объект класса mysqli. Объект - это просто набор переменных и функций, которые работают вместе, потому что они все знают друг о друге. Вы получаете доступ к этим «членам» следующим образом: '$ mysqli-> memberName'. '$ mysqli-> prepare ($ q);' возвращает другой связанный объект с разными членами, например. bind_param, выполнить, закрыть. Итак, после захвата этого объекта в переменной '$ stmt' мы получаем доступ к его членам:' $ stmt-> bind_param() '. Вы уже использовали это с паролем '$ profile-> steamID' – user1433150

+0

Кажется, вы находитесь на своем пути. Вам нужно будет потратить некоторое время и понять больше того, что происходит в вашем собственном коде, иначе ваши шансы заставить его работать по своему желанию довольно удалены. Независимо от того, используете ли вы мой код, не можете ли вы набирать баллы 1-4, то вы в значительной степени ослепляете. Я предлагаю вам использовать время, которое вы потратили на игру * Подключить хвост на осле *, а вместо этого использовать его для обучения; вы получите там быстрее ** и ** имейте больше, чтобы показать это. – user1433150

 Смежные вопросы

  • Нет связанных вопросов^_^