This may sound silly but i am trying to figure out the best approach to run a query only once in a stats table that have all values set to 0 as a starting point and i would like your opinion, my table is by example:
Col1 - Col2 - Col3 - Col4 - Created - Modified
0 0 0 0 Datetime- Datetime
My main script have several foreach loops where i evaluate some conditions, if there is a match, i build the query and run a mysqli multiquery at the end, by example (pseudo code):
$query = '';
foreach ($array as $val) {
if ($val == $mycondition) {
$query .= "UPDATE mytable SET Col1 = Col1 + 1;";
}
}
$db = mysqliConnection();
$num = $db->query("SELECT * FROM my table WHERE id = '".$ID."' AND Col1 = 0 AND Col2 = 0 AND Col3 = 0 AND Col4 = 0");
$result = mysqli_num_rows($num);
// if 0 it means that nothing has been modified yet so i can run the query
if ($result > 0) {
$db->multi_query($query)
}
$db->close();
This is the best approach i can think of right now, i created the columns created and modified but i think they will not work for this, as the creation time will always be before the modified time, probably in milisecs (but i dont want to risk taking the path to allow the mutiquery run after max 3 sec or so, cause if the user run the page several time by mistake between 3 secs it will store wrong values) and the modified column will change as soon as the first value is updated making the next queries fail if i rely on that column as condition in the WHERE clause (even if are just milisec).
What do you think guys is the best approach or i am in the right path?
Best Regards
I would suggest to use a flag. Something like:
$queryFlag = 0;
if($queryFlag == 0) {
//Do you things here
$queryFlag = 1;
}
Related
I have a SQL-statement like this:
$stmtTHIS = $db->query("SELECT titel, done_date FROM task WHERE project = $tID ");
How can I find out how many rows have an content in "done_date"?
First you have to define what "have content" means then just write a WHERE clause to find those. And use the COUNT function to count the number of rows returned. So lets say "have content" means the field is not null.
SELECT COUNT(*) FROM task WHERE project = $tID AND done_date IS NOT NULL
This counts all the records with that project id and have a value for done_date.
You may also want to check that done_date does not have some other empty value like empty string or 0.
AND done_date != "" AND done_date !=0
Alternate:
Use the query you have to get all those rows, then do the count in PHP:
$stmtTHIS = $db->query("SELECT titel, done_date FROM task WHERE project = $tID ");
$count = 0;
while($row = $stmtTHIS->fetchAssoc()){
//You probably want to do other stiff with the data
if( !empty($row['done_date']) ){
$count++;
}
}
echo $count;
Your code might be slightly different depending on the DB library your using, (I assumed mysqli)
Im trying to update a value in a table, using while loop, but i want this value to be like using auto_inc key.
My table: ID / CAR_ID / IMG_KEY / IMAGE
i want to take 12 rows of the same CAR_ID and give the IMG_KEY values from 1-12.
I tried the below loops, but the result is giving the IMG_KEY the value 1
$getImages = mysql_query("SELECT * FROM more_images WHERE car_id = '$car_id'") or die(mysql_error());
$img_key = 0;
for ($img_key = 1; $img_key <= mysql_num_rows($getImages); $img_key ++) {
while ($selectedImages = mysql_fetch_assoc($getImages)) {
$update = mysql_query("UPDATE `more_images` SET `img_key` = '$img_key' WHERE `car_id` = '$car_id'") or die(mysql_error());
}
}
The goal is give to the following 12 rows img_key values from 1 to 12 and all the other values as they are.
Ok, I'm still not 100% sure what you want, but my guess is that you are looking for something like this:
$imgKey = 0;
while ($selectedImages = mysql_fetch_assoc($getImages))
{
$imgKey++;
$update = mysql_query("UPDATE `more_images` SET `img_key` = '{$imgKey}' WHERE `car_id` = '{$car_id}'") or die(mysql_error());
}
In your question, your for loop isn't doing anything other than looping, in your case it iterates twelve times.
Since mysql_fetch_assoc($getImages) is a function that loops through all rows in a set of results. So for each iteration of your for loop, it updates all records to have the same $img_key.
Also, really do refrain from using mysql_* functions, they're deprecated. Read this thread:
Why shouldn't I use mysql_* functions in PHP?
I have some mysql tables (one for each container) like so (the table would be called containerA for instance):
Box_ID Box_Name Box_Distributor Container Box_state
======---========---===============---==========----=========
1 Box 1 Delivery Comp.1 ContainerA Full
2 Box 2 Delivery Comp.2 ContainerA Empty
3 Box 3 NULL ContainerA Missing
and I have another mysql table with a list of containers:
container_id container_name
============---==============
1 A
2 B
and I want to report the name of the container and the number of empty boxes to a webpage.
I've written this to do it:
$v1 = 0;
$sql = "select * from containers";
$result = mysql_query ($sql) or die(mysql_error());
while ($row = mysql_fetch_array($result))
{
$containers[] = $row[container_name];
$containerid[] = $row[container_id];
}
while ($v1 < 14)
{
$containerend = $containers[$v1];
$containerstart = "container";
$containername = $containerstart.$containerend;
$sql = "SELECT COUNT(*) FROM `$containername` WHERE state = 'Empty';";
$result = mysql_query($sql) or die(mysql_error());
$count = mysql_fetch_array($result);
var_dump($containers[$v1]);
var_dump($count[$v1]);
$v2 = $v1 + 1;
$v1 = $v2;
}
Which works in listing the container names, but it only gives me the first result for the empty boxes, the rest of the array is returned as NULL:
string(1) "4" NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
Am I doing something stupid here? Surely the SQL query in the while loop should be returning the count for each container?
Any help is appreciated.
change this
while ($row = mysql_fetch_array($result))
{
$containers[] = $row[container_name];
$containerid[] = $row[container_id];
}
to
while ($row = mysql_fetch_array($result))
{
$containers[] = $row['container_name'];
$containerid[] = $row['container_id'];
}
you missed '.
Am I doing something stupid here?
Yes.
Splitting the same data across multiple tables is really dumb.
$sql = "select * from containers";
...
while ($v1 < 14)
{
...
$sql = "SELECT COUNT(*) FROM `$containername` WHERE state = 'Empty';";
Relational database management systems are very good at performing joins. Procedural / OO languages are NOT.
If all your containerX tables where in a single table then the performance would be a lot better and the code much simpler. And it's trivial to create views named like the individual tables on an aggregated table thus avoiding having to rewrite most of your code straight away.
Why are you fetching all the containers then only processing the first 14?
What is $v2 doing?
It's rather hard to work out why your code is misbehaving as your description doesn't match your code - your query states "WHERE state = 'Empty'" but your table description has no column named state (and if that were an accurate report, then the code would stop on the first iteration with a MySQL error message).
$count is in essence only a single value (as you are counting a single container), so it will work for the first element, but not for subsequent elements. Quick fix is to use mysql_result:
$count = mysql_result($result, 0);
as ever, this code is using mysql functions that are both insecure and due to be deprecated - do consider switching to mysqli or pdo.
I am trying to update 3 column values in a row in mysql only if any of the 3 values is different.
Say I have a table of
x,y,z,id columns
I have currently,
Method A
update foo set x = 'x_value', y = 'y_value', z = 'z_value' where id = 'unique_id'
and ((x <> 'x_value') or (y <> 'y_value') or (z <> 'z_value'))
I don't know much about the theoretical benchmarking/architecture of mysql, and I was wondering if the statements
Method B
update foo set x ='x_value' where id = 'unique_id' and ((x <> 'x_value'));
update foo set y ='y_value' where id = 'unique_id' and ((y <> 'y_value'));
update foo set z ='z_value' where id = 'unique_id' and ((z <> 'z_value'));
is better or superior.
I realize that Method B will only do one write and 3 reads if only one column has changed, vs 3 writes and 3 reads for the Method A. I just don't know if it is more time intensive because method B requires looking up the index row 3 times.
Thanks in advance!
Based on what I've read in the comments, I agree with octern that you should simply run an update. It will use significantly less resources and based on your table engine, it will free up your table/ row lock for less time, making your table perform a lot better.
However, if you insist on doing a check before doing a write, do so through PHP. Simply do a select statement, compare the code in PHP and then update the appropriate table(s). For example:
$res = mysql_query("SELECT * FROM table1 WHERE PK_ID = '0'");
$arr = mysq_fetch_assoc($res);
$update = false;
if ($arr["field_1"] != $_POST["field_1"])
{
$update = true;
}
if ($arr["field_2"] != $_POST["field_2"])
{
$update = true;
}
if ($update)
{
mysql_query(sprintf("UPDATE table1 SET field_1 = '%s', field_2 = '%s'", $_POST["field_1"], $_POST["field_2"]));
}
if (
Method B will of course be more costly, because you do 3 different selects vs Method A's single select / update on condition.
Its pretty much a comparison of 1 statement to 3 statements. 1 will be faster as they are both update statements.
Imagine I've got a database with lots of data, from which users can search.
The result of a typical search is generally around 20-100 rows, which are then paginated (20 rows per page).
I've thought of two approaches to handle the navigation for these pages and would like to know if there are any pros and/or cons to these and if there are any better alternatives.
Query once, store results in $_SESSION variable and filter rows according to current page. The reason I came up with this was to make the data retrieval once, without having to connect to the database for every page the user navigates. I don't know if it's better or worse than the other alternative I've come up with.
session_start();
$search = rawurldecode($_GET['search']); //search word
$interval = rawurldecode($_GET['interval']); //rows per page
$page = rawurldecode($_GET['page']); //page
$min_row = $interval * ($page-1)+1;
$max_row = $interval * $page;
//query if (no results stored or first page) && the current search is not the previous search
if((empty($_SESSION['SEARCH_RESULTS']) || $page == 1) && $_SESSION['SEARCH_RESULTS']['TERM'] != $search){
$_SESSION['SEARCH_RESULTS'] = array();
$_SESSION['SEARCH_RESULTS']['TERM'] = $search;
$query = "exec usp_Search '$search'";
$dbh = new DBH;
$dbh->Connect()->Query($query);
while($row = $dbh->Fetch_Array()){
$_SESSION['SEARCH_RESULTS']['ROWS'][] = $row;
}
}
for($j = 0; $j < count($_SESSION['SEARCH_RESULTS']['ROWS']); $j++){
$row = $_SESSION['SEARCH_RESULTS']['ROWS'][$j];
//ignore all other rows not on the page
if($j < ($min_row-1) || $j > $max_row) continue;
//print stuff
}
Query page by page. The query and the pagination is pretty straightforward.
//Query
$search = rawurldecode($_GET['search']);
$interval = rawurldecode($_GET['interval']);
$page = rawurldecode($_GET['page']);
$min_row = $interval * ($page-1)+1;
$max_row = $interval * $page;
$query = "exec usp_Search '$search', $min_row, $max_row";
$dbh = new DBH;
$dbh->Connect()->Query($query);
while($row = $dbh->Fetch_Array()){
//print stuff
}
SQL procedures from the alternatives
Is just a procedure with a SELECT query
SELECT
COL1,
COL2,
COL...
FROM TABLE1
WHERE (
COL1 LIKE '%'+#search+'%' OR
COL2 LIKE '%'+#search+'%' OR
COL... LIKE '%'+#search+'%'
)
Is a procedure that creates a temp table and then selects rows from variables start to end.
SELECT
COL1,
COL2,
COL...,
ROW_NUMBER() OVER (ORDER BY COL1) AS [ROW_NUMBER]
INTO #result
FROM TABLE1
WHERE (
COL1 LIKE '%'+#search+'%' OR
COL2 LIKE '%'+#search+'%' OR
COL... LIKE '%'+#search+'%'
)
SELECT
COL1,
COL2,
COL...
FROM #result
WHERE ROW_NUMBER BETWEEN #row_start AND #row_end
You really can't store all of the results in the _SESSION for at least a couple reasons:
Users may make multiple searches simultaneously
Search results may change between a user's page loads.
The second point depends on how frequently you update your DB, but is something to consider. The first is major, but you may also be able to get around it if you store the session in a clever way (but you don't want _SESSION getting too large either). This is irrespective of performance.
Another consideration about getting all results at once and storing into _SESSION is that the majority of your users may only make one search request per visit. I know you would like to think they will always look at all 100 results, but if a large chunk of those results are not even being used, you're wasting quite a lot just to save a query or two. It's up to you to figure out how your users navigate.
After reading that this is only going to be used by 20-30 people and only 70 rows a day, I'm satisfied to say you're wasting time trying to improve performance at this point. Go for the code that's easier to update later in case of major changes.
Consider this scenario:
User searches a term with 100 results stored in database.
You query the database once getting all 100 results and you store them in session.
User finds what he was looking for in the first 5 results and leaves the search page.
In the end, you "overheated" database to fetch 95 rows for nothing. What if those 100 results are 1000, or 10.000 ?
In my opinion, getting all the results in a single query and store the results in session is a "reliable method" to reduce performance.