Adding condition to mysql query and fetch again - php

I have 3 queries which I run which are nearly identical, the latter two have an AND condition.
Main query:
$mess = $mysqli->prepare("SELECT * from ( SELECT cm.id ,cm.userid,cm.message,cm.voteup,cm.votedown,cm.date
FROM chat_messages cm
INNER JOIN members m ON m.id =cm.userid
INNER JOIN chat_settings cs ON cs.id = cm.room_id
WHERE cm.setting_id = ?
ORDER BY cm.date DESC LIMIT 30 ) ddd
ORDER BY date ASC ");
$mess->bind_param("i", $room);
$mess->execute();
$mess->store_result();
$mess->bind_result($chatid,$chat_userid,$message,$voteup,$votedown,$date);
while($row = $mess->fetch()){
//im fetching here in my <div class='div1' >
}
Then, in the second div I have to add an AND condition:
$mess2 = $mysqli->prepare("SELECT * from ( SELECT cm.id ,cm.userid,cm.message,cm.voteup,cm.votedown,cm.date
FROM chat_messages cm
INNER JOIN members m ON m.id =cm.userid
INNER JOIN chat_settings cs ON cs.id = cm.room_id
WHERE cm.setting_id = ? AND voteup - votedown >= 5
ORDER BY cm.date DESC LIMIT 30 ) ddd
ORDER BY date ASC ");
$mess2->bind_param("i", $room);
$mess2->execute();
$mess2->store_result();
$mess2->bind_result($chatid,$chat_userid,$message,$voteup,$votedown,$date);
while($row2 = $mess2->fetch()){
//im fetching here in my <div class='div2' >
}
Lastly, in the third div I have a slightly different AND condition:
$mess3 = $mysqli->prepare("SELECT * from ( SELECT cm.id ,cm.userid,cm.message,cm.voteup,cm.votedown,cm.date
FROM chat_messages cm
INNER JOIN members m ON m.id =cm.userid
INNER JOIN chat_settings cs ON cs.id = cm.room_id
WHERE cm.setting_id = ? AND votedown - voteup >= 5
ORDER BY cm.date DESC LIMIT 30 ) ddd
ORDER BY date ASC ");
$mess3->bind_param("i", $room);
$mess3->execute();
$mess3->store_result();
$mess3->bind_result($chatid,$chat_userid,$message,$voteup,$votedown,$date);
while($row3 = $mess3->fetch()){
//im fetching here in my <div class='div3' >
}
Everything works BUT doing this near-same query seems clumsy. Is it possible to construct the same thing with only one query? I have used $mess->data_seek(0); but its not helping because I didn't add my condition to the query.

Just go for PhP to filter your data instead of triple query your database. In this case you can figure out to go for this solution because you call 3 times your query with the same parameter :
$mess3 = $mysqli->prepare(" SELECT *
FROM ( SELECT cm.id ,
cm.userid,
cm.message,
cm.voteup,
cm.votedown,
cm.date
FROM chat_messages cm
INNER JOIN members m ON m.id =cm.userid
INNER JOIN chat_settings cs ON cs.id = cm.room_id
WHERE cm.setting_id = ?
AND votedown - voteup >= 5
ORDER BY cm.date DESC LIMIT 30 ) ddd
ORDER BY date ASC ");
$mess3->bind_param("i", $room);
$mess3->execute();
$mess3->store_result();
$mess3->bind_result($chatid,$chat_userid ,$message,$voteup,$votedown ,$date);
while($row = $mess3->fetch()){
$voteup = $row['voteup'];
$votedown = $row['votedown'];
addToDiv1($row);
if( $voteup - $votedown >= 5 ) {
addToDiv2($row);
}
if( $votedown - $voteup >= 5 ) {
addToDiv3($row);
}
}

I will just give an answer based specifically on cleaning up your code. Technically you will still make the 3 calls in this scenario, but it will be cleaner because you include one function only, you don't see the script behind it.
As I mentioned, I am not an SQL aficionado so I can not give a good solution there (maybe you can use GROUP BY and perhaps an OR clause...I don't really know...). If I were to do this, I would do a function that can return all the options:
/core/functions/getChatMessages.php
function getChatMessages($settings,$mysqli)
{
$id = (!empty($settings['id']))? $settings['id'] : false;
$type = (!empty($settings['type']))? $settings['type'] : false;
$max = (!empty($settings['max']))? $settings['max'] : 30;
$mod = '';
// No id, just stop
if(!is_numeric($id))
return false;
// equation one
if($type == 'up')
$mod = ' AND voteup - votedown >= 5';
// equation two
elseif($type == 'down')
$mod = ' AND votedown - voteup >= 5';
$mess = $mysqli->prepare("SELECT * from ( SELECT cm.id ,cm.userid,cm.message,cm.voteup,cm.votedown,cm.date
FROM chat_messages cm
INNER JOIN members m ON m.id =cm.userid
INNER JOIN chat_settings cs ON cs.id = cm.room_id
WHERE cm.setting_id = ? {$mod}
ORDER BY cm.date DESC LIMIT {$max} ) ddd
ORDER BY date ASC");
$mess->bind_param("i", $id);
$mess->execute();
$mess->store_result();
$mess->bind_result($chatid, $chat_userid, $message, $voteup, $votedown, $date);
while($mess->fetch()){
$result[] = array(
'chatid'=>$chatid,
'chat_userid'=>$chat_userid,
'message'=>$message,
'voteup'=>$voteup,
'votedown'=>$votedown
);
}
// Send back the data
return (!empty($result))? $result : array();
}
To use:
// Include our handy function
require_once('/core/functions/getChatMessages.php');
// Store our id for use
$settings['id'] = 100;
// Should get 30 from first select
$voteGen = getChatMessages($settings,$mysqli);
// Should get 30 from second select
$settings['type'] = 'up';
$voteUp = getChatMessages($settings,$mysqli);
// Should get 15 from third select
// Just for the heck of it, I added in a limit settings
$settings['max'] = 15;
$settings['type'] = 'down';
$voteDown = getChatMessages($settings,$mysqli);
Now that you have these stored, just use a foreach loop to place them into your view. The good side of this is that you can call this where ever and when ever since the function only returns data. It allows you to work with the data in a view or non-view situation. Side note, I use PDO, so if there is something ineffective with the way the mysqli is fetching, that will be why. It's probably just best to fetch an assoc array to return...

Related

PHP not storing query result

For a particular query
SELECT MAX(theCount), day
FROM (SELECT FK_Hour, day As day, Count(FK_Hour) As theCount
FROM (Select slottime.FK_Hour, time.day
From slottime INNER JOIN time ON slottime.FK_Hour = time.Hour )
As C GROUP By FK_Hour
)
AS counts GROUP By day
The database returns
However when running the php code
$timequery = array();
try {
$sth = $dbh->prepare("SELECT MAX(theCount), day
FROM (SELECT FK_Hour, day As day, Count(FK_Hour) As theCount
FROM (Select slottime.FK_Hour, time.day
From slottime INNER JOIN time ON slottime.FK_Hour = time.Hour )
As C GROUP By FK_Hour
)
AS counts GROUP By day
");
$sth->execute();
while ($timequery = $sth->fetch(PDO::FETCH_ASSOC)) {
$timequery[] = $results;
}
echo("trying ");
print_r($timequery);
echo(" tried");
}
The output is merely
trying tried
$results seem to be uninitialized... Change code as shown below
while ($results = $sth->fetch(PDO::FETCH_ASSOC))

PHP MySQL sort order ASC/DESC for only the records shown

I have a query that returns close to a 1000 records. Using pagination, I'm showing a 100 records per page. Great...no problem. I can also sort by last name or first name in either ascending of descending order. ok so far. The first page returns records for last name starting with A to C. The problem I'm having is that when I click last name to descend I get records with last name starting with Z. The records at the end of my query, I want to get results going from C to A (what is shown on my first page...repeating the same functionality in each page.
Here is what I got...
$orderColumn = 'lastName';
$orderDirection = 'ASC';
if( isset($_POST["oc"]) && $_POST["oc"] !== '' ) { $orderColumn = $_POST["oc"]; }
if( isset($_POST["od"]) && $_POST["od"] !== '' ) { $orderDirection = $_POST["od"]; }
$per_page = 100;
$query = "SELECT * FROM table as t
LEFT JOIN table_2 as t2 ON t.pk_uID = t2.fk_uID
LEFT JOIN table_3 as t3 ON t3.fk_utID = t2.pk_utID
WHERE t3.fk_utID = 7 and t.interviewed = 0";
$result = $db->query($query);
$count = mysql_num_rows($result);
$total = ceil($count/$per_page);
if ($_GET['page']) {
$page = $_GET['page'];
}
$offset = (($page-1)*$per_page);
$query2 = "SELECT firstName as first, lastName as last FROM table
LEFT JOIN table_2 as t2 ON t.pk_uID = t2.fk_uID
LEFT JOIN table_3 as t3 ON t3.fk_utID = t2.pk_utID
WHERE t3.fk_utID = 7 and interviewed = 0 order by $orderColumn $orderDirection LIMIT $offset, $per_page";
$res = $db-> query($query2);
while($row = mysql_fetch_array($res)){
echo "<span style='display: inline-block; width: 15%;'>$row[first]</span>";
echo "<span style='display: inline-block; width: 15%;'>$row[last]</span>";
}
To what I was saying in comment.. BTW I'm on my mobile phone so this may be unformatted and or take a while...
Select what_you_need
From
( select your_inner_select
From table t
LEFT JOIN table_2 as t2 ON t.pk_uID = t2.fk_uID
LEFT JOIN table_3 as t3 ON t3.fk_utID = t2.pk_utID
WHERE t3.fk_utID = 7 and interviewed = 0 LIMIT $offset, $per_page
ORDER BY $orderColumn ASC
)t
order by $orderColumn $orderDirection

PHP while loop returning only one row when SUM added to multiple JOIN query

I have a query like this:
$query = "SELECT a.sender_id,
a.recipient_id,
a.form_id, due_date,
a.completed,
f.name,
p.priority,
u.first_name,
u.last_name,
SUM(a.completed) as completed_sum
FROM form_assignments a
JOIN forms f ON (form_id = f.id)
JOIN users u ON (sender_id = u.id)
JOIN priorities p ON (priority_id = p.id)
WHERE recipient_id = '{$_SESSION['user_id']}'
ORDER BY due_date ASC";
And a while loop like this:
$assignment_count = (mysqli_num_rows($result));
$assignments_row = array();
while ($row = mysqli_fetch_array($result)) {
$sender = $row['first_name'] . ' ' . $row['last_name'];
$form_id = $row['form_id'];
$form_name = $row['name'];
$priority = $row['priority'];
$due_date = date('m/d/Y', strtotime($row['due_date']));
$completed = $row['completed'];
$not_done = $assignment_count - $row['completed_sum'];
}
And it's only returning one row. It seems my SUM(a.completed) as completed_sum is causing the issues because the query worked fine before I added it, but I want to add up all the values in completed to use in my $not_done variable.
Can anyone help clarify what I'm doing wrong?
When you use an aggregate function like SUM, all the results will be aggregated into one row unless you use a GROUP BY clause to segregate them. But it looks to me like you don't need a SUM in the first place. Your loop is subtracting this value from a total, so you just need the value from each row -- when you subtract them all you'll have subtracted the total. So just select a.completed rather than SUM(a.completed).
For $not_done, you need to initialize it before the loop:
$not_done = $assignment_count;
Then during the loop you should do a running subtraction:
$not_done -= $row['completed'];
Try this query :
SELECT
a.sender_id,
a.recipient_id,
a.form_id,
a.due_date,
a.completed,
f.name,
p.priority,
u.first_name,
u.last_name,
b.completed as completed_sum
FROM
form_assignments AS a
LEFT JOIN (
SELECT form_id,SUM(completed) FROM form_assignments GROUP BY form_id
) AS b ON (a.form_id = b.form_id)
LEFT JOIN forms AS f ON (form_id = f.id)
LEFT JOIN users AS u ON (sender_id = u.id)
LEFT JOIN priorities AS p ON (priority_id = p.id)
WHERE
recipient_id = '{$_SESSION['user_id']}'
ORDER BY due_date ASC

next / previous pagination query with parameters php mysql with parameters

I have the following problem: here is the structure of my tables
and here is my code:
$SQL_NEXT_PROJECT_ID ="SELECT id FROM projects WHERE id < '".$id_project."' and project_types_id='".$project_type_id."' ORDER BY id DESC LIMIT 1";
$conn->query($SQL_NEXT_PROJECT_ID);
foreach ($conn->query($SQL_NEXT_PROJECT_ID) as $rowProjectNext) {
$next_project_id = $rowProjectNext['id'];
}
$SQL_PREVIOUS_PROJECT_ID ="SELECT id FROM projects WHERE id > '".$id_project."' and project_types_id='".$project_type_id."' ORDER BY id ASC LIMIT 1";
$conn->query($SQL_PREVIOUS_PROJECT_ID);
foreach ($conn->query($SQL_PREVIOUS_PROJECT_ID) as $rowProjectPrevious) {
$previous_project_id = $rowProjectPrevious['id'];
}
the thing is that i need to put the query with an aditional condition from the 'images' table i have to evaluate the main field ='1', i have been trying to do it with a inner join but it doesnt seem to work, here i attach the query that i have been trying
$SQL_NEXT_PROJECT_ID ="SELECT projects.id FROM projects INNER JOIN images WHERE projects.id > '".$id_project."' and project_types_id='1' and main='1' ORDER BY projects.id DESC LIMIT 1";
Basically what i need to do is to create next / previous links to projects of certain type (project_types_id) based on the current id of the project ($id_project) taking into consideration the fact that the project should have a image that has the main field equal to '1'
hope i explained myself well...
Well youre not joining on anything... you need an ON clause.
SELECT pr.id FROM projects pr
INNER JOIN images img ON (pr.id = img.projects_id AND img.main = 1)
WHERE pr.id > ?
AND pr.project_types_id = 1
ORDER BY pr.id DESC LIMIT 1
at the end i did it like this
$_nextPrevious = array();
$SQL_SEARCH_VALUES="SELECT images.projects_id AS projectId FROM projects INNER JOIN images ON ( projects.id = images.projects_id ) AND project_types_id = '".$project_type_id."' AND images.main = '1' LIMIT 0 , 30";
$conn->query($SQL_SEARCH_VALUES);
foreach($conn->query($SQL_SEARCH_VALUES) as $rowNextPrevious) {
$value = $rowNextPrevious['projectId'];
array_push($_nextPrevious, $value);
}
$currentValue = array_search($id_project, $_nextPrevious);
$next = $currentValue + 1;
$previous = $currentValue - 1;
$next_project_id = $_nextPrevious[$next];
$previous_project_id = $_nextPrevious[$previous];
return array($project_name,$project_description,$project_path, $_images, $next_project_id, $previous_project_id);
using an array instead of two searches...

Using sql function min() in php loop

I have to output some products from table 'products', along with the lowest price from the table 'product_licenses', which is the only column I need from that table in this query.
However, when I try to use the sql function MIN(), my loop only runs through the code once and gets the first result and then it stops, so I am a bit lost here.
This is the query using min() :
$mysql->query("
SELECT pd.*, min(lc.price) AS price
FROM `products` AS pd, product_licenses AS lc
WHERE pd.`status` = '1' AND lc.product_id = pd.id
ORDER BY pd.`id` ASC
$limitQuery
");
I'm using this function to get the products, but this, unfortunately, fetches the highest price:
public function getAllProducts($start = 0, $limit = 0, $order = '`datetime` ASC') {
global $mysql;
$limitQuery = '';
if ($limit != 0) {
$limitQuery = " LIMIT $start,$limit ";
}
**// Not working if I use min() on lc.price**
$mysql->query("
SELECT pd.*, lc.price
FROM `products` AS pd, product_licenses AS lc
WHERE pd.`status` = '1' AND lc.product_id = pd.id
ORDER BY pd.`id` ASC
$limitQuery
");
if ($mysql->num_rows() == 0) {
return false;
}
$this->usersWhere = '';
$return = array();
while ($d = $mysql->fetch_array()) {
$categories = explode(',', $d['category_id']);
unset($d['category_id']);
foreach ($categories as $c) {
$c = trim($c);
if ($c != '') {
$d['category_id'][$c] = $c;
}
}
$return[$d['id']] = $d;
}
$this->foundRows = $mysql->getFoundRows();
return $return;
}
Add GROUP BY in your query. your current query returns only one result since your are using aggregate function (MIN) but not grouping it.
SELECT pd.col1,
pd.col2, min(lc.price) AS PRICE
FROM `products` AS pd
INNER JOIN product_licenses AS lc
ON lc.product_id = pd.id
WHERE pd.`status` = '1'
GROUP BY pd.col1, pd.col2, pd.col3
ORDER BY pd.`id` ASC
$limitQuery
PS: post the structure of your database with records. It will the community understands your question clearly :)
You have no group by clause in your query, so the query is returning the first row only.
SELECT pd.col1, pd.col2, pd.col3, min(lc.price) AS price
FROM `products` AS pd, product_licenses AS lc
WHERE pd.`status` = '1' AND lc.product_id = pd.id
group by pd.col1, pd.col2, pd.col3
ORDER BY pd.`id` ASC
$limitQuery
You'll need a GROUP BY in there, like so:
SELECT pd.*, min(lc.price) AS price
FROM `products` AS pd, product_licenses AS lc
WHERE pd.`status` = '1' AND lc.product_id = pd.id
GROUP BY pd.`id`
ORDER BY pd.`id` ASC
$limitQuery
Note that with MySQL, you only need to group by the id column even though you are selecting other columns from the products table.

Categories