If ( $currentCount <= $allowedCount ) .. Returns 1 extra? - php

For some reason this code still returns 2 instead of one?
$allowedCount = 1; ( This figure is set inside the database )
$sql_count = mysql_query("SELECT usrid FROM mytable WHERE usrid=".$uid) or die(mysql_error());
$currentCount = mysql_num_rows( $sql_count );
$currentCount = 1; ( In this example current count returns a 1 )
if ( $currentCount <= $allowedCount ) {
// do this OK
} else {
// do this Not OK
}
What im trying to do is check if the user has reached their limit, if so then disallow them further INSERT queries etc....
Would this be a simple approach?

check your db, you may have duplicate record. if your using a form to insert the data it may be reinserting data upon page refresh. if not check your db for duplication.

Related

PHP optimize multiple update and select query

I have a php API where i am checking different conditions and based on that, i am fetching the count of the row and updating the count in the same table.
Below are the Conditions i am writing the query: (Note: 1 user can have multiple campaigns)
1) For a given user(Uid), for a particular campaign whose type = Impression, i am getting the Impression count and updating the same in table
2) For a given user(Uid), for a particular campaign whose type = Action i am getting the Action count and updating the same in table
//To get the Impression/Action/Lead count
$Impressionarr = [];
$Actionarr = [];
//IMPRESSION COUNT
$imp_qry = "select count(*) as ImpressionCount from ClicksAndImpressions where Uid = 101642 and CampaignID =100 and Type='Impression' ;";
$impData = $this->getClicksAndImpressionsTable()->CustomQuery($imp_qry);
if($impData[0]['ImpressionCount'] != '' || $impData[0]['ImpressionCount'] !=NULL ){
$impr_update = "UPDATE ClicksAndImpressions SET ImpressionCount = ". $impData[0]['ImpressionCount'] ." where Uid = 101642 and CampaignID =100 ;";
}else{
echo '----not Present';
}
//Impression count
foreach($impData as $key=>$data)
{
$data['ImpressionCount'];
$Impressionarr[] = $data;
}
//ACTION COUNT
$action_qry = "select count(*) as ActionCount from ClicksAndImpressions where Uid = 101617 and CampaignID =81 and Type = 'Action';";
$actionData = $this->getClicksAndImpressionsTable()->CustomQuery($action_qry);
if($actionData[0]['ActionCount'] != '' || $actionData[0]['ActionCount'] !=NULL ){
$action_update = "UPDATE ClicksAndImpressions SET ActionCount = ". $actionData[0]['ActionCount'] ." where Uid = 101617 and CampaignID =81 ;";
$actionData = $this->getClicksAndImpressionsTable()->CustomUpdate($action_update); //print_r($actionData);exit;
}else{
echo '----not Present';
}
//Action count
foreach($actionData as $key=>$data)
{
$data['ActionCount'];
$Actionarr[] = $data;
}
//Trying to combine the 3 arrays- but 2nd and 3rd not merging into 1st
$combine = array_merge($CampaignDetailsarr,$Impressionarr,$Actionarr);
1) Can the above duplicates - either in Update query or multiple for loops be avoided. if so how to optimize the above as per my conditions
ie) For
if( Uid = 123 for some campaignId = 11 and if type is 'Impression')
-> Update query for impression
else if(Uid = 123 for campaignId= 22 and if type = 'something else')
-> Update query for something else
2) I already have one array 1. I need to merge my 2 new arrays (Impressionarr[], Actionarr[]) into the 1st one, but below is how im getting.
Expected:
Coming as:
You could probably speed it up by creating a stored procedure in your database and calling that with the required data. From what I can see, most of the logic you have to do can be done in the stored procedure.

PHP MySQL dont get last selected

i have a mysql Table with some rows.
The Select gets one (LIMIT 1) row. After a counter it reloads and get random another row. But sometimes he get the same (cause random).
How can i setup that he dont get the last row?
The problem is, i cannot do that in mysql. I must do that in the SESSION or only on that site.
I tried that:
$_SESSION['ads'] .= ','.$adid;
put that adid in "ads" SESSION and read it before SELECT here
session_start();
$ads = substr($_SESSION['ads'], 1);
$ads = str_replace(",", "','", $_SESSION['ads']);
In the SELECT is that
AND id NOT IN ('".$ads."')
But sometimes, i dont know why, he save two items or something... i dont find out why, cause the SELECT is LIMIT 1
Any ideas how to do that or is there a mysql function?
For any reason, the script is load two times the SELECT or something
This is the code:
$query = "SELECT * FROM ads ORDER BY RAND() LIMIT 1;";
while($row = $result->fetch_assoc()) {
$adid = $row["id"];
$_SESSION['ads'][] = $adid;
}
echo 'adid: '. $adid;
print_r($_SESSION['ads']);
There he print like that:
Array
(
[0] => 6
[1] => 3
)
I dont know, why he puts 2 in there. Cause the echo of the $adid shows only one!
Try something like this maybe :
1/ Create a new session and create an empty array :
session_start();
if (empty($_SESSION['ads']))
$_SESSION['ads'] = array();
2/ Do you select and add the id in this array :
if (empty($_SESSION['ads']) {
// 1. Do your select with no where condition
// 2. Fetch the result
$data = /* result of the select */;
// 3. Add the selected id in your session array
$_SESSION['ads'][] = $data['id'];
} else {
// 1. Do your select but with a WHERE condition
$query = "SELECT...
WHERE id NOT IN ( " . implode( "', '" , $_SESSION['ads'] ) . " )";
// 2. Fetch the result
$data = /* result of the select */;
// 3. Add the selected id in your session array
$_SESSION['ads'][] = $data['id'];
}
Is it what you are looking for?

PHP Update Query While Loop

So I have 2 tables named accounts and tblDataNumbers. The accounts table has a sponsorID field while the tblDataNumbers table has xsponsorID field. So first, this is the code:
for ($x = 501; $x <= 1061; $x++) {
$data = $conn->query("SELECT * FROM tblDataNumbers WHERE tableID = $x");
foreach ($data as $d) {
$xsponsorID = $d['xsponsorID'];
}
$checkSponsor = $conn->query("SELECT * FROM accounts WHERE sponsorID = '".$xsponsorID."' ");
if(count($checkSponsor) > 0) {
$xsid = $xsponsorID;
} else {
$xsid = "";
}
$stmt = $conn->prepare('UPDATE tblDataNumbers SET xsponsorID=:xsponsorID WHERE tableID=:x');
$stmt->execute(array(
':xsponsorID' => $xsid,
':x' => $x
));
}
The code above will check if the $xsponsorID is existing on the sponsorID field of the accounts table. If yes, it will set $xsid to the same value which is $xsponsorID and if not, it will be set to blank or "". When I run the code, nothing happens. There are lots of numbers in the xsponsorID field of the tblDataNumbersthat table that is not present in the sponsorID field of the accounts table so basically something should be set to blank but not even one.
What I wanted to happen with this is to repeat the code inside from row 501 to 1061 of table tblDataNumbers but nothing happens. Is there something wrong with my code? Thank you.
I don't know if this is what you are attempting but that could potentially kill the server for a while as there will be 560 x records (from 1st query ) = lots!
I think there must be a neater solution that does the work in one query - I shall look at the queries in detail to see if there is a solution.
for( $x = 501; $x <= 1061; $x++ ) {
$data = $conn->query("SELECT * FROM tblDataNumbers WHERE tableID = $x");
/* This loop will only ever get one result..
foreach( $data as $d ){
$xsponsorID = $d['xsponsorID'];
}
*/
foreach( $data as $d ){
$xsponsorID = $d['xsponsorID'];
$checkSponsor = $conn->query("SELECT * FROM accounts WHERE sponsorID = '".$xsponsorID."' ");
$xsid=( count( $checkSponsor ) > 0 ) ? $xsponsorID : '';
$stmt = $conn->prepare('UPDATE `tblDataNumbers` SET `xsponsorID`=:xsponsorID WHERE `tableID`=:x;');
$stmt->execute(array(
':xsponsorID' => $xsid,
':x' => $x
));
}
}
After looking at this again and reading your comments I wondered if something along the lines of the following might do the trick. I created a new database with the same two named tables and populated some test data ( though I do not know if it resembles your own data ) and used the following as a test within heidi ( mysql gui app )
set #tblid=1;
update `tblDataNumbers` t set t.`xsponsorID`=(
case
when ( t.`xsponsorID` not in ( select `sponsorID` from `accounts` ) ) then
null
else
t.`xsponsorID`
end
)
where t.`tableID`=#tblid;
Clearly this updates a record where the tableID is equal to the #tblid var only. However, to update all the records that match the criteria, remove the where clause and it will apply the NULL value to any record in the tblDataNumbers table that does not have a corresponding sponsorID in the accounts table. Before running this I would strongly advise making a backup of your data though!!!!
Without the mysql variable the query becomes the following and means you would not need the loops.
update `tblDataNumbers` t set t.`xsponsorID`=(
case
when ( t.`xsponsorID` not in ( select `sponsorID` from `accounts` ) ) then
null
else
t.`xsponsorID`
end
)
If it is important to update the records only between 501 and 1061 then you could add a where clause such as:-
where t.`tableID` between 501 and 1061
Thanks to #RamRaider, managed to fix it by adding a single line and removing the count() function.
for( $x = 501; $x <= 1061; $x++ ) {
$data = $conn->query("SELECT * FROM tblDataNumbers WHERE tableID = $x");
foreach( $data as $d ){
$xsponsorID = $d['xsponsorID'];
$checkSponsor = $conn->query("SELECT * FROM accounts WHERE sponsorID = '".$xsponsorID."' ");
$row = $checkSponsor->fetch(PDO::FETCH_ASSOC); //I forgot this line
$xsid=( $row > 0 ) ? $xsponsorID : '';
$stmt = $conn->prepare('UPDATE `tblDataNumbers` SET `xsponsorID`=:xsponsorID WHERE `tableID`=:x;');
$stmt->execute(array(
':xsponsorID' => $xsid,
':x' => $x
));
}
}

SQL | Update multiple rows with one query

I have a method, where about 20 rows must changed. Im passing per ajax a string like "14-33-61-10 ..." for saving the order of some rows.
Here is my actual (working) code:
$explode = explode('--',$_POST['data']); // -> array('0'=>'8', '1'=>'4', '2'=> ... )
$i = 1;
foreach( $explode as $task ) {
if( !is_int($task) ) continue;
$exec = $project->exec("UPDATE tasks SET pos=$i WHERE rowid=". $task );
$i++;
}
My problem is, that it takes about 1 second.
My question: Is there a way to edit multiple rows with just one query?
Sure, send a SQL string like:
update tasks
set pos =
case rowid
when 13 then 1
when 33 then 2
when 61 then 3
when 10 then 4
end
where rowid in (13,33,61,10)
The translation from 13-33-61-10 to (13,33,61,10) is best done in PHP.
If the range is short then we can use the ID IN (ids) argument.
UPDATE `profile` SET `app_status`=3 WHERE `id` IN (3,37,95,136,1087,1795,1817)
If it's long and we know that range, let's use the BETWEEN value AND value argument.
UPDATE `profile` SET `app_status`=3 WHERE `id` BETWEEN 3904 AND 3918
$explode = explode('--',$_POST['data']); // -> array('0'=>'8', '1'=>'4', ... )
$i = 1;
$sql = "";
foreach($explode as $task)
{
if(!is_int($task)) continue;
$sql .= "UPDATE tasks SET pos=$i WHERE rowid=$task;";
$i++;
}
$project->exec($sql);

Mysqli query performance multi-query

I was just hoping someone could help me speed up 4 queries with a multi query.
GOAL: a single multi query to function as the single queries below.
Simple queries, i am checking one table to see if user is banned, then if not, i am getting row for the id and updating it's view count by 1. If user is banned, i do not want the last to queries to complete.
Thank you in advance for your help.
current performance is around 1200ms. (+1000ms avg for facebook graph api query).
NOTE: af_freefeed.pageid & af_ban.pageid are both indexed in database.
ALSO: I have been studying and referencing from http://www.php.net/manual/en/mysqli.multi-query.php i just can not see how to get this config into multi with the if()
$fconn = new mysqli($fdbhost, $fdbuser, $fdbpass, $fdbname) or die ('Error connecting to mysqli');
// 12,000 rows for af_ban - bigint(255) : indexed
$q = sprintf('SELECT COUNT(pageid) AS numrowst FROM af_ban WHERE pageid = %s', $banpage);
$readtop = $fconn->query($q);
$rowtop = $readtop->fetch_assoc();
// 1.17 million rows for af_freefeed - bigint(255) : indexed
if($rowtop[numrowst] == 0){
$q = sprintf('SELECT COUNT(pageid) AS numrowsf FROM af_freefeed WHERE pageid = %s', $banpage);
$readf = $fconn->query($q);
$rowf = $readf->fetch_assoc();
// increment views
$read = $fconn->query("Update af_freefeed SET views = views + 1 WHERE pageid = ".$banpage."");
}
$q=$fconn->query("SELECT pagename,views,pageid FROM af_freefeed ORDER BY views DESC LIMIT 0, 20");
unset($q);
unset($rowf);
unset($rowtop);
mysqli_close($fconn);
actual request times.
grah api: 1127.04610825ms.
conncect: 1.20711326599ms.
check banned: 0.405788421631ms.
get row: 418.189229965ms.
increment views: 472.24655151ms.
get top20: 94.31447983ms.
Multi_query #1 How to stop the multi query if user is banned?
Possible Contender: 943.8181ms. if added : 933.1279ms. if banned
10ms difference if exit loop for banned. This leads me to believe the loop is completing all the queries before they are actually supposed to be executed, "next_result". Or i have an error in how i looped the functions.
replaced exit; with $thread_id = $fconn->thread_id; $fconn->kill($thread_id);
if banned 953.4719ms. no gain.
$banpage='234232874008';
$query = "SELECT pagename,views,pageid FROM af_freefeed ORDER BY views DESC LIMIT 0, 2;";
$query .= "SELECT pageid AS isbanned FROM af_ban WHERE pageid = \"".$banpage."\";";
$query .= "SELECT pageid AS isadded FROM af_freefeed WHERE pageid = \"".$banpage."\";";
$query .= "Update af_freefeed SET views = views + 1 WHERE pageid = \"".$banpage."\"";
/* execute multi query */
if ($fconn->multi_query($query)) {
if ($result = $fconn->store_result()) {
while ($row = $result->fetch_row()) {
print_r($row).'<br />';
}
$result->free();
}
if ($fconn->more_results()) {
while ($fconn->next_result()){
if($thisresult = $fconn->store_result()){
while (is_array($row = $thisresult->fetch_array())) {
if(isset($row['isbanned'])){
if($row['isbanned']===''.$banpage.''){
$thread_id = $fconn->thread_id;
$fconn->kill($thread_id);
// exit;
}
}
}
}
}
}
}
unset($query);
unset($result);
unset($thisresult);
Multi_query #2 "current for benchmark" How to remove duplicate fields in result set after next_result()?
2.667ms. / 1032.2499ms. but print_r is showing duplicate fields in $thisresults?
**Array
(
[0] => 37
[id] => 37
[1] => 159616034235
[pageid] => 159616034235
[2] =>
[userid] =>
[3] => 30343
[views] => 30343
[4] => Walmart
[pagename] => Walmart
)**
$query = "SELECT pageid AS isbanned FROM af_ban WHERE pageid = \"".$banpage."\";";
$query .= "SELECT pageid AS isadded FROM af_freefeed WHERE pageid = \"".$banpage."\";";
$query .= "SELECT * FROM af_freefeed ORDER BY views DESC LIMIT 0, 20";
//$query .= "Update af_freefeed SET views = views + 1 WHERE pageid = \"".$banpage."\"";
/* execute multi query */
echo '<pre>';
$i=0;
if ($fconn->multi_query($query)) {
if ($result = $fconn->store_result()) {
//$row = $result->fetch_assoc();
while ($row = $result->fetch_assoc()) {
print_r($row).'<br />';
}
$result->free();
}
if ($fconn->more_results()) {
while ($fconn->next_result()){
if($thisresult = $fconn->store_result()){
while ($row2 = $thisresult->fetch_array()) {
if(isset($row2['isadded'])){
if($row2['isadded']===''.$banpage.''){
$addone = $fconn->query("Update af_freefeed SET views = views + 1 WHERE pageid = ".$banpage."");
}
}
print_r($row2);
}
}
}
}
}
/* determine our thread id */
$thread_id = $fconn->thread_id;
/* Kill connection */
$fconn->kill($thread_id);
//
echo '</pre><hr/>';
Try to use index in getting count. Like for example COUNT(pageid). It will speed up your query.
Update
You can also try this link for further explanation
EDIT : So now, the conclusion: (test case below)
You cannot control the execution of subsequent statements of a multi-statement query.
You can therefore not use multi_query() in the way you wanted to.
Execute them all, or execute none.
Regarding
Multi_query #2 "current for benchmark" How to remove duplicate fields in result set after next_result()?
Use fetch_assoc() or fetch_array(MYSQLI_ASSOC) (both practically the same) instead of fetch_array().
About multi_query():
I recently worked on a program using the MySQL C API, which mysqli uses, too.
About multiple-statement query support the documentation states:
Executing a multiple-statement string can produce multiple result sets or row-count indicators. Processing these results involves a different approach than for the single-statement case: After handling the result from the first statement, it is necessary to check whether more results exist and process them in turn if so. To support multiple-result processing, the C API includes the mysql_more_results() and mysql_next_result() functions. These functions are used at the end of a loop that iterates as long as more results are available. Failure to process the result this way may result in a dropped connection to the server.
(emphasize added)
This leads to the conclusion, that aborting a multiple-statement query is not an intended feature.
Moreover, I didn't find any resource explaining when subsequent queries are actually executed.
Calling next_result() doesn't neccessarily mean that the query hasn't been executed already.
EDIT : TEST CASE
To prove what I previously assumed, I created a test case:
<?php
$db = new mysqli('localhost', 'root', '', 'common');
$query = 'SELECT NOW() as time;';
$query .= 'SELECT NOW() as time;';
$query .= 'SELECT NOW() as time;';
$query .= 'SELECT NOW() as time;';
if($db->multi_query($query)) {
// Current time
echo "'multi_query()' executed at:\n\t\t"
.date('Y-m-d H:i:s')."\n";
// First result
if($result = $db->store_result()) {
$i = 1;
$row = $result->fetch_assoc();
echo "'NOW()' of result $i:\n\t\t".$row['time']."\n";
$result->free();
// Wait 5 seconds
sleep(5);
// Subsequent results
while($db->more_results() && $db->next_result()) {
$result = $db->store_result();
$row = $result->fetch_assoc();
$i++;
echo "'NOW()' of result $i:\n\t\t".$row['time']."\n";
// Wait 5 seconds
sleep(5);
$result->free();
}
}
}
$db->close();
?>
This results in:
'multi_query()' executed at:
2013-05-10 10:18:47
'NOW()' of result 1:
2013-05-10 10:18:47
'NOW()' of result 2:
2013-05-10 10:18:47
'NOW()' of result 3:
2013-05-10 10:18:47
'NOW()' of result 4:
2013-05-10 10:18:47
Given that, it is obvious that all four statements of the query were executed directly after the call to multi_query().
If they were only executed after calling next_result() there would be a 5 second delay caused by sleep(5) calls I added between the loop iterations.
Please run following query in mysql and check your query run time :
CREATE INDEX pagidIndex ON af_ban (pageid(11));
CREATE INDEX pagidFeedIndex ON af_freefeed (pageid(11));
CREATE INDEX viewsIndex ON af_freefeed (views(11));
i am checking one table to see if user is banned, then if not, i am getting row for the id and updating it's view count by 1.
The following query may help you to update the view count. I assume that you already know the page_id.
UPDATE af_freefeed SET views=views+1 WHERE page_id=%s and page_id not in (select page_id from af_ban WHERE page_id=%s);
You could try something along these lines:
$sql = sprintf("SELECT af_freefeed.pageid FROM af_freefeed left join af_ban ".
"on (af_freefeed.pageid = af_ban.pageid) ".
"where af_freefeed.pageid = %s and ".
"af_ban.pageid is null limit 1", $pageid);
to replace your first two queries.
The existence of a record in the results should indicate an unbanned user requesting the resource. Then you can do your update your views.
Hope this helps.

Categories