I have a problem where I get an array of words and I have to insert every one of them in DB via a foreach, but the whole thing is running too slow.
foreach($words as $word) {
// even more checks
if(strlen($word) < 3) continue;
$word = $this->db->escapeString(strtolower($word));
// word not found?
$result = $this->db->querySingle("SELECT id FROM words WHERE word = '{$word}'");
if(!$result) {
$this->db->exec("INSERT INTO words (word) VALUES ('{$word}')");
$this->db->exec("INSERT INTO search (reply, word) VALUES ('{$id}', '{$this->db->lastInsertRowID()}')");
// word found
} else $this->db->exec("INSERT INTO search (reply, word) VALUES ('{$id}', '{$result}')");
}
Basically lets say $words = array('hello', 'kitten');
Within that foreach, it will take my first word (hello) and check if it exists in the words table. If it cannot find the word, it will then insert it there and also insert it into another table with a variable $id that will not change within the foreach. If however it found the word it will insert it directly in the 2nd table. After that it will take the 2nd word (kitten) and do the same thing.
Using php5 with sqlite3
$this->db = new \SQLite3(ROOT . DS . 'db' . DS . 'app.db');
The tables in question are very light
CREATE TABLE words (id INTEGER PRIMARY KEY AUTOINCREMENT, word TEXT);
CREATE TABLE search (reply INTEGER, word INTEGER);
CREATE INDEX search_reply_idx ON search (reply);
CREATE INDEX search_word_idx ON search (word);
This works fine most of the time for 10-15 words, but if i have over 150 words it will be as slow as 8 seconds. Can i combine the queries into just one? Am i missing something?
Thanks.
This method is based on the premise that SQLite support this syntax for insertion (this syntax works in MySQL):
INSERT INTO table (column) VALUES ('value1'), ('value2'), ('value3'), ('valueN');
What you can do is use PHP to build the SQL insert string using logic from the SELECT statement, and then at the end perform two queries; One on the words table and one on the search table:
$sql_words = 'INSERT INTO words (word) VALUES ';
$sql_search = 'INSERT INTO search (reply, word) VALUES ';
$count = count($words);
$i = 0;
$last_insert_id = '';
$delim = '';
foreach ($words as $word)
{
$result = $this->db->querySingle("SELECT id FROM words WHERE word = '{$word}'");
if ($i < $count) {
$delim = ', ';
} else {
$delim = '';
}
if ($result) {
$sql_search .= "('{$result}','{$word}')".$delim;
} else {
$sql_words .= "('{$word}')".$delim;
$sql_search .= "('{$result}','{$last_insert_id}')".$delim;
}
$last_insert_id = $result;
$i++;
}
$this->db-exec($sql_words);
$this->db->exec($sql_search);
As for the validity of this code I am unsure, I was a bit confused where $id came from, and assumed it was the same as $result.
So in order to achieve blazing fast performance some things had to be changed.
Firstly, the use of transactions (sort of like mulquin's answer) and secondly I've added a unique index for the column word in the words table. This will help me skip the sql that checked if a word already existed and just ignore the insert statements from that transaction.
This is the new table which will create my unique index automatically
CREATE TABLE words (id INTEGER PRIMARY KEY AUTOINCREMENT, word TEXT UNIQUE)
And here is the modified foreach
$t1 = $t2 = null;
foreach($words as $word) {
// even more checks
if(strlen($word) < 3) continue;
$word = $this->db->escapeString(strtolower($word));
$t1 .= "INSERT OR IGNORE INTO words (word) VALUES ('{$word}');";
$t2 .= "INSERT INTO search (reply, word) SELECT '{$id}', id FROM words WHERE word = '{$word}';";
}
// run transactions
if(!is_null($t1)) $this->db->exec("BEGIN TRANSACTION;" . $t1 . "COMMIT;");
if(!is_null($t2)) $this->db->exec("BEGIN TRANSACTION;" . $t2 . "COMMIT;");
So, when in doubt, use transactions :)
Related
$stuffname=$_GET['stuffname'];
$pieces = explode(" ", $stuffname);
$pieces can have any number of words in it.
I want to loop this query so that each word is added from pieces as a separate entry into the table keywords
$query=$con->prepare("INSERT INTO keywords (stuffname) VALUES (?)");
$query->execute([$pieces]);
Thanks for your time
It's unclear if you've tried anything or where you got stuck, but this should be very simple with a loop.
Either
execute a separate INSERT for each new row
$query = $con->prepare("INSERT INTO keywords (stuffname) VALUES (?)");
foreach ($pieces as $piece)
$query->execute([$piece]);{
}
or
Try to build a single INSERT with multiple sets of values:
$sql = "INSERT INTO keywords (stuffname) VALUES ";
$vals = "";
foreach ($pieces as $piece)
{
$vals .= ($vals != "" ? "," : "")."(?)";
}
$query = $con->prepare($sql.$vals);
$query->execute([$pieces]);
Okay, so I'm having a pretty annoying little problem with my php code. Basically I pull two variables from two seperate sources. One's a cookie and the other is from a MySQL database.
$data = explode("|", $_COOKIE['login']);
$sql = "SELECT session_id FROM users WHERE username='user1'";
$result = $data->query($sql);
$row = $result->fetch_assoc();
$test1 = $data[0];
$test2 = $row['session_id'];
If($test1 == $test2) {
// Do some stuff
}
else {
// Don't do some stuff
}
The actual string is:
x6vkYu6Ep^lm(1Rdm)5Gj5Hj7ilL6FsDL88JC#n#iTyBUqYgJ48#9Ow%*2ZdGs1rA8bc)JoCD7dywcZgg7soV0D#!DpR^pjQwF#QpBt#HRKe$JEtQ*3LhFXsjmkzWNpt
The string is randomly generated before being stored from the following character set:
1234567890!##$%^&*()abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
for($i = 0; $i < 128; $i++) {
$string .= $char_set[rand(0, strlen($char_set)-1)];
}
$sql = "UPDATE users SET session_id='$string' WHERE user='user1'";
$data->query($sql);
setcookie('login', $string . "|" . $username);
If I just set the two variables equal to the above string and evaluate, it works out just fine. Also, if I echo both $data[0] and $row['session_id'] the entire string will display, and they look indentical.
The if() statement will work if I use basic strings, like a number, or basic word, so I'm guessing it's due to special characters, but I don't know where in the proccess it goes wrong. As I said, if I set two variables to that string value, it evaluates, but when I pull from MySQL and the cookie, despite that both strings look the same, it won't evaluate.
Any thoughts?
I have a column in a table of a MySQL database that stores numbers separated by commas. Here's an example:
,,322,,,,455,,,,698,,,,722,
There is a specific pattern:
The first number always has two commas before it
The numbers in between the first and last are separated by 4 commas
The last number is followed by a single comma
The numbers are ALWAYS separated by commas
I'm having some difficulty maintaining this pattern.. sometimes this field updates incorrectly resulting in too many or too few commas in certain places like so:
,,166,,,,845,,,,,,,,846,
I use this PHP to add/remove commas:
public function serializeArray($array) {
$string = ',';
foreach ($array as $obj) {
$string .= ',' . $obj . ',';
}
return $string;
}
public function unserializeArray($string) {
$array = explode(",,",$string);
unset($array[0]);
$array = array_values($array);
return $array;
echo "Array: " . print_r($array);
}
SQL to update column:
$query = $this->pdo->prepare(
'UPDATE `' . $this->table . '` SET
`team_ids` = :team_ids
WHERE `id` = :customer_id LIMIT 1;');
$query->bindParam(':customer_id', $customer_id, PDO::PARAM_INT);
$query->bindParam(':team_ids', $team_ids);
$query->execute();
What SQL can I use to UPDATE all of the values in the column to follow the specific pattern requirements mentioned above?
The issue here looks like you're missing a number, not that it is not following your pattern.
,,166,,,,845,,,,Missing No,,,,846,
Are you sure you want to delete this? I would instead focus on catching the null or blank number.
If so, it looks like you should be able to do a replace
Update TableName
Set NumberPattern = Replace(NumberPattern, ',,,,,,,,', ',,,,') --Repalce 8 ',' with 4 ','
I'm exploding a comma separated list into a variable named $tagArray and trying to write those values into incrementing rows of a table.
The code below works in so much as it creates the appropriate number of rows in my table but it only writes the first letter of the comma separating string (ie. if the string reads as "one, two, three", "o" is written in the first row and the remaining two rows have a blank value for column "blog_tag":
$tagInput = $_POST["blog_tags"];
$tagArray = explode(",",$tagInput);
$sql_2 = "INSERT INTO blog_tags (blog_tag, blog_id)
VALUES ";
$valuesArray = array();
foreach($tagArray as $row){
$tag = mysqli_real_escape_string($conxn, $row['blog_tag']);
$valuesArray[] = "('$tag','$lastID')";
}
$sql_2 .= implode(',', $valuesArray);
if (!mysqli_query($conxn,$sql_2)) {
die('Error: ' . mysqli_error($conxn));
}
This is spaghetti pieced together from various searches here and it's getting close but I can't figure out where it's grabbing just that first letter of the string.
Explode doesn't create associative arrays
$tag = mysqli_real_escape_string($conxn, $row); //instead of $row['blog_tag']
just replace your foreach with this for inserting values of array
foreach($tagArray as $row){
$a=mysqli_real_escape_string($row)
$sql_2 = "INSERT INTO blog_tags (blog_tag, blog_id) VALUES
('$a','$lastID') ";
}
I want to store the results of permutation into a temporary table in mysql so i can use it in the search script.
<?php
function permute($str,$i,$n) {
if ($i == $n) {
echo "$str\n";
echo "<br/>";
$query = mysql_query("CREATE TABLE temp(
id int NOT NULL AUTO_INCREMENT,
number varchar(64) NOT NULL,
PRIMARY KEY(id)
)");
$str = addslashes(trim($_POST['str']));
$query = mysql_query("INSERT INTO temp (number) VALUES ('$str')")
or die(mysql_error());
}
else {
for ($j = $i; $j < $n; $j++) {
swap($str,$i,$j);
permute($str, $i+1, $n);
swap($str,$i,$j); // backtrack.
}
}
}
// function to swap the char at pos $i and $j of $str.
function swap(&$str,$i,$j) {
$temp = $str[$i];
$str[$i] = $str[$j];
$str[$j] = $temp;
}
$str = #$_GET['number'] ;
permute($str,0,strlen($str)); // call the function.
// Get the search variable from URL
?>
Does anyone know how to insert the result of permutation into a temporary table?
I have try to insert into permanent table but the 24sets result of 1234 is not inserted but only the id 1-24 is inserted. I think the problem is because the $str contain 24sets of result but is not separated since it is print out together??
Any solution?
Your real problem is $str = addslashes(trim($_POST['str']));, which is attempting to retrieve the value from the web request in a post form, immediately before putting it into the temp table.
Basically, you're over-writing your variable with something that is (probably not set, thus) blank.
Oh, and I hope in reality you're safely escaping your input parms, or your site is going to be taken over in short order. If number is only ever supposed to contain an actual number (1234), and not some string (ABC), cast it to numeric data (and back to string) to completely sanitize it (exception handling should be included, too).