I am trying to UPDATE my table using a PHP for loop but it will take too long to work. I really have 200,000 people in my table. When I open the php file, the browser literally hungs itself :) When I open the phpMyAdmin, I can see it works, yet very slowly.
Is there a way to do the exact same thing using SQL, directly in phpMyAdmin?
for ($a = 0; $a < 200000; $a++) {
$rand = mt_rand(10000000, 99999999);
// checks whether the same url exists or not
$sec = "SELECT person_url FROM person WHERE person_url = '$rand'";
$result = $sqli->query($sec);
$row = $result->fetch_assoc();
$finish = $row['person_url'];
if ($finish == false) {
$sql = $sqli->prepare("UPDATE person SET person_url = '$rand' WHERE person_id = '$a'");
$sql->execute();
}
}
You seem to be updating every row in your table with a random number in a particular range. You don't need to do any of the PHP processing at all.
You can simply update the table with
update person set person_url = (cast(rand()*89999999 as signed)+10000000);
You run the risk of getting duplicate entries in the person_url field which you will need to resolve by some means.
One means of doing this is to set the person_url column to unique and use the query with ignore and a different where clause:
update ignore person set person_url = (cast(rand()*89999999 as signed)+10000000)
where person_url is null;
This will probably do the job in one pass, but if it doesn't, run it repeatedly until it does. You'd be very unlucky to have to use more than two or three passes and it's still likely to be much faster than manually checking for uniqueness with PHP.
Prepare the statements outside the loop and use bound parameters.
$sql1 = $sqli->prepare("SELECT person_url FROM person WHERE person_url = ?");
$sql1->bind_param('s', $rand);
$sql2 = $sqli->prepare("UPDATE person SET person_url = ? WHERE person_id = ?");
$sql2->bind_param('si', $rand, $a);
for ($i = 0; $a < 200000; $a++) {
$rand = mt_rand(10000000, 99999999);
// checks whether the same url exists or not
$sql1->execute();
$sql1->store_result();
if($sql1->num_rows == 0) {
$sql2->execute();
}
}
Related
I am using PHP PDO,
this the code :
for ($i = 0; $i < 1000; $i++) {
//select room and insert to chart
$thisDay=date ("Y-m-d");
$query = $db->prepare("SELECT room FROM d_room WHERE activ=1 ORDER BY room");
$query->execute();
for($a = 1; $result = $query->fetch(); $a++) {
$query2 = $db->prepare("INSERT INTO d_chart (date,room,status) VALUES (? + INTERVAL ? DAY,?,0)");
$query2->execute(array($thisDay,$i,$result['room']));
}
}
this code run too slow, How to make better code and fast, < 2 second.
I don't know why you are trying to do this. However,I suggest you not to store this fuzzy data in your database because there are other ways for doing such tasks if time and space constraint is the issue. As you said <2 seconds then storing that big result will not take less than 30seconds even on the local machine.
So what you can do is just store single result in database as follows:
$thisDay=date ("Y-m-d");
$query = $db->prepare("SELECT room FROM d_room WHERE activ=1 ORDER BY room");
$query->execute();
$result = $query->fetchAll(PDO::FETCH_ASSOC); // storing result here would reduce some time to fetch the data inside loop because your script would not require to get the data again and again from server.
$query = $db->prepare("INSERT INTO d_chart (date,room,status) VALUES (? + INTERVAL ? DAY,?,0)");
for($i=0; $i<sizeof($result);$i++)
{
$query->execute(array($thisDay,$i,$result[$i]['room']));
}
and if you want to retrieve the data for next 1000 days then just fetch the single day data from the database and show the result using some mathematical calculations for next 1000 days at the client side, which would be much faster than anything.
However, you should explain what is your aim behind doing such huge task so that you can get better answers.
You should be able to make this significantly simpler by using an INSERT...SELECT query (assuming MySQL)
// Make sure you see any errors that might occur
ini_set('display_errors', 'On');
error_reporting(E_ALL);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$thisDay = date('Y-m-d');
$stmt = $db->prepare('INSERT INTO d_chart (date, room, status)
SELECT (:thisDay + INTERVAL :days DAY), room, 0
FROM d_room WHERE activ = 1'); // there's no need to order these results
$stmt->bindParam(':thisDay', $thisDay);
$stmt->bindParam(':days', $i, PDO::PARAM_INT);
for ($i = 0; $i < 1000; $i++) {
$stmt->execute();
}
If d_room.activ has an index, this would be even faster.
Don't run the exact same query 1000 times!
Check your indexing to speed up the query.
Prepare the query, then execute it in the loop. This is what preparing is for.
Use PDO::beginTransaction and PDO::commit before and after the loop, respectively. Index updates can be expensive and it's faster to do them all at once.
That should at least make it as fast as possible.
$thisDay = date ("Y-m-d"); // Take this outside the loop
$query = $db->prepare("SELECT room FROM d_room WHERE activ=1 ORDER BY room");
$query2 = $db->prepare("INSERT INTO d_chart (date,room,status) VALUES (? + INTERVAL ? DAY,?,0)"); // Prepare this once
$query->execute(); // Just run this once
$rowset = $query->fetchAll (); // Put into an array to re-loop without querying again
$db->beginTransaction (); // Will update indices in bulk - faster
for ($i = 0; $i < 1000; $i++)
{
//select room and insert to chart
foreach ($rowset as $result)
$query2->execute(array($thisDay,$i,$result['room']));
}
$db->commit (); // Apply changes
As you can see, the loop is now much, much tighter - always the first place to look to speed up code.
I am not seeing any reason to run this query thousands time inside the loop. Because it is executing the same query. Put the query outside the loop.
<?php
//select room and insert to chart
$thisDay = date("Y-m-d");
$query = $db->prepare("SELECT room FROM d_room WHERE activ=1 ORDER BY room");
$query->execute();
$query2 = $db->prepare("INSERT INTO d_chart (date,room,status) VALUES (? + INTERVAL ? DAY,?,0)");
$result = $query->fetch();
for ($i = 0; $i < 1000; $i++) {
$query2->execute(array($thisDay, $i, $result['room']));
}
Currently working on a login script that would allow for multiple users with the same username to exist. The current plan is to generate a random "secret" user id that will take the place of the actual username. So how would I go about generating a random integer and checking to see if has been added?
This is my attempt at the code; however it does not seem to work as it does not seem to do anything.
$looptime = 100;
while ($looptime > 0) {
$userid = rand(0, 999999999);
$SQL = "SELECT * FROM Accounts WHERE username = '" . $userid . "'";
$result_id = #mysql_query($SQL) or die("DATABASE ERROR!");
$total = mysql_num_rows($result_id);
if (!$total) {
$looping = 0;
//CREATE THE ACCOUNT
mysql_query("INSERT INTO Accounts (id,username,password, email, money, activated) VALUES ('', '$username','$password', '$email', '0', '1')") or die("REGISTER ERROR!"); //1=account activated
//CONNECTED
echo "IMCONNECTED";
}
$looptime--;
}
EDIT: The code/number should be fairly easy to remember/jot down somewhere as the user will be able to view it and/or jot it down for account recovery purposes.
I would suggest either using a UUID/GUID (not an integer) to minimize the possibility of clashes, or using an identity column (not random) to guarantee uniqueness. Does it have to be an integer and does it have to be random?
Are you using an integer for the ID in the table? You could append this ID to the username. For example: MyUsername1234, MyUsername1245.
Here is a way you could do it. Create a scalar-variable function in your database (similar to below):
CREATE FUNCTION [dbo].[fn_randomNumber] (#guid nvarchar(128))
RETURNS int AS
BEGIN
SET #guid = REPLACE(#guid, '-', '');
DECLARE #idInt varchar(Max) = '';
DECLARE #i INT = 0;
DECLARE #char VARCHAR;
WHILE(#i < LEN(#guid))
BEGIN
SET #char = (SUBSTRING(#guid, #i, 1));
IF(ISNUMERIC(#char) = 1)
BEGIN
SET #idInt = #idInt + #char;
IF(LEN(#idInt) = 9)
BEGIN
BREAK;
END
END
SET #i = #i + 1;
END
RETURN CAST(#idInt as INT);
END
GO
Then execute this script:
SELECT [dbo].[fn_randomNumber] (
newid())
Of course you will want to evaluate the result to make sure it doesn't already exist.
So in this piece of code, I just deleted a row from the table, and so, the values for img_pos were:
1,2,3,4,5
And now, they are (assuming we deleted the third entry):
1,2,4,5
Of course, I want this to be:
1,2,3,4
So I have to batch rename the rows.
I got this, but doesn't seem to work....
$sql = "SELECT * FROM $tableImg WHERE img_acc = $accid ORDER BY img_pos";
$res = mysql_query($sql);
$num = mysql_num_rows($res);
$i = 0;
$n = 1;
while($i<$num){
$sql = "SELECT * FROM $tableImg WHERE img_acc = $accid ORDER BY img_pos DESC LIMIT $i,1";
$res = mysql_query($sql);
$row = mysql_fetch_array($res);
$img_pos = $row['img_pos'];
$sql = "UPDATE $tableImg SET img_pos = '$n' WHERE img_acc = '$accid' AND img_pos = '$img_pos'";
$res = mysql_query($sql);
$i++;
$n++;
}
mysql_close();
$tableImg is just a variable containing the table name, that works just fine.
I guessthe problem is somewhere around "$img_pos = $row['img_pos'];", because all the querys are used somewhere differently, be it slightly different, and they should work...
Thanks in advance!
I ended up simply doing this:
$i = 1;
while($row = mysql_fetch_array($res)){
$old_pos = $row['img_pos'];
$sql = "UPDATE $tableImg SET img_pos = $i WHERE img_acc = $accid AND img_pos = $old_pos";
$res = mysql_query($sql);
$i++;
};
This is quite possible, just totally unnecessary. The nice thing about digital data is that you don't have to look at it so it doesn't matter if it's a bit gappy, does it?
If you REALLY want to do this (say, you are building an application and you are just cleaning up the stuff you deleted whilst working on it) the following example will do in in SQL, as this simple example shows:
CREATE TABLE disorder (id int,stuff CHAR(6));
CREATE TABLE disorder2 (id SERIAL,stuff CHAR(6));
INSERT INTO disorder (id,stuff)
VALUES
('1','ONE'),
('2','TWO'),
('3','THREE'),
('4','FOUR'),
('5','FIVE');
DELETE FROM disorder WHERE id='3';
INSERT INTO disorder2 (stuff) SELECT stuff FROM disorder;
TRUNCATE TABLE disorder;
INSERT INTO disorder SELECT * from disorder2;
DROP TABLE disorder2;
This can be seen in action on sqlfiddle but it's pretty obvious. If you do a SELECT * from disorder, you will see why you probably shouldn't do this sort of thing.
Your tables really do need to have primary keys. This speeds searches/indexing and makes them useful. Look up database normal forms for a thorough discussion of the reasoning.
I am creating a browser statistics script in PHP.
When PHP finds a match in a table how do I retrieve the row and pull all three fields of the table into separate variables.
My table rows are (browser, version, amount)
so I want to select everything from the TB were
browser = $browser and version = $version.
But when this happens how do I add one to the amount field and resubmit the row. Without altering anything else. Below is the code I have.
$browser_name= "MSIE";
$version = "7";
$query = ("SELECT * FROM $TB
WERE browser = '$browser_name' AND version = '$version'");
$result = mysql_query($query);
$count = mysql_num_rows($result);
if($count == 1)
{
$mysql = ("SELECT * FROM $TB
WERE browser = '$browser_name' AND version = '$version'");
//code to add 1 to amount would be here
}
else
{
//if browser is not detected insert fresh row.
$mysql = "INSERT INTO $TB (browser, version, amount)
VALUES ('$browser_name', '$version', 1)";
}
I have been looking around for answers for ages but they just tell me how to select information out of a DB as a whole.
update table set amount_field = amount_field + 1 where browser = '$browser_name' and version = '$version'
I don't understand why you make twice the same select.
$browser_name= "MSIE";
$version = "7";
$query = "SELECT * FROM $TB WHERE browser = '$browser_name' AND version = '$version'";
$result = mysql_query($query);
if($data = mysql_fetch_assoc($result))
{
print_r($data);
//use UPDATE from other answers if you need one here.
}
else
{
//if browser is not detected insert fresh row.
mysql_query("INSERT INTO $TB (browser, version, amount)
VALUES ('$browser_name', '$version', 1)");
}
Beware of SQL injections!
SELECT * FROM $TB WHERE browser
you have a mistake it must be WHERE instead of WERE.
You update query will be like this
UPDATE $TB SET ammount = 1 WHERE browser = $browser and version = $version
There are hundreds of issues with your query like sanitization etc. I suggest you read a good mySQL book to improve the queries. But to answer your question:
//code to add 1 to ammount would be here
mysql_query("update $TB set amount = amount + 1 where browser = '".mysql_real_escape_string($browser_name)."' and version = '".mysql_real_escape_string($version)."'");
First of all, you should connect to db using
$db = new mysqli('host','user','pass','dbname');
Then, your query isn't right. You have a sql syntax error.
SELECT * FROM table WHERE column = value
So, without prepare, your code should look like:
$tb = 'table_name'; // to avoid sql injections use addslashes() to your input
$browserName = addslashes('browser_name'); // like this
$version = '7';
$db = new mysqli('host','user','pass','dbname');
$result = $db->query("SELECT * FROM $tb WERE browser = '$browserName' AND version = '$version'");
// Than, you can fetch it.
while ($result->fetch as $row) {
echo $row['yourColumn']; // will display value of your row.
}
$db->query("INSERT INTO $tb (browser, version) VALUES ('$browser_name', '$version')";
}");
And, that's all. You can count your records using mysql count() method. Your code will work. I advice you, at first go to php.net and check the doc. There are many examples.
I have a page that writes to a MySQL table. The table has a set amount of rows (24).
I have an $id variable that's set by a rand() function. I basically want to pull the row at that $id, so if $id was 3, I want to pull the third row. Then, I want to check if there is a price set at that row (indicating that the row is being used). If there is no price, I want to keep $id at the value it has been set at and proceed with the query. If there is a price, I want to re-randomize the $id variable, and check again if that row is used up. When it finds an empty row, proceed with the query.
My solution semi-works, but it seems to have a <10% chance of overwriting a used row, for some reason. I want it to never overwrite a used row.
Here's my code:
mysql_select_db("delives0_booklet", $con);
$query = "SELECT * FROM booklet WHERE id = '$id'";
$res = mysql_query($query,$con);
$newId = $id;
while($row = mysql_fetch_array($res))
{
if($row['price'] != 0)
{
do{
$newId = rand(1, 24);
}while($newId == $id);
}
}
$id = $newId;
mysql_query("UPDATE booklet SET price = '$price', advertiser = '$advertiser', image = '$image', monthsRemaining = '$monthsRemaining', availability = 1 WHERE id = '$id'");
Edit
I had the idea to do this. I loop through the table and I put the 'id' of each unfilled spot into an array. Then I pick randomly from that array. However, there seems to be a bug that I can't find, since the array keeps showing as having nothing in it, even after the loop is run, and $i is the correct figure.
mysql_select_db("delives0_booklet", $con);
$query = "SELECT * FROM booklet";
$res = mysql_query($query,$con);
$i = 0;
$isEmpty = array();
while($row = mysql_fetch_array($res))
{
if($row['price'] == 0)
{
$isEmpty[i] = $row['id'];
$i = $i + 1;
}
}
echo $i . " unfilled spots.";
$n = 0;
while($n<$i)
{
echo $isEmpty[$n];
$n = $n + 1;
}
if($i > 0)
{
$id = $isEmpty[rand(0, $i)];
}
if($i == 0)
{
echo 'All spots have been filled.';
}
I think it is a top level logic problem. Because you populate with random ids, you can get duplicate ids, and so when you update "WHERE id = '$id'" you may be picking up rows already populated.
I don't know your goal, but perhaps using an auto-increment id, and dropping rows that you want to get rid of, is the way to go. A rolling set of rows (24 at a time) but with ever increasing ids, would prevent mistaking one for the other.
If I understand the problem correct, this should work:
SELECT *
FROM booklet
WHERE price = 0 OR price IS NULL
ORDER BY RAND()