mysql_query does not work partially when loading from sql file - php

I have dumped the contents of a database in an sql file in a form like
insert into `a` values
(17,11,5),
(18,12,7),
(19,12,10),
(21,14,45),
(22,15,46),
(24,16,46),
(25,16,49),
(26,17,21),
(27,17,30),
(28,17,45),
(29,17,54),
(30,18,32),
(31,18,35),
(32,19,23),
(33,19,27),
(34,19,54),
(35,20,53),
(36,21,32),
(37,21,35),
(38,21,45),
(39,22,23),
(40,22,30),
(41,22,45),
(57,24,19),
(58,25,46),
(59,26,39),
(60,27,49),
(61,27,56),
(62,28,34);
insert into `b` values (14,'2009-01-06',''),
(15,'2009-02-01',''),
(16,'2009-03-01',''),
(17,'2009-03-25',''),
(18,'2009-04-05',''),
(19,'2009-04-17',''),
(20,'2009-04-18',''),
(21,'2009-04-19',''),
(22,'2009-04-23',''),
(24,'2009-07-05',''),
(25,'2009-08-02',''),
(26,'2009-08-07',''),
(27,'2009-09-06',''),
(28,'2009-09-14','');
etc..
I have 4 such tables with no foreigh key constrains. Then I try to upload the data into the db (mysql). I read the file's contents, I pass each table's insertion into an array and then i do mysql_query for each element :
$sqlArray = explode(';',$sqlFile);
for($i=0;$i<sizeof($sqlArray);$i++){
mysql_query($sqlArray[$i]) or die ('Error: '.mysql_error());;
}
The result is that the last three tables are inserted but the first one is not, and the error is :
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' insert into `a` values (17,11,5), (18,12,7), (19,12,10), (21,14,4' at line 1
I validated that the $sqlArray has the correct contains and the queries are correct and runnable from phpmyadmin.
The problem seems to be regardless of the first table (i.e. it will show up even if b was first) and it always seems to "cut" the query in the middle (or after almost 70 characters).
Any help will be appreciated!

Your second statement has a typo ("int" should be "into"):
insert int `b` values (14,'2009-01-06',''),
Alternately, if that's not the issue, try using separate insert statements to get a clearer error message:
insert into `a` values (17,11,5);
insert into `a` values (118,12,7);
...
I have experienced on some older versions of MySQL that they don't like the extended inserts. You can also try specifying the column names explicitly with the real names of your columns. This would be useful if you have more than 3 columns in those tables (an auto-increment column for example).
insert into `a` (`[column1name]`, `[column2name]`, `[column3name]`) values (17,11,5);

Related

"Unknown column in 'field list'" when prepared statement's placeholder is in subquery

I'm using PHP 5.5.9 and MySQL 5.5.44 with mysqlnd 5.0.11-dev on Ubuntu 14.04 LTS. The following statement fails to prepare:
$db->prepare("SELECT nr.x FROM (SELECT ? AS x) AS nr")
This is despite the fact that the following statement prepares successfully:
$db->prepare("SELECT nr.x FROM (SELECT '1337' AS x) AS nr")
What causes this difference? The manual says "Parameter markers can be used only where data values should appear, not for SQL keywords, identifiers, and so forth." But this is for a data value.
Not PDO's fault
The same thing happens in the stand-alone client:
mysql -uredacted -predacted redacted
-- Type 'help;' or '\h' for help.
SELECT nr.x FROM (SELECT '1337' AS x) AS nr;
-- x
-- 1337
-- 1 row in set (0.00 sec)
PREPARE workingstmt FROM 'SELECT nr.x FROM (SELECT ''1337'' AS x) AS nr';
-- Query OK, 0 rows affected (0.00 sec)
-- Statement prepared
DEALLOCATE PREPARE workingstmt;
-- Query OK, 0 rows affected (0.00 sec)
PREPARE brokenstmt FROM 'SELECT nr.x FROM (SELECT ? AS x) AS nr';
-- ERROR 1054 (42S22): Unknown column 'nr.x' in 'field list'
^D
-- Bye
My motivation
I'm trying to add a row to a table that has an auto-incrementing primary key. In InnoDB's default auto-increment locking mode, which the manual calls "consecutive", InnoDB skips an auto-increment value when a row might be inserted but is not, as is the case with INSERT IGNORE or ON DUPLICATE KEY UPDATE that runs into an existing row whose UNIQUE values match those of the row being inserted. (These are called "mixed-mode inserts" in the manual.)
Every few hours, I import a feed from my supplier. This has about 200,000 rows, and all but on average 200 of these rows have unique values that correspond to values already present in the table. So if I were to use INSERT IGNORE or ON DUPLICATE KEY UPDATE all the time, I'd burn through 199,800 IDs every few hours. So I don't want to use INSERT IGNORE or ON DUPLICATE KEY UPDATE for fear that I might exhaust the 4.2 billion limit of INTEGER UNSIGNED with repeated inserts over time to a table with the same UNIQUE key. I don't want to switch the column to BIGINT type because 32-bit PHP has no type with the same semantics as MySQL BIGINT. The server administrator is unwilling to switch to 64-bit PHP or to change innodb_autoinc_lock_mode for all users of the server.
So instead, I decided to try INSERT INTO ... SELECT, creating a 1-row table with the unique key columns in a subquery and left joining it to the main table to reject unique key values that already exist. (The manual says INSERT INTO ... SELECT is a "bulk insert", which does not burn IDs.) The intent is to do something like this:
INSERT INTO the_table
(uniquecol, othercol1, othercol2)
SELECT nr.uniquecol, :o1 AS othercol1, :o2 AS othercol2
FROM (
SELECT ? AS uniquecol
) AS nr
LEFT JOIN the_table ON nr.settlement_id = the_table.settlement_id
WHERE the_table.row_id IS NULL
This failed, giving the PDO error:
["42S22",1054,"Unknown column 'settlement_id' in 'field list'"]
<?php // MCVE follows
/* Connect to database */
$pdo_dsn = 'mysql:host=127.0.0.1;dbname=redacted';
$pdo_username = 'redacted';
$pdo_password = 'redacted';
$pdo_options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',];
$db = new PDO($pdo_dsn, $pdo_username, $pdo_password, $pdo_options);
$pdo_dsn = $pdo_username = $pdo_password = 'try harder';
// ensure that PDO doesn't convert everything to strings
// per http://stackoverflow.com/a/15592818/2738262
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
/* Create mock data with which to test the statements */
$prep_stmts = ["
CREATE TEMPORARY TABLE sotemp (
file_id INTEGER UNSIGNED PRIMARY KEY AUTO_INCREMENT,
settlement_id VARCHAR(30) NOT NULL,
num_lines INTEGER UNSIGNED NOT NULL DEFAULT 0,
UNIQUE (settlement_id)
)
","
INSERT INTO sotemp (settlement_id, num_lines) VALUES
('15A1', 150),
('15A2', 273),
('15A3', 201)
"];
foreach ($prep_stmts as $stmt) $db->exec($stmt);
/* Now the tests */
$working_stmt = $db->prepare("
SELECT nr.settlement_id
FROM (
-- change this to either a value in sotemp or one not in sotemp
-- and re-run the test program
SELECT '15A3' AS settlement_id
) AS nr
LEFT JOIN sotemp ON nr.settlement_id = sotemp.settlement_id
WHERE sotemp.file_id IS NULL
");
if ($working_stmt) {
$working_stmt->execute();
$data = $working_stmt->fetchAll(PDO::FETCH_ASSOC);
echo "Working: ".json_encode($data)."\n";
} else {
echo "Working statement failed: ".json_encode($db->errorInfo())."\n";
}
$broken_stmt = $db->prepare("
SELECT nr.settlement_id
FROM (
SELECT ? AS settlement_id
) AS nr
LEFT JOIN sotemp ON nr.settlement_id = sotemp.settlement_id
WHERE sotemp.file_id IS NULL
");
if ($broken_stmt) {
$broken_stmt->execute(['15A4']);
$data = $broken_stmt->fetchAll(PDO::FETCH_ASSOC);
echo "Broken: ".json_encode($data)."\n";
} else {
echo "Broken statement failed: ".json_encode($db->errorInfo())."\n";
}
What is causing this error? And is there a better way to insert a row only if the primary key does not exist without exhausting auto-increment IDs?
Your latest edit made the question very clear, so I'll attempt an answer:
the cause of this difference is the placeholder.
As documented here, placeholders can only be used in certain places in the query. In particular:
Parameter markers can be used only where data values should appear, not for SQL keywords, identifiers, and so forth.
Now you might have noticed that SELECT ? as x prepares fine, but not SELECT nr.x FROM (SELECT ? AS x) AS nr. Why is that? Well this is best explained by an anonymous author on PHP's doc, so let me copy/paste:
There is a common misconception about how the placeholders in prepared statements work: they are not simply substituted in as (escaped) strings, and the resulting SQL executed. Instead, a DBMS asked to "prepare" a statement comes up with a complete query plan for how it would execute that query, including which tables and indexes it would use, which will be the same regardless of how you fill in the placeholders.
So simply put: because you are using a placeholder in a subquery in the FROM clause, MySQL cannot calculate the execution plan of the query.
In other words, since your query will always change, there is not "template" that can be prepared for it.
Therefore if you really want to use this query, you need to use a normal (non-prepared) query, or turn back on PDO's emulated prepared statements.
That being said, please, do consider the various alternatives offered in the comments section. There are much better solutions for what you are trying to achieve.

INSERT only if both colomns are not duplicate

DELETE FROM RelationsAuthors WHERE MainId = :MainId AND AuthorId NOT IN (:authorarray)
The above code will delete anything that is not in authorarry and where MainId equals a specific value.
After the deletion I would like to insert the values of authoarray into the database if they do not exist without getting any errors.
*with using foreach $_POST['AuthorId']:
INSERT INTO RelationsAuthors (Id,MainId,AuthorId) VALUES('',:MainId,:AuthorId)
However I would like to add to my code that I need to INSERT only WHERE (MainId = :MainId AND AuthorId = :AuthorID) does not exist. How can I do that?
First, create a unique index on the two fields so the database will prevent duplicates for you:
create unique index idx_RelationsAuthors_MainId_AuthorId on RelationsAuthors(MainId, AuthorId);
Then the insert will fail with an error if you have duplicates. You can have this error ignored in a few ways. My preferred way is:
INSERT INTO RelationsAuthors (MainId, AuthorId)
VALUES(:MainId, :AuthorId)
ON DUPLICATE KEY UPDATE MainId = VALUES(MainId);
This will specifically ignore duplicate key errors, but other problems will still generate an error (if appropriate). Note I removed the first column. I'm guessing from the syntax that it is an auto-incremented id, so you don't need to include it in the insert statement at all.

Error in SQL syntax for INSERT INTO

I am trying to insert data into a MySQL table which contains 19 columns however not all the rows are being stored.
Only a few of the rows are being stored and I'm getting the error message:
There is error in your SQL syntax. Check your syntax for your SQL version.
Although when I echo the variables, they are working fine.
My code is as follows:
$sql="CREATE TABLE tb(tb1 VARCHAR(50),tb2 VARCHAR(50),tb3 VARCHAR(100),tb4 VARCHAR(100),tb5 VARCHAR(100),tb6
VARCHAR(100),tb7 VARCHAR(100),tb8 VARCHAR(100),tb9 VARCHAR(100),tb10 VARCHAR(100),tb11 VARCHAR(100),tb12
VARCHAR(100),tb13 VARCHAR(100),tb14 VARCHAR(100),tb15 VARCHAR(100),tb16 VARCHAR(100),tb17 VARCHAR(100),tb18
VARCHAR(100),tb19 VARCHAR(100))";
foreach ($xml->product as $character)
{
$a1=$character->category->primary;
$b2=$character->category->secondary;
$c3=$character->URl->product;
$d4=$character->URL->productImage;
$e5=$character->URL->buy;
$f6=$character->description->short;
$g7=$character->description->long;
$h8=$character->discount->amount;
$i9=$character->discount->time;
$j10=$character->price->sale;
$k11=$character->price->retail;
$l12=$character->brand;
$m13=$character->shipping->cost->amount;
$n14=$character->shipping->cost->currency;
$o15=$character->shipping->information;
$p16=$character->shipping->availability;
$q17=$character->keywords;
$r18=$character->upc;
$s19=$character->m1;
$sql="INSERT INTO tb
(tb1,tb2,tb3,tb4,tb5,tb6,tb7,tb8,tb9,tb10,tb11,tb12,tb13,tb14,tb15,tb16,tb17,tb18,tb19) VALUES
('$a1','$b2','$c3','$d4','$e5','$f6','$g7','$h8','$i9','$j10','$k11','$l12','$m13','$n14','$o15','$p16','$q17','$r18','$s19')";
mysql_query($sql,$conn);
}
If ANY of your values contains an apostrophe, your query breaks.
Use mysql_real_escape_string() around each of your values as a quick fix.
A more correct and future-proof solution is to stop using mysql_* functions and instead start using PDO, making use of features like prepared statements as these take care of escaping things for you.
This is a formatted comment. A frequent mistake with this type of query is that the number of fields does not match the number of values. That is easier to troubleshoot if you type your query like this:
insert into table (
field1
, field2
, etc
)
values (
value1
, value2
, etc
)
This format makes it easier to count the number of fields and values. Sometimes the problem is with a certain field or value. This format, with the commas at the start of the line, make it easier to comment out blocks of code to isolate the problem.

mysql: 1 INSERT INTO query two result

I have a table user (id VARCHAR(5), name VARCHAR(30))
I used INSERT INTO query in two way:
1) Directly:
...
$sql="INSERT INTO user (id,name) VALUES ('00001','abcd');
...
---> result: id(00001), name(abcd).
That's the right result.
2) By function:
function insert($id,$name)
{
$sql="INSERT INTO user (id,name) VALUES ($id,$name)";
....
}
I used this function with 2 kind of parameter
a)
insert('00001','00123');
---> result: id(1), name(123) (all zeros have been cut).
b)
insert('00001','abcd');
---> error: Unknown column 'abcd' in 'field list'.
I want to ask: why all the zeros have been cut, and why when I used a string value it make an error. How can I fix it to get right result by function.
Many thanks!
You never bothered quoting your values:
INSERT INTO user (id,name) VALUES ($id,$name)
^^^^^^^^^---here
So the query becomes
INSERT INTO user (id, name) VALUES (1, abcd)
Without the quotes, abcd is seen as a FIELD NAME, not a value. Since your table has no field named abcd, you get your error. Try:
INSERT INTO user (id,name) VALUES ($id, '$name')
as a short-term fix (note the ' quotes around $name). Long term fix: Start using prepared statements and/or placeholders, which eliminate the need for this kind of quoting.

entering datas of php page to database

I have a php form with two text boxes and i want to enter the text box values into the database. I have created the table (with two columns namely webmeasurementsuite id and webmeasurements id) I used the following syntax for creating table:
CREATE TABLE `radio` (
`webmeasurementsuite id` INT NOT NULL,
`webmeasurements id` INT NOT NULL
);
Utilising the tutorial in the following link, I wrote the php coding but unfortunately the datas are not getting entered into the database. I am getting an error in the insert sql syntax. I checked it but i am not able to trace out the error.Can anyone correct me? I got the coding from http://www.webune.com/forums/php-how-to-enter-data-into-database-with-php-scripts.html
$sql = "INSERT INTO $db_table(webmeasurementsuite id,webmeasurements id) values
('".mysql_real_escape_string(stripslashes($_REQUEST['webmeasurementsuite
id']))."','".mysql_real_escape_string(stripslashes($_REQUEST['webmeasurements id']))."')";
echo$sql;
My error is as follows:
INSERT INTO radio(webmeasurementsuite id,webmeasurements id) values ('','')ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'id,webmeasurements id) values ('','')' at line 1
Because your table names have a space in them, you have to always surround them in backticks. Try this for your query:
$sql = "INSERT INTO $db_table(`webmeasurementsuite id`,`webmeasurements id`) values ('".mysql_real_escape_string(stripslashes($_REQUEST['webmeasurementsuite id']))."','".mysql_real_escape_string(stripslashes($_REQUEST['webmeasurements id']))."')";
Looking at your pastebin, it looks like you have forgotten to close your input tags:
<input TYPE="text" name="webmeasurementsuite id"

Categories