I'm developing a PHP web app using a MySQL database.
I'm wondering what is the best way to find out what primary key (or any other autoincrement field) did a row receive after insertion.
Something that returns the full row as a result is also pretty good, since I also wanted to know about default values assigned to fields I didn't explicitly set.
All help is appreciated.
-- edit
So, I'm using an in-house framework that abstracts away the actual database functions, so I can't use the connection-specific "mysql_last_insert_id", and the "select last_insert_id" query, AFAIK, would be affected by other database connections, especially considering that the framework I'm using opens new connections for every query.
Guess this is a framework problem and you can't help me. If INSERT INTO had a "return inserted rows" mode, though, that would be nice.
MySQL provides a convenient way to answer this exact question:
mysql> SELECT LAST_INSERT_ID()
The mysql_* functions come with a wrapper for that: check mysql_insert_id
The mysql driver for PDO gives the same:
$pdo->exec('insert into ...');
$lastId = $pdo->lastInsertId();
Try this
MySQL CODE:
CREATE TABLE IF NOT EXISTS `mytable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`member` int(11) NOT NULL,
`update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`created` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
SHOW:
AUTO_INCREMENT
MySQL Insert:
INSERT INTO mytable (`id`,`name`,`update`,`created`) values (NULL,'TEST',NOW(),NOW());
OR
INSERT INTO mytable (`name`,`update`,`created`) values ('TEST',NOW(),NOW());
OR
INSERT INTO mytable (`name`,`created`) values ('TEST',NOW());
PHP MySQL Code:
<?php
$foo = 'test';
mysql_query("INSERT INTO mytable (`name`,`created`) values ('".mysql_real_escape_string( $foo )."',NOW())");
// GET LAST ID
$id = mysql_insert_id();
?>
In PHP use MYSQL_REAL_ESCAPE_STRING
mysql_real_escape_string( string )
See this doc mysql_real_escape_string
Bye!!
If you're using mysql_* functions, then you can simply use mysql_insert_id(). If you want the values of default rows, you'll have to select them using the key.
Related
I have created a web you can upload and download files - everything works perfect. But now, I want to create a init file, that delete old records in database and create a new tables in it.
So I write this:
$command = "
IF OBJECT_ID(`".$database.".Users`) IS NOT NULL
DROP TABLE ".$database.".Users;
IF OBJECT_ID(`".$database.".Uploads`) IS NOT NULL
DROP TABLE ".$database.".Uploads;
CREATE TABLE `Users` (
`Id` int(11) NOT NULL,
`User` text NOT NULL,
`Password` text NOT NULL,
`Permission` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
ALTER TABLE `Users` ADD PRIMARY KEY (`Id`);
ALTER TABLE `Users` MODIFY `Id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=0;
CREATE TABLE `Uploads` (
`Id` int(11) NOT NULL,
`Name` text NOT NULL,
`User` text NOT NULL,
`Comment` text NOT NULL,
`Path` text NOT NULL,
`Permission` int(11) NOT NULL,
`Date` text NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
ALTER TABLE `Uploads` ADD PRIMARY KEY (`Id`);
ALTER TABLE `Uploads` MODIFY `Id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=0;
";
$result = mysqli_query($conn, $command) or die(mysqli_error($conn));
I think, that code is right (but obviously not). When I run it, SQL throws an error:
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'IF OBJECT_ID(db.Users) IS NOT NULL DROP TABLE db.User' at line 1**.
This means that it don’t have a problem with connection to SQL database.
I tried instead of IF OBJECT_ID use IF NOT EXISTS, but it doesn't works too. Can anybody tell me if multi-line SQL command is this problem or if it is something else?
Note: I use 5.5.37 version of MariaDB (if it helps)
IF is not a valid SQL statement in MySQL / MariaDB.
The IF OBJECT_ID(...) statement in the question appears to be a Transact-SQL (Microsoft SQL Server) construct.
The equivalent functionality in MySQL would be achieved with
DROP TABLE IF EXISTS foo.mytable ;
(I expect this would work in MariaDB 5.5, but I haven't verified.)
Note that if the table doesn't exist, the execution of the statement will raise a warning. (A warning message, not an error message.)
The mysqli_query function runs a single statement. To run multiple statements, we can use mysqli_multi_query function, documented here:
http://php.net/manual/en/mysqli.multi-query.php
As far as concerns, OBJECT_ID does not exist in mysql, only in mssql. Searching for OBJECT_ID mysql 8.0 reference manual does not retun anything meaningful. Even if it existed, your syntax for IF block does not look good : you want IF...THEN...END.
To fix the error, you can replace this :
IF OBJECT_ID(`".$database.".Users`) IS NOT NULL
DROP TABLE ".$database.".Users;
IF OBJECT_ID(`".$database.".Uploads`) IS NOT NULL
DROP TABLE ".$database.".Uploads;
With :
DROP TABLE IF EXISTS ".$database.".Users;
DROP TABLE IF EXISTS ".$database.".Uploads;
never used OBJECT_ID but what you want seem to be easily doable with
"drop table if exists users;"
I'm currently trying to create a logparser for Call of Duty 4. The parser itself is in php and reads through every line of the logfile for a specific server, and writes all the statistics to a database with mysqli. The databases are already in place and I'm fairly certain (with my limited experience) that they're well-organized. However, I'm not sure in what way I should send the update/insert queries to the database, or rather, which way is optimal.
My databases are structured as follows
-- --------------------------------------------------------
--
-- Table structure for table `servers`
--
CREATE TABLE IF NOT EXISTS `servers` (
`server_id` tinyint(3) unsigned NOT NULL auto_increment,
`servernr` smallint(1) unsigned NOT NULL default '0',
`name` varchar(30) NOT NULL default '',
`gametype` varchar(8) NOT NULL default '',
PRIMARY KEY (`server_id`),
UNIQUE KEY (`servernr`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-- --------------------------------------------------------
--
-- Table structure for table `players`
--
CREATE TABLE IF NOT EXISTS `players` (
`player_id` tinyint(3) unsigned NOT NULL auto_increment,
`guid` varchar(8) NOT NULL default '0',
`fixed_name` varchar(30) NOT NULL default '',
`hide` smallint(1) NOT NULL default '0',
PRIMARY KEY (`player_id`),
UNIQUE KEY (`guid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
-- --------------------------------------------------------
--
-- Table structure for table `playerstats`
--
CREATE TABLE IF NOT EXISTS `playerstats` (
`pid` mediumint(9) unsigned NOT NULL auto_increment,
`guid` varchar(8) NOT NULL default '0',
`servernr` smallint(1) unsigned NOT NULL default '0',
`kills` mediumint(8) unsigned NOT NULL default '0',
`deaths` mediumint(8) unsigned NOT NULL default '0',
# And more stats...
PRIMARY KEY (`pid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
In short, servers and players contain unique entities, and they are combined in playerstats (i.e. statistics for a player in a specific server). In addition to the stats, they are also given a player id (pid) for use in later databases. Similarly, the database contains the tables weapons (unique weapons) and weaponstats (statistics for a weapon in a server), attachments and attachstats, and maps and mapstats. Once I get all of this working, I would like to implement more relations between these stats (i.e. a player's stats for a specific weapon in a specific server, using pid and wid).
The PHP parser copies the log of each server (there are 6 atm) over http and then reads through them every 5 minutes (I'm not too sure on that yet). One can assume that during this parsing, every table has to be queried (either with UPDATE or INSERT) at least once (and probably alot more). Right now, I have a number of options on how to send queries (that I know of):
1: Use regular queries, i.e.
$statdb = new mysqli($sqlserver,$user,$pw, $db);
foreach( $playerlist as $guid => $data ){
$query = 'INSERT INTO `playerstats`
VALUES (NULL, '$guid', $servernr, $data[0], $data[1])';
$statdb->query($query);
}
2: Use multi query
$statdb = new mysqli($sqlserver,$user,$pw, $db);
foreach( $playerlist as $guid => $data ){
$query = "INSERT INTO `playerstats`
VALUES (NULL, '$guid', $servernr, $data[0], $data[1]);";
$totalquery .= $query;
}
$statdb->multi_query($totalquery);
3: Use prepared statements; I haven't actually tried this yet. It seems like a good idea, but then I have to make a prepared statement for every table (I think). Will that even be possible, and if so, will it be efficient?
4: As you might be able to see from the aforementioned code, I initially count all the statistics for each player,weapon,map, etc. into an array. Once the parser has read through the entire file, it sends a query with those accumulated stats to the mysql server. However, I have also seen (more often then not) in other logparsers, that queries are being sent whenever a new line of the logfile has been parsed, so something like:
UPDATE playerstats
SET kills = kills+1
WHERE guid = $guid
It doesn't seem very efficient to me, but then again I'm just starting out with both php and sql so what do I know :>
So, in short; what would be the most efficient way to query the database, considering that the logparser reads through every line one by one? Of course, any other advice or suggestion is always welcome.
.5. create a single multi-insert query using mysql's support for the queries like
INSERT INTO table (fields) VALUES(data),VALUES(data)...
It seems most efficient of them all, including prepared statements
The most efficient way to me would be to scan the server every so often, once every 5 minutes or so, then scan the list of stats into an array (e.g. in 5 mins 38 people have been on the server so you have an array of 38 IDs, each with the accumulated stats changes of those 38 IDs that need to be updated in the server). Run one query to check to see if a user has an existing ID in stats, and then 2 more queries, one to create new users (multi query insert) and one to update users (single query with CASE update). That limits you to 3 queries every 5 minutes.
I have a simple table
CREATE TABLE `keys` (
`IDkey` int NOT NULL auto_increment,
`username` varchar(50) NOT NULL,
PRIMARY KEY (`IDkey`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
and give out incrementing integer keys 'IDkey' to users as they call in with my webapp. I also store their username in the table.
I have two questions I'm stuck on.
First question: at the moment I am doing the following to give out the key, is there a way to combine this into one query?
INSERT INTO keys VALUES (NULL, '$username');
SELECT IDkey FROM keys WHERE username='$username';
Second Question: the key expires so the same user may return for a new key but this causes a problem because their username is already in the database. Is there a way to write my SELECT query so it returns the most recent record by that user?
If you're using PDO, check out PDO::lastInsertId().
If you're using mysqli, check out mysqli::$insert_id.
If you're using mysql, upgrade your code to use PDO or mysqli. ;-) (But seriously, you can do this with mysql_insert_id()).
Immediately call this function mysql_insert_id() after you insert this record. It will give you the id of last inserted record.
Trying to make insert or update sql using the prepared statements from php's pdo. First I thought of using REPLACE INTO command,but it gives me an error because I have a foreign key on my index. Read that I must use INSERT...ON DUPLICATE KEY UPDATE syntax to make it working, but it's not clear for me how to do that with prepared statements. Any solution for this? Thanks.
The sql is :
$sql="REPLACE INTO fn_currencies(id,short,name,buy,sell,date) VALUES (:id,:short,:name,:buy,:sell,:update)";
UPD: I am making this query in Yii that uses personal wrapper over the PDO.
When I use unnamed parameters I get this type of error:
CDbCommand failed to execute the SQL statement: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens. The SQL statement executed was: INSERT INTO `fn_currencies` (id,short,name,buy,sell,date) VALUES (?,?,?,?,?,?) ON DUPLICATE KEY UPDATE id=?,short=?,name=?,buy=?,sell=?,date=?
When I use the named parameters with differed names for Insert and Update as was mentioned..I get no errors and neither data is inserted in my DB.
Here is the schema for the DB:
CREATE TABLE IF NOT EXISTS `fn_currencies` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`short` varchar(4) NOT NULL,
`name` varchar(200) NOT NULL,
`buy` decimal(10,4) NOT NULL,
`sell` decimal(10,4) NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
--
ALTER TABLE `fn_currencies`
ADD CONSTRAINT `FK_fn_currencies` FOREIGN KEY (`id`) REFERENCES `fn_operations` (`currency_id`);
Thanks to DavaRandom, he pointed out an error in my code, but this should do the trick. Replace the named parameter with ? and use an array merge to make the SQL on the fly like this:
$sql="
insert INTO fn_currencies(id,short,name,buy,sell,date)
VALUES (?,?,?,?,?,?)
on duplicate key update currencies set
short=?, name=?, buy=?, sell=?, update=?";
$values=array("id"=>1, "short"=>36, "name"=>'Bazinga', "sell"=>3.67, "date"=>'2012-08-08');
$db->query($sql, array_merge(array_values($values),array_values($values)));
Apparently this will also work (See comments all over the page about yes/no/maybe) but the above will certainly work:
$sql="
insert INTO fn_currencies(id,short,name,buy,sell,date)
VALUES (:id,:short,:name,:buy,:sell,:update)
on duplicate key update currencies set
short=:short, name=:name, buy=:buy, sell=:Sell, update=:update";
Really simple question. I forgot how to deal with this specific script. With a PHP file I create tables in mysql database. I have $query variable with the following commands:
$query = "CREATE TABLE IF NOT EXISTS `table1` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`status` int(11) NOT NULL
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `table2` (
`something` varchar(100) NOT NULL,
`whatever` text NOT NULL
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
";
It works only if I exec one single command. When I run multiple CREATE / INSERT / DROP ... commands it doesn't work. For sure there's a mistake with the syntax maybe ; and ,.
mysql_query() doesn't support multiple statements in the same call.
http://php.net/manual/en/function.mysql-query.php
mysql_query() sends a unique query (multiple queries are not supported) to the currently active database on the server that's associated with the specified link_identifier.
You're problem doesn't comes from the SQL (well, I didn't checked it properly to be honest), but from mysql_query (assuming you're using it) : it does't allow multiple request.
http://php.net/manual/fr/function.mysql-query.php
As others have stated, the mysql_query() function doesn't support multiple queries in a single call.
On a somewhat related note, if you are able you should look into using mysql_i or PDO in place of the old mysql_*() functions, which are inferior for too many reasons to list here.
http://php.net/manual/en/book.mysqli.php
http://php.net/manual/en/book.pdo.php