mysql retrieve autoinc value for join insert - php

We have the following two tables:
CREATE TABLE IF NOT EXISTS `gp` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`amount` decimal(15,2) NOT NULL,
`user` varchar(100) NOT NULL DEFAULT '',
`status` tinyint(2) NOT NULL DEFAULT '1',
`ip` varchar(20) NOT NULL DEFAULT 'N/A',
`token` varchar(100) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;
CREATE TABLE IF NOT EXISTS `gp_logs` (
`id` int(11) NOT NULL,
`log` varchar(1000) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
We JOIN them, for statistics, but we do this rarely, since the data from the 2nd table is not used too often except when we need to verify things.
Considering that we have many queries per second, how can our query be optimized to use 1 INSERT query instead of two and to insert the correct id in the 2nd table (gp_logs) that was generated by the INSERT into table gp?
Right now, we do a combination of MYSQL with PHP:
mysqli_query($con,"INSERT INTO `gp` (amount,user) VALUES ('1234','1')");
$id = mysqli_insert_id($con);
mysqli_query($con,"INSERT INTO gp_logs(id,log) VALUES ('$id','some_data')");
We want to eliminate the requirement of PHP for getting the last inserted ID and to insert both entries by running a single INSERT query (with a JOIN).

Related

PHP SQL query slow?

Here is my function which i am using to un-follow users.It first DELETE the relationship between users and all the notifications that are related to this relationship.Then it INSERT a new notification for user which we are going to un-follow and then UPDATE his followers count (as one follower has left).I am using multi_query and this query seems to be bit slower on large database and i want to know whether it's a good practice or not or is there is any more complex form of query to get the job done.
PHP Function
// 'By' is the array that hold logged user and 'followed' is the user id which we are going to unfollow
function unFollowUser($followed,$by) {
$following = $this->getUserByID($followed);// Return fetch_assoc of user row
if(!empty($following['idu'])) { // if user exists
// return user followers as number of rows
$followers = $this->db->real_escape_string($this->numberFollowers($following['idu'])) - 1;
$followed_esc = $this->db->real_escape_string($following['idu']);
$by_user_esc = $this->db->real_escape_string($by['idu']);
// delete relationship
$query = "DELETE FROM `relationships` WHERE `relationships`.`user2` = '$followed_esc' AND `relationships`.`user1` = '$by_user_esc' ;" ;
// delete notification (user started following you )
$query.= "DELETE FROM `notifications` WHERE `notifications`.`not_from` = '$by_user_esc' AND `notifications`.`not_to` = '$followed_esc' ;" ;
// Insert a new notification( user has unfollowed you)
$query.= "INSERT INTO `notifications`(`id`, `not_from`, `not_to`, `not_content_id`,`not_content`,`not_type`,`not_read`, `not_time`) VALUES (NULL, '$by_user_esc', '$followed_esc', '0','0','5','0', CURRENT_TIMESTAMP) ;" ;
// update user followers (-1)
$query .= "UPDATE `users` SET `followers` = '$followers' WHERE `users`.`idu` = '$followed_esc' ;" ;
if($this->db->multi_query($query) === TRUE) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
}
Table structures
--
-- Table structure for table `notifications`
--
CREATE TABLE IF NOT EXISTS `notifications` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`not_from` int(11) NOT NULL,
`not_to` int(11) NOT NULL,
`not_content_id` int(11) NOT NULL,
`not_content` int(11) NOT NULL,
`not_type` int(11) NOT NULL,
`not_read` int(11) NOT NULL,
`not_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- Table structure for table `relationships`
--
CREATE TABLE IF NOT EXISTS `relationships` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user1` int(11) NOT NULL,
`user2` int(11) NOT NULL,
`status` int(11) NOT NULL,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
`idu` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL,
`password` varchar(256) NOT NULL,
`email` varchar(256) NOT NULL,
`first_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`last_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`verified` int(11) NOT NULL,
`posts` text CHARACTER SET utf32 NOT NULL,
`photos` text CHARACTER SET utf32 NOT NULL,
`followers` text CHARACTER SET utf32 NOT NULL,
UNIQUE KEY `id` (`idu`),
UNIQUE KEY `idu` (`idu`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
In my testing, multi_query has been the fastest way to execute multiple different queries. Why do you feel it's running slow? Compared to what?
Anyway, improvements could come from adding indexes to some of the columns you search frequently:
relationships.users2
relationships.users1
notifications.not_from
notifications.not_to
users.idu
Adding indexes makes searching faster, but it has at least two downsides:
Makes the DB a lot more resource hungry, which could affect your server performance
Makes writing operations take longer
I don't see any problem with your current queries. Really consider whether the slow performance you're seeing comes from the DB queries themselves, or from the rest of your PHP process. Try measuring the script time with the queries, then skipping the queries and taking another measurement (you could hardcode query results). It will give you an idea of whether the slowness is attributable to something else.
Either way, benchmark.
Try creating index on user where deletes are running , this may speed up query

Implicit MySQL Join on Update Statement - 0 rows affected

I'm trying to get this MySQL code to work, but it's saying 0 rows affected.
UPDATE assessments, assessment_types
SET assessments.assessment_type_id = assessment_types.id
WHERE (assessment_types.description = "Skills Assessment" AND assessments.id = 2);
Basically I have assessment_types with id and description column, and I just have the id in the assessments.assessment_type_id
I need to update the id.
I searched and couldn't find quite what I need for this.
Thanks!
Table Data:
assessment_types
id description
1 Knowledge Assessment
2 Skill Assessment
3 Personal Information
4 Natural Skills
Table Structure:
--
-- Table structure for table `assessments`
--
CREATE TABLE IF NOT EXISTS `assessments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_bin NOT NULL,
`acronym` varchar(255) COLLATE utf8_bin NOT NULL,
`assessment_type_id` int(11) NOT NULL,
`language_id` int(11) NOT NULL,
`date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`date_updated` date NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
KEY `assessment_type_id` (`assessment_type_id`),
KEY `language_id` (`language_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=2385 ;
--
-- Table structure for table `assessment_types`
--
CREATE TABLE IF NOT EXISTS `assessment_types` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`description` varchar(255) CHARACTER SET latin1 NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=7 ;
You can try doing an explicit join of the two tables in your UPDATE statement:
UPDATE assessments a
INNER JOIN assessment_types at
ON a.assessment_type_id = at.id
SET a.assessment_type_id = at.id
WHERE (at.description = "Skills Assessment" AND a.id = 2);

SQL/PHP - On key update

I have messed up my database design a bit. This was the original schema:
CREATE TABLE IF NOT EXISTS `xeon_stats_clicks` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`typ` enum('1','2','3','4','5','6','7','8','9') COLLATE utf8_bin NOT NULL,
`user` varchar(20) COLLATE utf8_bin NOT NULL,
`data` varchar(10) COLLATE utf8_bin NOT NULL,
`value` varchar(20) COLLATE utf8_bin NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `typ` (`typ`,`user`,`data`),
KEY `data` (`data`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1 ;
As you can see, I have KEY on the following:
UNIQUE KEY `typ` (`typ`,`user`,`data`),
KEY `data` (`data`)
I have the following code execute:
"INSERT INTO `xeon_stats_clicks` (typ, user, data, value) VALUES ('1', :username, :date, 1) ON DUPLICATE KEY UPDATE value = value + 1"
However, above code doesn't work now, as my table schema now look like this:
CREATE TABLE `xeon_stats_clicks` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`typ` enum('1','2','3','4','5','6','7','8','9') COLLATE utf8_bin NOT NULL,
`user` varchar(20) COLLATE utf8_bin NOT NULL,
`data` varchar(10) COLLATE utf8_bin NOT NULL,
`value` varchar(20) COLLATE utf8_bin NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `idx_value` (`value`),
KEY `idx_typ` (`typ`),
KEY `idx_data` (`data`),
KEY `idx_user` (`user`),
KEY `data` (`data`),
KEY `data_2` (`data`)
) ENGINE=MyISAM AUTO_INCREMENT=991799 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
How can I revert the changes made, and return to the first schema without messing up the data in the table?
I have no idea why your first schema + code doesn't work.
It works for value that is integer:
http://sqlfiddle.com/#!9/c3260/1
INSERT INTO `xeon_stats_clicks` (typ, user, data, value) VALUES
('2', 'user2', 'data3', 1) ON DUPLICATE KEY UPDATE `value` = `value` + 1
But if you will try on fiddle to apply that query to other lines it doesn't work. Because mysql can't convert VARCHAR to INT.
My guess you have wrong data in value column. For the combination of (typ, user, data, value) that you test.
UPDATE Here is the fiddle with your second schema in use:
http://sqlfiddle.com/#!9/5ea62b/1
As you can see your query works fine as well if you add
UNIQUE KEY `typ` (`typ`,`user`,`data`),
to that second schema.
and here is ALTER TABLE variant that works as well:
http://sqlfiddle.com/#!9/57b409/1
UPDATE 2 Another guess: You have broken uniqueness in your table now.
If I got you correctly you had
UNIQUE KEY `typ` (`typ`,`user`,`data`),
when start the project. After a while you did remove that UNIQUE KEY from schema. That change allowed mysql to insert duplicate records into that table. And apparently you inserted several (or a lot) of duplicates. And now you want to apply ALTER TABLE to get back unique key but mysql refuse that because of that.
Like here: http://sqlfiddle.com/#!9/4cbb5 <-- uncomment ALTER line to see error message
So you need to fix uniqueness first.
UPDATE 3 Delete duplicates:
http://sqlfiddle.com/#!9/85f228/1
DELETE FROM xeon_stats_clicks USING xeon_stats_clicks
INNER JOIN xeon_stats_clicks dup
ON xeon_stats_clicks.id < dup.id
AND xeon_stats_clicks.typ = dup.typ
AND xeon_stats_clicks.user = dup.user
AND xeon_stats_clicks.data = dup.data;

Migrate data from old table to new table query

Need a little help creating a query that takes the topic_title, and topic_content from mb_topics, and the post_content from the mb_posts table and then inserts the mb_topics.topic_title into the forum_topics.topic_title (table.field), mb_topics.topic_content and mb_posts.post_content into the forum_posts table.
Is it possible to use a single select query?
mb tables:
CREATE TABLE IF NOT EXISTS `mb_posts` (
`id` int(11) NOT NULL,
`posted_by` bigint(20) NOT NULL DEFAULT '0',
`topic_id` int(11) NOT NULL DEFAULT '0',
`post_content` text NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `mb_topics` (
`id` int(11) NOT NULL,
`topic_title` varchar(75) NOT NULL DEFAULT '',
`posted_by` bigint(20) NOT NULL DEFAULT '0',
`topic_content` text NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
forum tables:
CREATE TABLE IF NOT EXISTS `forum_posts` (
`post_id` int(11) NOT NULL AUTO_INCREMENT,
`post_content` text NOT NULL,
`post_date` datetime NOT NULL,
`post_topic` int(11) NOT NULL,
`post_by` int(11) unsigned NOT NULL
PRIMARY KEY (`post_id`),
KEY `post_topic` (`post_topic`),
KEY `post_by` (`post_by`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `forum_topics` (
`topic_id` int(11) NOT NULL AUTO_INCREMENT,
`topic_title` varchar(150) NOT NULL,
`topic_by` int(11) unsigned NOT NULL
PRIMARY KEY (`topic_id`),
KEY `topic_by` (`topic_by`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
PHP:
$get_old_data_query=mysql_query('SELECT `title`, `content` FROM `mb_topics`');
while($old_data=mysql_fetch_assoc($get_old_data_query))
{
$old_data_array[]=$old_data;
}
Something like this i guess would be ok?
<?php
$Old = mysql_query("SELECT * FROM Table WHERE Name = 'Name'");
while(mysql_fetch_array($Old)){
$Data = mysql_fetch_array($Old);
$Old1 = $Data['Name'];
mysql_query("INSERT INTO NewTable (Name) VALUES ('$Old1')");
}
This following query will fetch data from mb_posts and mb_topics tables and will insert into forum_posts table.
INSERT INTO forum_posts( post_content, post_topic, post_date, post_by )
SELECT MBP.post_content, MBT.id, NOW( ) , MBP.posted_by
FROM mb_posts AS MBP
LEFT JOIN mb_topics AS MBT ON MBP.topic_id = MBT.id
Similarly the following query will get post topics from old table (mb_topics) to new table (forum_topics).
INSERT INTO forum_topics( topic_title, topic_by)
SELECT MBT.topic_title, MBT.posted_by
FROM mb_posts AS MBP
LEFT JOIN mb_topics AS MBT ON MBP.topic_id = MBT.id
This would be 2 separate queries, because with one INSERT you can only insert into 1 table.

Query for inserting last_insert_id() produce the same id value

Here's my info table:
CREATE TABLE `info` (
`id_info` int(10) NOT NULL auto_increment,
`judul_info` varchar(50) collate latin1_general_ci NOT NULL,
`konten` varchar(255) collate latin1_general_ci NOT NULL,
`diubah_oleh` varchar(20) collate latin1_general_ci NOT NULL,
`id_kategori` int(10) NOT NULL,
`tgl_buat` timestamp NOT NULL default '0000-00-00 00:00:00',
`tgl_ubah` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`dibuat_oleh` varchar(20) collate latin1_general_ci NOT NULL,
`id` int(10) NOT NULL,
PRIMARY KEY (`id_info`),
KEY `id_kategori` (`id_kategori`),
KEY `id` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=62 ;
Here's my upload table
CREATE TABLE `upload` (
`id` int(10) unsigned NOT NULL auto_increment,
`deskripsi` text,
`filetype` varchar(200) default NULL,
`filedata` longblob,
`filename` varchar(200) default NULL,
`filesize` bigint(20) default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=34 ;
I'm using this query :
$sql1="INSERT INTO info VALUES('','$judul', '$konten','$diubah_oleh','$kategori',now(),'$tgl_ubah','$dibuat_oleh','')";
$sql2="insert into upload values ('','$keterangan','$tipe','$filedata','$nama_file',$ukuran)";
$sql3="UPDATE info SET id=last_insert_id()";
$result=mysql_query($sql1);
$result=mysql_query($sql2);
$result=mysql_query($sql3);
I want info.id has the same value as upload.id but with this query all of the value i get in info.id is the same as value i last inserted in upload.id.
CREATE TABLE `upload` (
`id` int(10) unsigned NOT NULL,
`deskripsi` text,
`filetype` varchar(200) default NULL,
`filedata` longblob,
`filename` varchar(200) default NULL,
`filesize` bigint(20) default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=34 ;
$sql1="INSERT INTO info VALUES('','$judul', '$konten','$diubah_oleh','$kategori',now(),'$tgl_ubah','$dibuat_oleh','')";
$result=mysql_query($sql1);
$lastId = mysql_insert_id();
$sql2="insert into upload values ('$lastId','$keterangan','$tipe','$filedata','$nama_file',$ukuran)";
$result=mysql_query($sql2);
Your last update statement below is updating all the rows in your info tables with the same id because there is no where statement.
Since you need the upload table id information inside the info table.
Follow these steps:
Run the $sql2 first.
Then run the $sql1 inserting the last_insert_id() in info.id.
This way you don't need to use update statement as well.
You can do this by using mysql_insert_id(). This function returns the AUTO_INCREMENT ID generated from the previous INSERT operation. Your code should look like this
$sql1="INSERT INTO info VALUES('','$judul', '$konten','$diubah_oleh','$kategori',now(),'$tgl_ubah','$dibuat_oleh','')";
$result=mysql_query($sql1);
$lastinsertedid= mysql_insert_id();
$sql2="insert into upload values ('$lastinsertedid','$keterangan','$tipe','$filedata','$nama_file',$ukuran)";
$result=mysql_query($sql2);
Hope this helps you
There is an alternate php function to that mysql_insert_id() . You can use this to generate the ID inserted in the last executed query.
can you try to do this:
$sql1="INSERT INTO info VALUES('','$judul', '$konten','$diubah_oleh','$kategori',now(),'$tgl_ubah','$dibuat_oleh','')";
$sql2="insert into upload values ('','$keterangan','$tipe','$filedata','$nama_file',$ukuran)";
$last_id = last_insert_id();
$sql3="UPDATE info SET id=".$last_id;
$result=mysql_query($sql1);
$result=mysql_query($sql2);
$result=mysql_query($sql3);

Categories