Mysqli select multiple queries - php

I'm trying to select one query by using the user_id to get the categories specific to the user and then from there use the results from the first query to select data from a second table in a second query. The data from the second query I would like to display in a drop down menu. Is there any easy way to do this? I'm new to using mysqli so please bear with me.
I have the following function but it's not displaying anything in the dropdown menu, it is showing the drop down menu though.
function get_classes($mysqli) {
if(isset($_SESSION['user_id'], $_SESSION['username'], $_SESSION['login_string'])) {
$user_id = $_SESSION['user_id'];
if ($stmt = $mysqli->prepare("SELECT category_id
FROM questions WHERE user_id = ?")) {
$stmt->bind_param('i', $user_id);
$stmt->execute();
$stmt->store_result();
if($stmt->num_rows>0) {
$stmt->bind_result($category_id);
$stmt->fetch();
if($result = $mysqli->prepare("SELECT category_id, category_name
FROM category WHERE category_id = ?")) {
$result->bind_param('s', $category_id);
$result->execute();
$result->store_result();
}
}
echo "<select id='classes' name='classes'>";
while ($row = $result->fetch_assoc()) {
unset($user_id, $category_name);
$category_id = $row['category_id'];
$category_name = $row['category_name'];
echo '<option value="'.$category_id.'">'.$category_name.'</option>';
}
echo "</select>";
}
}
}
I'm calling the function from another page with the following code:
<?php
get_classes($mysqli);
?>

You can make all via one sql query:
SELECT c.category_id, c.category_name
FROM questions q
INNER JOIN category c ON c.category_id = q.category_id
WHERE q.user_id = ?

Alternatively, you could join them instead, then the normal fetching. Example:
function get_classes($mysqli) {
if(!isset($_SESSION['user_id'], $_SESSION['username'], $_SESSION['login_string'])) {
return false;
}
$user_id = $_SESSION['user_id'];
$sql = '
SELECT
category.category_id,
category.category_name
FROM category
JOIN questions
ON questions.category_id = category.category_id
WHERE questions.user_id = ?
';
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('i', $user_id);
$stmt->execute();
$result = $stmt->bind_result($category_id, $category_name);
// printing
echo '<select name="classes" name="classes">';
while($row = $stmt->fetch()) {
echo '<option value="'.$category_id.'">'.$category_name.'</option>';
}
echo '</select>';
}

Related

How to nest 2 SQL statements with a foreach loop inside each other

Okay I try with the first query to get all names of the computers from the table psComputers. Now I need in the second query a variable from the first query to iterate over all entries which are assigned to the respective computer in the table psTest. I wonder if such a thing is possible at all?
Table psComputer contains ID, name
Table psTest contains ID, computername, category, value
index.php
$statement = $pdo->prepare("SELECT * FROM psComputers ");
$statement->execute();
$result = $statement->fetchAll();
if ($statement->rowCount() > 0) {
foreach ($statement->fetchAll() as $row) {
$id = $row['ID'];
$name = $row['name'];
$statement2 = $pdo->prepare("SELECT * FROM psTest WHERE computerName = $name");
$statement2->execute();
$result2 = $statement2->fetchAll();
if ($statement2->rowCount() > 0) {
foreach ($statement2->fetchAll() as $row2) {
$id2 = $row2['ID'];
$computerName = $row2['computerName'];
$category = $row2['category'];
$value = $row2['value'];
}
}
}
}
You need quotes around $name in the second query, since it's a string.
$statement2 = $pdo->prepare("SELECT * FROM psTest WHERE computerName = '$name'");
But since you're using a prepared query, you should use a parameter instead of substituting a variable.
You also shouldn't call $statement->fetchAll() twice. The first call will read all the rows, and the second won't have anything left to read (it doesn't reset the cursor).
$statement = $pdo->prepare("SELECT * FROM psComputers ");
$statement->execute();
$result = $statement->fetchAll();
if (count($result) > 0) {
$statement2 = $pdo->prepare("SELECT * FROM psTest WHERE computerName = :name");
$statement2->bindParam(':name', $name);
foreach ($result as $row) {
$id = $row['ID'];
$name = $row['name'];
$statement2->execute();
$result2 = $statement2->fetchAll();
if (count($result2) > 0) {
foreach ($result2 as $row2) {
$id2 = $row2['ID'];
$computerName = $row2['computerName'];
$category = $row2['category'];
$value = $row2['value'];
}
}
}
}
But even better is to just join the two queries:
$statement = $pdo->prepare("
SELECT c.id AS computerID, c.name AS computerName, t.id AS testID, t.category, t.value
FROM psComputers AS c
JOIN psTest AS t ON c.name = t.computerName
ORDER BY c.id");
A couple things to note,
When using strings in queries, they must be quoted.
You are already preparing the statement - bind the value instead, and the note above becomes irrelevant.
You can use a JOIN instead of running a query in a loop. This will also remove the variable in the name, making both notes above irrelevant! (You should take note of both, but they become irrelevant for the code in question).
Its rarely a good idea to run a query within a loop.
$statement = $pdo->prepare("SELECT pt.*
FROM psTest pt
JOIN psComputers pc ON pt.computerName=pc.name");
$statement->execute();
$result = $statement->fetchAll();
if (count($result)) {
foreach ($result as $row) {
$id2 = $row['ID'];
$computerName = $row['computerName'];
$category = $row['category'];
$value = $row['value'];
}
}

loop parent record followed by children, parent and children etc

I have seen a few questions like this and variations of this but I am still confused as how to go about doing this. I have different dealers in different regions and want to list them by region in one long list.
West Coast
dealer 1
dealer 2
dealer 3
East Coast
dealer 1
dealer 2
dealer 3
And so on...
I have a database table with a list of regions and another table with a list of dealers.
The dealer table has a column which contains the region id from the regions table so I can join the tables.
I tried this:
$stmt = $link->prepare("SELECT `region_name`, `dealer_name` FROM `dealer_region` as `dr` INNER JOIN `dealers` as `d` ON dr.`id` = d.`region_id` GROUP BY `region_name`");
$stmt->execute();
$result = $stmt->get_result();
$numRows = $result->num_rows;
if($numRows > 0) {
while($row = $result->fetch_assoc()) {
$dealer_name = $row['dealer_name'];
$region_name = $row['region_name'];
echo $region_name . "<br />" . $dealer_name . "<br />";
}
}
$stmt->close();
But this only results in one dealer being shown under each region instead of all.
Instead of "GROUP BY region_name", you should use ORDER BY region_name. GROUP BY should only be used with aggregate functions (SUM, MIN, MAX, COUNT...). With ORDER BY, you will get the dealers by region.
Slight modification to your code included:
$stmt = $link->prepare("
SELECT region_name, dealer_name
FROM dealer_region as dr
INNER JOIN dealers as d ON dr.id = d.region_id
ORDER BY region_name
");
$stmt->execute();
$result = $stmt->get_result();
$numRows = $result->num_rows;
$region_name = null;
if($numRows > 0) {
while($row = $result->fetch_assoc()) {
if (is_null($region_name) || $region_name != $row['region_name']) {
$region_name = $row['region_name'];
echo '<b>' . $region_name . '</b><br>';
}
echo $row['dealer_name'].'<br>';
}
}
$stmt->close();
For what you want, you need to show the region once, and than a list of all dealers. What you are doing is showing per dealer also the region: because both are printed in the same loop.
In this situation it doesn't really make sense to use a join, since you don't need all the region information with each dealer.
in pseudo codo:
Select * from dealer_region
Loop over the results
echo $regionname
Select * from dealers where region_id = $dealerID
Loop over the results
echo $dealername
Edit: oke... query inside a loop is not eeh.. recommended
$stmt = $link->prepare("SELECT * FROM `dealer_region`");
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_assoc()) {
$regions[ $row['id'] ] = $row;
}
$stmt->close();
$stmt = $link->prepare("SELECT * FROM `dealers` ORDER BY `region_id`");
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_assoc()) {
$dealers[ $row['region_id'] ][ $row['id'] ] = $row;
}
$stmt->close();
foreach( $dealers AS $regionID => $dealers_)
{
echo '<b>'.$regions[ $regionID ].'</b>';
foreach($dealers_ AS $dealerID => $dealer )
{
echo $dealer['dealer_name'];
}
}
In case you want one query only, you need 3 loops...
$stmt = $link->prepare("SELECT `region_name`, `dealer_name` FROM `dealer_region` as `dr` INNER JOIN `dealers` as `d` ON dr.`id` = d.`region_id`");
$stmt->execute();
$result = $stmt->get_result();
while($row = $result->fetch_assoc()) {
$data[ $row['region_name'] ][] = $row;
}
$stmt->close();
foreach( $data AS $regionName => $dealers)
{
echo '<b>'.$regionName .'</b>';
foreach( $dealers AS $dealer )
{
echo $dealer['dealer_name'];
}
}

Alternate query using if statement in PHP

I'm trying to run an alternate query if the initial query fails (it does because the id I'm searching for in this instance only exists in one of the databases being joined) using an if statement and I've constructed it like so:
<?php
require_once($_SERVER['DOCUMENT_ROOT'].'/php/link_costreport_2013.php');
$id = $_GET['id']; //ID # For page/query
if($query = $link->prepare("SELECT locale.id, locale.provider_num, locale.provider_name, locale.state, locale.city,
finstat_ca.coh_and_banks, finstat_ca.temp_investments, finstat_ca.notes_receivable, finstat_ca.accounts_receivable, finstat_ca.other_receivables,
finstat_ca.afun_and_ar, finstat_ca.inventory, finstat_ca.prepaid_expenses, (finstat_ca.other_cur_assets + finstat_ca.due_from_other_funds) as other_cur_assets, finstat_ca.total_current_assets,
finstat_fa.total_fixed_assets,
finstat_olta.investments, (finstat_olta.dep_on_leases + finstat_olta.due_from_owners_officers + finstat_olta.other_assets) as all_olta, finstat_olta.total_other_assets, finstat_olta.end_assets,
finstat_cl.accounts_payable, finstat_cl.salaries_wages_fees_payable, finstat_cl.payroll_taxes_payable, finstat_cl.notes_loans_payable, finstat_cl.deferred_income, finstat_cl.total_current_liabilities,
(finstat_cl.total_current_liabilities - (finstat_cl.accounts_payable + finstat_cl.salaries_wages_fees_payable + finstat_cl.payroll_taxes_payable + finstat_cl.notes_loans_payable + finstat_cl.deferred_income)) as all_other_cl,
finstat_ltl.mortgage_payable, finstat_ltl.notes_payable, finstat_ltl.unsecured_loans, finstat_ltl.other_long_term_liabilities, finstat_ltl.total_long_term_liabilities,
finstat_talfb.total_fund_balance, finstat_talfb.total_lia_plus_fb
FROM `locale`
INNER JOIN `finstat_ca`
ON locale.id = finstat_ca.id
INNER JOIN `finstat_fa`
ON locale.id = finstat_fa.id
INNER JOIN `finstat_olta`
ON locale.id = finstat_olta.id
INNER JOIN `finstat_cl`
ON locale.id = finstat_cl.id
INNER JOIN `finstat_ltl`
ON locale.id = finstat_ltl.id
INNER JOIN `finstat_talfb`
ON locale.id = finstat_talfb.id
WHERE locale.id = :id
LIMIT 1")){
} else {
$query = $link->prepare("SELECT id, provider_num, provider_name, state, city
FROM `locale`
WHERE id = :id
LIMIT 1");
}
$query->bindParam(':id', $id);
$query->execute();
$results = $query->fetch(PDO::FETCH_ASSOC);
echo json_encode($results);
Basically it defaults to the single table where the ID does exist and only pulls a couple fields as opposed to the large statement above it. My only issue is that my code here is not working. My JSON only says false when I echo it. It obviously should not.
Is there an error in my code here?
Thanks in advance
:edit: I should note that when I enter an ID that exists in all the tables joined, the correct result (json) is displayed on the page.
I believe the problem is that even if ID does not exist in the first query, the $query variable still has a proper query in it and there is nothing false about it. That's not what you should be if-testing.
I think you should be testing $results.
This shows you the logic.
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . '/php/link_costreport_2013.php');
//ID # For page/query
$id = $_GET['id'];
$sql_1 = "SQL CODE FOR QUERY 1";
$sql_2 = "SQL CODE FOR QUERY 2";
$query = $link->prepare($sql_1);
$query->bindParam(':id', $id);
$query->execute();
$results = $query->fetch(PDO::FETCH_ASSOC);
if (!$results)
{
$query = $link->prepare($sql_2);
$query->bindParam(':id', $id);
$query->execute();
$results = $query->fetch(PDO::FETCH_ASSOC);
}
echo json_encode($results);
However as you can see there are a few lines of code that are repeated inside the if-statement that very similar to code that was just before the if-statement. Perhaps with a loop that loops twice but breaks out if $results is not false would be neater.
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . '/php/link_costreport_2013.php');
//ID # For page/query
$id = $_GET['id'];
$sql[] = "SQL CODE FOR QUERY 1";
$sql[] = "SQL CODE FOR QUERY 2";
foreach ($sql as $sql_query)
{
$query = $link->prepare($sql_query);
$query->bindParam(':id', $id);
$query->execute();
$results = $query->fetch(PDO::FETCH_ASSOC);
if ($results)
{
break;
}
}
echo json_encode($results);
The world is your oyster.

How to shuffle posts in two tables?

I was working on a post system..
So, I have to show posts by friends of the user and the groups in which user has participated..
Here is my code to show posts..
<?php
$sql = "SELECT * FROM posts WHERE uploader_id=:friend_id ORDER BY id DESC";
$query = $db->prepare($sql);
$query->execute(array(
":friend_id" => $friend_id
));
$rows = $query->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
$name = $row['name'];
echo "POST BY $name";
}
$sql = "SELECT * FROM group_posts WHERE id=:member_group ORDER BY id DESC";
$query = $db->prepare($sql);
$query->execute(array(
":member_group" => $group_id
));
$rows = $query->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
$name = $row['name'];
echo "POST BY $name";
}
?>
Now, I want all these posts to be shuffled in a way that all the posts of the post table and group_posts table are shown in the descending order.
UPDATE
I edited my code to this..
I figured out that first I'll have to code this before coding my post system..
<?php
$sql = "SELECT * FROM friends WHERE user_one=:me OR user_two=:me2 UNION SELECT * FROM group_members WHERE member_id=:me3";
$query = $db->prepare($sql);
$query->execute(array(
":me" => $my_id,
":me2" => $my_id,
":me3" => $my_id
));
$rows = $query->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows as $row) {
$user_one = $row['user_one'];
$user_two = $row['user_two'];
$group_id = $row['group_id'];
if ($user_one == $my_id) {
$friend_id = $user_two;
} else {
$friend_id = $user_one;
}
echo $friend_id . "<BR>" . $group_id;
}
?>
Now, here's the problem..
This is successfully printing the $friend_id but, it shows an undefined index 'group_id' while printing $group_id.
I have checked all the fields are correct.
Try using just one query with UNION
SELECT *
FROM (
SELECT name, id FROM posts WHERE uploader_id=:friend_id
UNION
SELECT name, id FROM group_posts WHERE id=:member_group
) p
ORDER BY p.id DESC
Note, your inner queries must return the same number of columns in the same order (and I think with the same name/alias, too).

Error with php function in "mysqli select" prepare statement

I create a function to call some data from database with left-join and prepare statement.
Here is the sketch of the php function:
function getStock()
{
global $mysqli;
$stmt = $mysqli->prepare
("SELECT products.`product_name`, product_category.`price`
FROM products
LEFT JOIN product_category
ON products.product_category_id = product_category.id
WHERE products.id = ?");
$id=3;
$stmt->bind_param("s", $id);
$stmt->execute();
$stmt->fetch();
return $stmt;
In the view page I do this:
$resultsTicket = getStock();
$results = $resultsTicket->num_rows;
var_dump($results);
if ($resultsTicket->num_rows > 0) {
while($resultsTicket->fetch()){
However in the var_dump I only get int(0)
I don't know anymore how to find the error there beside the var_dump. Please help me in the above code. Thank you!
[UPDATE]
$query = "SELECT products.`product_name`, product_category.`price`
FROM products
LEFT JOIN product_category
ON products.product_category_id = product_category.id
WHERE products.id = 3;
if ($stmt = $mysqli->prepare($query)) {
$stmt->execute();
$stmt->bind_result($product_name, $price);
//$stmt->fetch();
while ($stmt->fetch()) {
printf ("%s (%s)\n", $product_name, $price);
}
$stmt->close();}
return $stmt;
}
In the code above I get one data/row from database.
The problem is that you are executing and fetching within the function but returning the statement. There are two possible changes you can make.
Execute and fetch within the function, then loop through the results and return an array representing the results.
Return the statement from the function and perform the execute and fetch where you are using the result of the function.
I think you got enough help with the guys, If you still not sure how to code it, here you go:
Single record
$query = "SELECT products.`product_name`, product_category.`price`
FROM products
LEFT JOIN product_category
ON products.product_category_id = product_category.id
WHERE products.id = 3";
if ($stmt = $mysqli->prepare($query)) {
$stmt->execute();
$stmt->bind_result($product_name, $price);
$row = array();
while ($stmt->fetch()) {
$row = array('product_name'=>$product_name, 'price'=>$price);
}
$stmt->close();
}
return $row;
Multiple Record:
$query = "SELECT products.`product_name`, product_category.`price`
FROM products
LEFT JOIN product_category
ON products.product_category_id = product_category.id
WHERE products.id = 3";
if ($stmt = $mysqli->prepare($query)) {
$stmt->execute();
$stmt->bind_result($product_name, $price);
$rows = array();
while ($stmt->fetch()) {
$rows[] = array('product_name'=>$product_name, 'price'=>$price);
}
$stmt->close();
}
return $rows;
Example in PDO:
$query = "SELECT products.`product_name`, product_category.`price`
FROM products
LEFT JOIN product_category
ON products.product_category_id = product_category.id
WHERE products.id = 3";
if ($stmt = $pdo->prepare($query)) {
$stmt->execute();
$rows = $stmt->fetchAll();
}
return $rows;

Categories