My objective
To add a number of columns to a MySQL table. I have two concerns:
1) How to do this
2) Is this a bad idea, and if so why?
My reason for wanting to do this:
I have a form with a systematically named set of fields (e.g. field_1 field_2 etc). I want to post that data to a page and have it store it the mysql table, and I would like the fields to enter columns of a corresponding name (i.e. columns are named field_1 field_2 etc)
Rather than manually creating a column for each field name manually, it seemed obvious to loop the task.
However, research here and here seems tells me this approach illicits horror from people, and I found no actual solutions.
My attempt:
$mysqli = new mysqli("localhost","user","password","db");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$i = 1;
while ($i <= 14)
{
$column = 'field_'.$i;
$sql= '"ALTER TABLE supply ADD '.$column.' VARCHAR(45)"';
$mysqli->query($sql);
printf("Affected rows (ALTER): %d\n", $mysqli->affected_rows);
$i++;
}
This seems to run without error, however the affected rows message gives me (per loop, so 14 of these):
Affected rows (ALTER): -1
and the columns are not being added.
Can anyone advise me of my error, or a better way to debug what is going wrong? Additionally if this is an unwise thing to be doing could could you explain why and what I should consider doing instead? Thank you.
Thats because affected_rows are set when you use only statements:
INSERT
UPDATE
REPLACE
DELETE
which work with rows, with data inside your table.
When you use ALTER your result should be true or false, because you do not work with data, you just edit the structure of your table.
$result = $mysqli->query($sql) ;
if ($result){
echo "Table is updated. New column {$column} added" ;
}
Also, the correct SQL here would be:
$sql = "ALTER TABLE supply ADD {$column} VARCHAR(45) ; " ;
Related
I have the below code, which works perfect. What i want to do is to check the refNo first to see if there are duplicates entries in MySQL. If there is then appear a warning message, otherwise appear a "ok" message. How can i do that with PDO? Any help?
(include("db.php"));
$SQLquery = "INSERT INTO mydatabase (refNo, name)
VALUES ('".$_POST["refNo"]."', '".$_POST["name"]."');";
$STH = $dbc->query($SQLquery);
?>
edit: Hello guys,
i prefer not to add primary keys. Is there any other way?
Set up refNo as a primary key. You could also create it as unique but that defeats the purpose - your reference number appears to be a unique primary identifier. Perfect choice for a primary key.
Further, change your query
try {
$SQLquery = "INSERT INTO mydatabase (refNo, name) VALUES (:refNo, :name)";
$SQLquery = $dbc->prepare($SQLquery);
$SQLquery->bindValue(':refNo', $_POST['refNo']);
$SQLquery->bindValue(':name', $_POST['name']);
$SQLquery->execute();
} catch (Exception $e) {
die("Insert error");
}
$count = $SQLquery->rowCount();
if ($count == 1) {
echo "Record added!";
}
This binds the post value to prevent SQL injection too.
Edit: You could follow this up with $count = $SQLquery->rowCount(); which will be 1 if the insert was successful, as it appears you've edited your question since you posted it for more info.
If you want to do this without using a database level constraint, you'll need to do an extra SELECT statement before inserting into the table. But that gives you no absolute guarantees, as it might be two processes want to insert the same row at the same time and they will still succeed.
-- it'll look a little something like this; I'm not familiar with PDO but the structure should be the same
$selectQuery = "SELECT * FROM mydatabase
WHERE refno = '".$_POST["refNo"]."'";
$res = $dbc->query( $selectQuery );
if( $res->count() > 0 ) {
// this result already exists; show error
}
else {
// this result is new; put the insert query here
}
I cant quite think about how to do this with mysql and php. Basically I want to be able to submit data into a mysql database but before it is inserted, it will check to see if that entry already exists.
$guid=$_POST['guid'];
$name=$_POST['name'];
//Username
$user="webhost";
//Password
$pass="*******";
//IP To Host
$ip="***********";
//Database
$db="dayz2";
//Table
$table="whitelist";
//Database Connection
$con=#mysql_connect("$ip", "$user", "$pass")
or die(mysql_error());
//Select Database
$dbcon=#mysql_select_db($db, $con)
or die(mysql_error());
$dupesql = "SELECT * FROM $table where (name = '$name' AND guid = '$guid')";
$duperaw = mysql_query($dupesql);
if (mysql_num_rows($duberaw) > 0) {
echo "Entry Already Exists";
}
else {
//Query Data Into Whitelist Table
$sql="INSERT INTO $table (name, guid) VALUES ('$name', '$guid')";
//Submit Data into Whitelist Table
$result=#mysql_query($sql, $con) or die(mysql_error());
}
?>
You can do it in another way, instead of:
submit data into a mysql database but before it is inserted, it will
check to see if that entry already exists.
You can do:
INSERT data into a mysql database if not existed, else ignore them
Something like :
INSERT IGNORE INTO table
INSERT IGNORE INTO yourtablename
SET fieldname = 'blah'
,..
It depends what you are trying to do - what is the exact criteria for your query?
You have several options:
use INSERT IGNORE ... if you only want to insert new rows that don't have a duplicate primary key. See http://dev.mysql.com/doc/refman/5.5/en/insert.html.
use INSERT ... ON DUPLICATE KEY UPDATE to insert new rows and update rows where there is a primary key match.
See http://dev.mysql.com/doc/refman/5.5/en/insert-on-duplicate.html.
use a normal SQL SELECT ... to pull the results first before performing business logic on the results before deciding which to INSERT ... or UPDATE ... depending on your requirements.
It depends how you want to handle case when the entry exists.
I you want to throw some error then you can create table trigger for insert event and put some checks there, but it will be slow because every insert will do this check.
I don't know if it can be done with just a sql query or it needs a php code
when a cid is missing
There exist many missing values which I can't handle manually
For example, here I don't have cid=1 and cid=6.
I want to insert a row:
cid=1 tcp_sport='undefined' tcp_dport='undefined'
and
cid=6 tcp_sport='undefined' tcp_dport='undefined'
It seems to me I should create a procedure and insert between lines
another solution that I thaught was that I will create a table with cid and undifined values with the respective order and then join this one with that one and this join should have for example ifnull(tcp_sport,'')
would you please help me?
First, use MAX for get the largest ID.
SELECT MAX(cid) as max FROM table
Then, create a for loop for checking if the individual IDs exist:
for ($i = 0; $i < $max; $i++) {
// $query = ... SELECT 1 FROM table WHERE cid = $i ...
// check if the number of rows for $query is greater than 0
// if not, INSERT INTO table VALUES ($i, DEFAULT, DEFAULT)
}
The whole idea of an auto increment ID is to have a value that only refers to one thing ever. By "inserting between the lines" you may be opening yourself up to a lot of unforeseen problems. Image you have another table that has some values that link to the CID of this table. What if that table already has an entry for CID=1, When you insert a new item with CID=1 it will then join to that supporting record. So Data that really belongs to the original item with CID=1 will show for the new item which it probably has nothing to do with.
You aren't going to run out of ID values (if you are approaching the limit of integer, switch it to bigInt), don't re-use IDs if you can avoid it.
You need to use PHP to automate this.
<?php
$link = mysql_connect("localhost", "mysql_user", "mysql_password");
mysql_select_db("database", $link);
while($i < max_value_cid)//replace max_value_cid by the numeric maximum value of cid (SELECT MAX(cid) as max FROM table)
{
$result = mysql_query("SELECT * FROM `table` WHERE cid=".$i, $link);
if(mysql_num_rows($result) == 0)
mysql_query("INSERT INTO `table` VALUES ($i, NULL, NULL);", $link);
$i++;
}
?>
Do test the query on a sample set before execution and remember to backup the entire table, just-in-case.
I'm new to php. So, please forgive me if this seems like a dumb question.
Say i have a MySQL insert statement insert into table (a,b) values (1,2),(3,4),(5,6). table 'table' has a auto increment field called 'id'.
how can I retrieve all the ids created by the insert statement above?
It will be great if i get an example that uses mysqli.
You can't. I would suggest that you maintain your own ids (using guid or your own auto-increment table) and use it when you insert into the table.
But it's possible to get the auto-increment value for the last inserted using LAST_INSERT_ID():
http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
AngeDeLaMort's answer is almost right. Certainly, the most appropriate way to deal with the problem is to insert one row at a time and poll the insert_id or generate the sequence elsewhere (which has additional benefits in terms of scalability).
I'd advise strongly against trying to determine the last insert_id and comparing this the most recent insert_id after the insert - there's just too may ways this will fail.
But...an alternative approach would be:
....
"INSERT INTO destn (id, data, other, trans_ref)
SELECT id, data, other, connection_id() FROM source";
....
"SELECT id FROM destn WHERE trans_ref=connection_id()";
....
"UPDATE destn SET trans_ref=NULL where trans_ref=connection_id()";
The second query will return the ids generated (note that this assumes that you use the same connection for all 3 queries). The third query is necessary because connection ids to go back into the pool when you disconnect (i.e. are reused).
C.
In some cases, if you have another identifier of sort such as a UserID, you could filter your query by UniqueID's greater than or equal to mysql_insert_id(), limit by the number of affected rows and only display those by the user. This would really only work inside of a transaction.
$SQL = "INSERT INTO Table
(UserID, Data)
VALUES
(1,'Foo'),
(1,'Bar'),
(1,'FooBar')";
$Result = mysql_query($SQL);
$LastID = mysql_insert_id();
$RowsAffected = mysql_affected_rows();
$IDSQL = "SELECT RecordID
FROM Table
WHERE UserID = 1
AND RecordID >= '$LastID'
LIMIT '$RowsAffected'";
$IDResult = mysql_query($IDSQL);
as a follow up to AngeDeLaMort:
You could seperate your inserts and do it something like this:
$data = array (
array(1,2),
array(3,4),
array(5,6)
);
$ids = array();
foreach ($data as $item) {
$sql = 'insert into table (a,b) values ('.$item[0].','.$item[1].')';
mysql_query ($sql);
$id[] = mysql_insert_id();
}
Now all your new id's are in the $id array.
Maybe I can do this
$insert = "insert into table (a,b) values (1,2),(3,4),(5,6)";
$mysqli->query($insert);
$rows_to_be_inserted=3;
$inserted_id = $mysqli->insert_id // gives me the id of the first row in my list
$last_row_id = ($inserted_id+$rows_to_be_inserted)-1;
$mysql->query("select * from table where id between $inserted_id and $last_row_id");
what to you guys say?
I have a scripts that retrieves huge data on a table. I want to create a mysqldump to insert data into another database table with different fields. I want the format of phpMyAdmin where it repeats the INSERT INTO Table VALUES(values1),(values2), ...(values100); if reaches certain amount of value sets depends on what you set.
ex: If I have 550 data sets and i want to be devided the data by 100 so that i will have 6 sets of INSERT INTO query.
INSERT INTO tablename VALUES(value1), (value2), .... (value100);
INSERT INTO tablename VALUES(value101), (value102), .... (value200);
INSERT INTO tablename VALUES(value201), (value202), .... (value300);
INSERT INTO tablename VALUES(value301), (value302), .... (value400);
INSERT INTO tablename VALUES(value401), (value402), .... (value500);
INSERT INTO tablename VALUES(value501), (value502), .... (value550);
If you're using mysqldump and wish to output mutiple rows into a single insert, then you need to use the --extended-insert option:
mysqldump extended insert option
I'm not sure it's possible to specify with mysqldump to specify that a specific number of rows are included in each INSERT statement generated in the dump. Rather you can set the net_buffer_length (although it's not recommended that you do change it), so the actual amount may vary depending on the data in each row.
You could use array_chunk(), something like:
$toInsert = array( '(values1)', '(values2)', '(values3)', '(values4)' ); //etc.
$sqlStart = 'INSERT INTO tablename (field1, field2, field3, etc) VALUES ';
foreach (array_chunk($toInsert, 100) as $insertSet) {
$sql = $sqlStart . implode(', ', $insertSet);
//execute $sql
}
Are you actually doing much with the data though? You might be able to do it all in SQL with INSERT INTO table (field1, field2) SELECT somefield, somefield2 FROM another table
While fetching the rows, increment a counter, and when it hits a certain value, have it create a new insert statement?
Some code that might not be correct (no PHP for a LONG time), but you will probably get the idea
$i = 0;
$insertstatements = array();
$currentinsertstatement;
while ($temp = mysql_fetch_assoc($result)) {
// do something with the data
$insertpart = "(value_xxx)";
if ($i % 100 == 0) {
// first value
if ($i != 0) $insertstatements[count($insertstatements)] = $currentinsertstatement;
$currentinsertstatement = "INSERT INTO tablename VALUES " . $insertpart;
} else {
$currentinsertstatement .= ", " . $insertpart;
// somewhere in the middle of the insert statement
}
$i++;
}
if ($i % 100 != 0) {
$insertstatements[count($insertstatements] = $currentinsertstatement;
}
You definitely should use transactions for huge inserts, if your storage engine supports them (like innoDB):
BEGIN;
INSERT INTO tablename VALUES...
INSERT INTO tablename VALUES...
COMMIT;
If something goes wrong, you can safely ROLLBACK the last operation, restart you script, etc.