How to Compare Huge Array to Database (with PHP or SQL) - php

I have a big 2D array (576,000 X 4), and huge database (millions records and 10 columns, its size is in Gigabytes). The array, of course, is much smaller than the number of records in the database.
I need some effective way to compare the 2D array to the database, and delete the equal lines from the 2D array only.
Does anyone have an idea how could i apply it efficiently? The speed is very important to me.
I tried to apply it like that:
$query = mysqli_query($config, "SELECT * FROM sec ") or die(mysql_error());
while ($row = mysqli_fetch_array($query) ) {
if ( isset($arr[$row['CHROM']][$row['POS']]) ) {
// delete line from the 2D array
}
}
But, i don't know how efficient it is, because i tried it just on small database, and it makes me load all the records of the database to the PHP page, and it creates a memory problem.
Another way that i check is this:
foreach ($arr as $chr=>$v) {
foreach ($v as $pos=>$val) {
$query = mysqli_query($config, "SELECT * FROM sec WHERE CHROM='$chr' && POS='$pos' ") or die(mysql_error());
if (mysqli_num_rows($query) > 0) {
// delete line from the 2D array
}
}
}
But, its not a good solution, because it took too much time.
edit:
my sec table looks like that:
the call to a item from the 2D array looks like that $arr[some_CHAROM][some_POS]
if the some_CHAROM equal to some CHAROM in the database AND some_POS equal to the POS in the same line, we have a match.
i build the 2D array from a file that the user upload to the website. and im not load it to the mySql.

The algorithm:
convert the file uploaded by the user into a CSV file (if not already in this format); this is a simple task that can be done in several lines of PHP code; see function fputcsv();
create a buffer table: tbl1;
use LOAD DATA LOCAL INFILE to load the content of the (local) CSV file into the buffer table tbl1;
use:
DELETE tbl1
FROM tbl1
INNER JOIN tbl2 on tbl1.id = tbl2.id
to delete from table tbl1 the rows that have matches in table tbl2. I assumed the match field is named id on both tables; change it to match your design;
fetch the data from table tbl1, format it as you wish, send it to the browser;
cleanup: DROP TABLE tbl1;
Because the script processes a file uploaded by an user, in order to avoid any concurrency issue you need to generate for the buffer table an unique name for each user. You can use a prefix and append the userId to it to avoid two users using the same table on the same time.

Try following code
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "drupal7";
mysql_connect($servername, $username, $password );
mysql_select_db($dbname);
$sql = "SHOW TABLES FROM $dbname";
$result = mysql_query($sql);
if (!$result) {
echo "DB Error, could not list tables\n";
echo 'MySQL Error: ' . mysql_error();
exit;
}
$database1=array();
while ($row = mysql_fetch_row($result)) {
$result1 = mysql_query("SELECT * FROM ".$row[0]);
if(mysql_num_rows($result1)){
$num_rows = mysql_num_rows($result1);
// echo "Table: {$row[0]} ==>".$num_rows."<br>";
$database1[$row[0]]=$num_rows;
}
// }
}
echo '<pre>';
print_r($database1);
mysql_free_result($result);
// mysql_close();
$dbname='drupal71';
mysql_select_db($dbname);
$sql = "SHOW TABLES FROM $dbname";
$result = mysql_query($sql);
if (!$result) {
echo "DB Error, could not list tables\n";
echo 'MySQL Error: ' . mysql_error();
exit;
}
$database2=array();
while ($row = mysql_fetch_row($result)) {
$result1 = mysql_query("SELECT * FROM ".$row[0]);
if(mysql_num_rows($result1)){
$num_rows = mysql_num_rows($result1);
// echo "Table: {$row[0]} ==>".$num_rows."<br>";
$database2[$row[0]]=$num_rows;
}
// }
}
print_r($database2);
$test = array_diff($database1, $database2);
print_r($test);die;

From your code snippet
foreach ($arr as $chr=>$v) {
foreach ($v as $pos=>$val) {
$query = mysqli_query($config, "SELECT * FROM sec WHERE CHROM='$chr' && POS='$pos' ") or die(mysql_error());
if (mysqli_num_rows($query) > 0) {
// delete line from the 2D array
}
}
}
I assume, that you want to delete based on $chr and $pos.
So, you could do the following: Assemble a single query to rule them all* :)
$ors = array();
foreach ($arr as $chr=>$v) {
foreach ($v as $pos=>$val) {
$ors[] = "CHROM='$chr' AND POS='$pos'";
}
}
$deleteConditions = "(" . implode(") OR (", $ors) . ")":
$query = mysqli_query($config, "DELETE FROM sec WHERE " . $deleteConditions);
Untested, but this should give you a single query, like
DELETE FROM
sec
WHERE
(CHROM='1' AND POS='2') OR
(CHROM='3' AND POS='4') OR
(CHROM='5' AND POS='6') OR
...
depending on what $chr and $pos are.
*As Ollie Jones noted in the comments: Take care of the overall query length. If required, create a second, third, ... query until you processed all items in appropriate batches.

Related

Fastest way to find, fetch and replace part of the string in database

I have a set of records in database table and one of the columns has string value. Something like HeyHelloWorld1 or HeyGoodDayWorld2 or HeyHowdyWorld32. I need to change them all to GoodEveningWorld (and whatever comes at the end of the string). I'm trying to run script but it takes too long and I was wondering if anyone knows of a fastest way to implement this
The script:
$con=mysqli_connect("localhost","user","password","db");
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$str_to_look_for = 'Hey';
$new_str = 'GoodEvening';
$result = mysqli_query($con,"SELECT * FROM table1 WHERE item LIKE '%$str%'");
if(!$result) echo "No records found?";
else
{
echo " Found ".mysqli_num_rows($result)." rows<br/>... Executing script...";
while($row = mysqli_fetch_array($result))
{
$val = strstr($row['item'], '/World');
$new_val = $new_str.$val;
$id = $row['ID'];
insert($new_val, $id, $con);
}
echo " DONE!";
}
function insert($x, $id, $con)
{
$result = mysqli_query($con,"UPDATE table1 SET item = '$x' WHERE ID = '$id'");
if (!$result) echo "missed..<br/>";
}
Check out the MySQL String functions and consider replacing it directly in the database.
UPDATE table1
SET item =
CONCAT(
'GoodEvening',
SUBSTRING( item, INSTR( item, 'World') )
)
This would work for anything followed by World, rather than just HelloWorld or HayWorld.

Multiple SELECT Statements and INSERTS in 1 file

I'm working with a file and I'm attempting to do multiple select statements one after another and insert some values. So far the insert and the select I've got working together but when attempting to get the last SELECT to work I get no value. Checking the SQL query in workbench and everything works fine. Here's the code:
$id = "SELECT idaccount FROM `animator`.`account` WHERE email = '$Email'";
$result = mysqli_query($dbc, $id) or die("Error: ".mysqli_error($dbc));
while($row = mysqli_fetch_array($result))
{
echo $row[0];
$insert_into_user = "INSERT INTO `animator`.`user` (idaccount) VALUES ('$row[0]')";
}
$select_userid = "SELECT iduser FROM `animator`.`user` WHERE iduser = '$row[0]'";
$results = mysqli_query($dbc, $select_userid) or die("Error: ".mysqli_error($dbc));
while($rows = mysqli_fetch_array($results))
{
echo $rows[0];
}
I do not want to use $mysqli->multi_query because of previous problems I ran into. Any suggestions? And yes I know the naming conventions are close naming... They will be changed shortly.
Your code makes no sense. You repeatedly build/re-build the $insert_int-User query, and then NEVER actually execute the query. The $select_userid query will use only the LAST retrieved $row[0] value from the first query. Since that last "row" will be a boolean FALSE to signify that no more data is available $row[0] will actually be trying to de-reference that boolean FALSE as an array.
Since you're effectively only doing 2 select queries (or at least trying to), why not re-write as a single two-value joined query?
SELECT iduser, idaccount
FROM account
LEFT JOIN user ON user.iduser=account.idaccount
WHERE email='$Email';
I'm not sure what you're trying to do in your code exactly but that a look at this...
// create select statement to get all accounts where email=$Email from animator.account
$id_query = "SELECT idaccount FROM animator.account WHERE email = '$Email'";
echo $id_query."\n";
// run select statement for email=$mail
$select_results = mysqli_query($dbc, $id_query) or die("Error: ".mysqli_error($dbc));
// if we got some rows back from the database...
if ($select_results!==false)
{
$row_count = 0;
// loop through all results
while($row = mysqli_fetch_array($result))
{
$idaccount = $row[0];
echo "\n\n-- Row #$row_count --------------------------------------------\n";
echo $idaccount."\n";
// create insert statement for this idaccount
$insert_into_user = "INSERT INTO animator.user (idaccount) VALUES ('$idaccount')";
echo $insert_into_user."\n";
// run insert statement for this idaccount
$insert_results = mysqli_query($dbc, $insert_into_user) or die("Error: ".mysqli_error($dbc));
// if our insert statement worked...
if ($insert_results!==false)
{
// Returns the auto generated id used in the last query
$last_inisert_id = mysqli_insert_id($dbc);
echo $last_inisert_id."\n";
}
else
{
echo "insert statement did not work.\n";
}
$row_count++;
}
}
// we didn't get any rows back from the DB for email=$Email
else
{
echo "select query returned no results...? \n";
}

PHP MYSQLI two queries in a page

I have two php files. They each have a different query in them. Both of them work. Then I have one file where I include both files inside of it. The queries work on their individual pages, but in the page where they are both included only the first query works. They look something like this (The first one uses * because I pull out every row)
include 'connect.php';
$query = "SELECT * FROM table ORDER by jid DESC";
$ex = $mysqli->query($query) or die(mysqli_error());
$row_cnt = mysqli_num_rows($ex);
if ($row_cnt > 0) {
/* fetch associative array */
while ($row = $ex->fetch_assoc()) {
echo $row["one"] . $row["two"] . $row["three"] . $row["four"];
}
$result->free();
}
$mysqli->close($mysqli);
The second one is like this
include 'connect.php';
$q = "SELECT one, three FROM table ORDER by jid DESC";
$d = $mysqli->query($q) or die(mysqli_error());
$row_cnt = mysqli_num_rows($d);
if ($row_cnt > 0) {
/* fetch associative array */
while ($row = $d->fetch_assoc()) {
echo $row["one"] . $row["three"];
}
$result->free();
}
$mysqli->close($mysqli);
Then the file that includes them is just two includes like include ' ';
How do I get both queries to work on the one page?
add value in array, like this:
include 'connect.php';
$q = "SELECT one, three FROM jokes ORDER by jid DESC";
$d = $mysqli->query($q) or die(mysqli_error());
$row_cnt = mysqli_num_rows($d);
$values = array();
if ($row_cnt > 0) {
/* fetch associative array */
while ($row = $d->fetch_assoc()) {
$values[0][] = $row["one"];
$values[1][] = $row["two"];
$values[2][] = $row["three"];
$values[3][] = $row["four"];
}
$result->free();
}
$mysqli->close($mysqli);
... after, use foreach for print the value
I have not tested
How do I get both queries to work on the one page?
Just run them one after another like everyone does.
If something goes wrong - debug your code, like everyone does. Read all the error messages and act accordingly.

Storing multiple rows from MySQL in separate variables

I am writing a web application in PHP which will store employee data and generate employee ID cards to PDF. I am using FPDF for creation of PDFs and that works fine. I am having a problem with showing results from MySQL database.
I have to generate PDF with 4 employee ID cards and I am not sure how to get them from the database. So far I am using LIMIT option in the query to get only 4 results and i will have an if statement based on mysql.php?id=1 id which will define the limit. It is a little messy but there are not going to be more than 80 employees.
This is my code:
$id = $_GET['id'];
if ($id == 1) {
$limit_start = 0;
$limit_end = 4;
}
$result=mysql_query("SELECT users.tajemnik, users.dateCreated, users.showmeID,
users.workerName, users.dateCreated, users.workerPlace, users.workerSID, uploads.userID, uploads.data, uploads.filetype
FROM users INNER JOIN uploads ON users.showmeID = uploads.userID ORDER BY workerName DESC LIMIT $limit_start, $limit_end") or die (mysql_error());
mysql_query("SET NAMES 'utf8'") or die('Spojení se nezdařilo');
while($row = mysql_fetch_array($result)){
$workerName = $row["workerName"];
$workerPlace = $row["workerPlace"];
$workerSID = $row["workerSID"];
$tajemnik = $row["tajemnik"];
$showmeID = $row["showmeID"];
$mysqldatetime = strtotime($row['dateCreated']);
$image = $row["data"];
$phpdatetime = date("d.m.Y",$mysqldatetime);
}
This will get me the first result from the query. I need to get information from all 4 rows and have them stored in variables like $workerName1, $workerName2 etc. I hope it makes sense what I am trying to do.
Thank you for your replies!
V.
I need to get variables like $workerName1, $workerName2 etc
Nope, you don't.
You actually need an array.
So, first, get yourself a function
function sqlArr($sql){
$ret = array();
$res = mysql_query($sql) or trigger_error(mysql_error()." ".$sql);
if ($res) {
while($row = mysql_fetch_array($res)){
$ret[] = $row;
}
}
return $ret;
}
then write a code
mysql_query("SET NAMES 'utf8'") or die('Spojení se nezdařilo');
$sql = "SELECT users.tajemnik, users.dateCreated, users.showmeID, users.workerName,
users.dateCreated, users.workerPlace, users.workerSID, uploads.userID,
uploads.data, uploads.filetype
FROM users
INNER JOIN uploads ON users.showmeID = uploads.userID
ORDER BY workerName DESC LIMIT $limit_start, $limit_end";
$data = sqlArr($sql);
Now you have all your data in the $data array.
So, you can loop over it or access single values like
echo $data[0]['tajemnik'];
or
foreach($data as $row) {
//do whatever you want with database row
echo $row['tajemnik'];
}

Why isn't this script working? (odd/even)

I've been writing a script to display the names of users based on whether they are assigned an even or odd comment id. It calls up data from 2 different tables in the same database. Here is the table information:
Table 'comments' has the columns commentid, tutorialid, name, date: Table 'winners' has the columns pool, pool2, pool3, pool4, pool5, pool6, pool7. Table 'comments' has multiple rows that are updated through user input. Table 'winners' has only 1 row with numbers that are randomly generated daily.
The first part of the script that displays "Result 1" and "Result 2" is working properly. The part that isn't working is the part that calls up the usernames. I only want to display the usernames that corralate with the result that is displayed IE if Result 1 is chosen then I only want the usernames with even 'commentid's displayed.
<?php
$db = mysql_connect('localhost', 'username', 'pass') or die("Database error");
mysql_select_db('dbname', $db);
$query = "SELECT pool FROM winners";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_array($result))
if ($row['pool'] % 2) {
echo "<h4>Result 1</h4>";
$names = get_names(1);
foreach($names as $name) {
echo $name . "<br/>";
}
} else {
echo "<h4>Result 2</h4>";
$names = get_names(0);
foreach($names as $name) {
echo $name . "<br/>";
}
}
function get_names($pool_result)
{
$name_array = array();
$query = "SELECT * FROM comments where mod('commentid',2) = $pool_result";
$result = mysql_query($query);
while ($row = mysql_fetch_array($result)) {
array_push($name_array, $row['name']);
}
return $name_array;
}
?>
Can anyone figure out why this isn't working?
The SELECT statement with the mod is not referencing the field. Should be backticks instead of single quotes. Single quotes indicate a string constant, which would result in a constant result set (mod('commentid',2) appears to have a result of 0). It should be something like this:
$query = "SELECT * FROM comments where mod(`commentid`,2) = $pool_result";
Adding quotes around commentid treats it as a string, and you can't mod a string by an integer. Try the following instead:
$query = "SELECT * FROM comments WHERE commentid % 2 = $pool_result";
This was taken from the following Stack question: select row if the "value" % 2 = 1. MOD()

Categories