As part of my learning OOP PHP, I have made a database object that includes the following method:
public static function find_by_sql($sql="") {
global $database;
$result_set = $database->query($sql);
$object_array = array();
while ($row = $database->fetch_array($result_set)) {
$object_array[] = static::instantiate($row);
}
return $object_array;
}
and I can use this to retrieve and access data from a single table, however when I try to use it with joined tables, the object only gives me the data from the primary table e.g.
$sql = "SELECT s.name, m.id, m.firstName, m.lastName, m.dob";
$sql .= " FROM members AS m";
$sql .= " LEFT JOIN mbr_sections AS ms ON m.id = ms.member_id";
$sql .= " LEFT JOIN sections AS s ON ms.section_id = s.id";
$sql .= " ORDER BY s.organisation ASC, s.name ASC, m.lastName ASC, m.firstName ASC";
$sql .= " LIMIT {$per_page} ";
$sql .= " OFFSET {$pagination->offset()}";
$members = Member::find_by_sql($sql);
Using the above query the following code outputs nothing for the s.name field, but all the fields from the members table are correctly listed. I know that the MySQL query is accessing the data, as the ORDER BY statement is correctly sorting the output.
<?php foreach($members as $member): ?>
<tr>
<td><?php echo $member->name;?></td>
<td><?php echo $member->full_name();?></td>
<td><?php echo $member->getAge($member->dob);?></td>
<td>Edit</td>
<td>Delete</td>
</tr>
<?php endforeach; ?>
If I output $members with print_r($members) it only contains the data from the members table, how do I access the data retrieved from the other tables?
Thanks
You need to select them too here:
$sql = "SELECT s.name, m.id, m.firstName, m.lastName, m.dob";
$sql .= " FROM members AS m";
$sql .= " LEFT JOIN mbr_sections AS ms ON m.id = ms.member_id";
$sql .= " LEFT JOIN sections AS s ON ms.section_id = s.id";
$sql .= " ORDER BY s.organisation ASC, s.name ASC, m.lastName ASC, m.firstName ASC";
$sql .= " LIMIT {$per_page} ";
$sql .= " OFFSET {$pagination->offset()}";
$members = Member::find_by_sql($sql);
You only selected name, id, firstName, lastName and dob.
Here is an example:
$sql = "SELECT s.name, m.id, m.firstName, m.lastName, m.dob, mbr_sections.field_you_want, sections.*";
Related
for the past few hours, I have been trying to find a simple method of while loop echoing information from multiple tables at once. I'd like to say I've not pulled all my hair out looking, but I have.
Here is one mysqli query to get the following fields from CUSTOMER
$tid = $_SESSION['user_id']; // "id" is 1 for example
$query = "SELECT * FROM `CUSTOMER` WHERE user_id = {$tid}";
$results = mysqli_query($dbconnection, $query);
while ($row = mysqli_fetch_array($results)) {
echo $row['user_id'] . "<br><br>";
echo $row['c_fname'] . "<br>";
echo $row['c_sname'] . "<br>";
};
Here is another mysqli query to get the following fields from SALE
$query = "SELECT * FROM `SALE` WHERE user_id = {$tid}";
$results = mysqli_query($dbconnection, $query);
while ($row = mysqli_fetch_array($results)) {
echo $row['s_date'] . "<br>";
echo $row['s_total'] . "<br>";
};
Could someone possibly show me how I can get both of these tables in one query so that echoing both tables information is possible at the same time instead of separately. I am not fussed how it is done, As long as it gets all from both tables for echoing purpose, that is good.
You can do it by using LEFT JOIN like this.
SELECT column_name(s)
FROM table1
LEFT JOIN table2 ON table1.column_name = table2.column_name;
And this is your code.
$query = "SELECT * FROM `CUSTOMER` LEFT JOIN `SALE` ON `SALE`.user_id=`CUSTOMER`.user_id WHERE `SALE`.user_id={$tid}";
$results = mysqli_query($dbconnection, $query);
while ($row = mysqli_fetch_array($results)) {
echo $row['user_id'] . "<br><br>";
echo $row['c_fname'] . "<br>";
echo $row['c_sname'] . "<br>";
echo $row['s_date'] . "<br>";
echo $row['s_total'] . "<br>";
}
For more info read this,
https://www.w3schools.com/sql/sql_join_left.asp
I hope this helps.
EDITED
This is for joining 3 tables,
SELECT column_name(s)
FROM table1
LEFT JOIN table2 ON table1.column_name = table2.column_name;
LEFT JOIN table3 ON table1.column_name = table3.column_name;
In your code.
SELECT * FROM `CUSTOMER`
LEFT JOIN `SALE` ON `CUSTOMER`.user_id = `SALE`.user_id
LEFT JOIN `PRODUCTS` ON `CUSTOMER`.user_id = `PRODUCTS`.user_id
WHERE `SALE`.user_id={$tid};
As variable.
$query = "SELECT * FROM `CUSTOMER` LEFT JOIN `SALE` ON `CUSTOMER`.user_id = `SALE`.user_id LEFT JOIN `PRODUCTS` ON `CUSTOMER`.user_id = `PRODUCTS`.user_id WHERE `SALE`.user_id={$tid}";
You can use the following code and will help u solve Ur problem
$query = "SELECT C.*,S.* FROM CUSTOMER C,SALES S
WHERE C.user_id={$tid}
and C.user_id=S.user_id;
while ($row = mysqli_fetch_array($results)) {
echo $row['C.user_id'] . "<br><br>";
echo $row['C.c_fname'] . "<br>";
echo $row['C.c_sname'] . "<br>";
echo $row['S.s_date'] . "<br>";
echo $row['S.s_total'] . "<br>";
};
You can simply join the tables to get your expected result as shown below.
$query = "SELECT c.user_id, c.c_fname, c.c_sname, s.s_date, s.s_total FROM `CUSTOMER` AS c INNER JOIN `SALE` AS s ON c.user_id = s.user_id WHERE c.user_id = {$tid}";
Joining 3 tables example
$query = "SELECT *
FROM `CUSTOMER` AS c
INNER JOIN `SALE` AS s ON c.user_id = s.user_id
INNER JOIN `PRODUCTS` AS p ON p.product_id = s.product_id
WHERE c.user_id = {$tid}";
I would like to get data from two tables in MySQL, ordered by date.
$sql = "
SELECT
items.*, invoice.*
FROM
items
JOIN
invoice
ON
items.user_id = invoice.buyer_id
WHERE
items.user_id = '$user_id'"
LIMIT
10
ORDER BY
date;
";
Try with:
$sql = "SELECT *";
$sql .= " FROM items, invoice";
$sql .= " WHERE items.user_id = invoice.buyer_id";
$sql .= " AND items.user_id = '$user_id'";
$sql .= " ORDER BY date DESC";
$sql .= " LIMIT 10";
Also it is better if you use it as a prepared statement instead of having the variable inside the SQL query to avoid SQL injection.
I would like someone to explain me why the first method works only after quoting the placeholder ':cat_id' in the WHERE clause, and requires the $this->db->query($query);, otherwise it throws fatal error:
"SQLSTATE[HY093]: Invalid parameter number: number of bound variables
does not match number of tokens in..."
while the second method doesn't need neither quoting and the $this->db->query() method?
public function getAllPosts($cat_id = null)
{
// Query build
$query = "SELECT posts.*, users.username, categories.title FROM posts "
. "INNER JOIN users "
. "ON posts.user_id = users.id "
. "INNER JOIN categories "
. "ON posts.category_id = categories.id ";
// Filter
if (!is_null($cat_id))
{
$query .= "WHERE category_id = ':cat_id' ";
// Order query
$query .= "ORDER BY create_date DESC";
$this->db->bind(':cat_id', $cat_id);
}
else
{
$query .= "ORDER BY create_date DESC";
}
$this->db->query($query);
// Run the query
// Assign Result Set
$results = $this->db->resultset();
return $results;
}
public function getCategoryPosts($cat_id)
{
$query = "SELECT posts.*, users.username, categories.title FROM posts "
. "INNER JOIN users "
. "ON posts.user_id = users.id "
. "INNER JOIN categories "
. "ON posts.category_id = categories.id "
. "WHERE posts.category_id = :cat_id "
. "ORDER BY create_date DESC";
$this->db->bind(':cat_id', $cat_id);
$results = $this->db->resultset();
return $results;
}
Update:
Here are a echo output of the query from the first method:
1. with quoted:
SELECT posts.*, users.username, categories.title FROM posts
INNER JOIN users ON posts.user_id = users.id
INNER JOIN categories ON posts.category_id = categories.id
WHERE category_id = ':cat_id' ORDER BY create_date DESC
2. unquoted:
SELECT posts.*, users.username, categories.title FROM posts
INNER JOIN users ON posts.user_id = users.id
INNER JOIN categories ON posts.category_id = categories.id
WHERE category_id = :cat_id ORDER BY create_date DESC
You are missing a trailing space on the following string
$query .= "WHERE category_id = ':cat_id'";
So you are concatenating it into:
WHERE category_id = ':cat_id'ORDER BY create_date DESC
If you remove the ', you would get:
WHERE category_id = :cat_idORDER BY create_date DESC
So PDO expects a bound value for :cat_idORDER
Also in getCategoryPosts() you create a query but never actually use it.
This question already has answers here:
mysqli_stmt::bind_result(): Number of bind variables doesn't match number of fields in prepared statement
(2 answers)
Closed 1 year ago.
I have the following mysql query which am executing in my php script:
$qr = "Select p.productID,p.productDesc,p.productQty,";
$qr .= "p.productPr,p.type,p.gender,p.date From";
$qr .= " products AS p";
$qr .= " INNER JOIN(Select c.productID, GROUP_CONCAT(";
$qr .= "DISTINCT c.availCol) AS color_list FROM";
$qr .= " availColors AS c GROUP BY c.productID) AS colors";
$qr .= " ON p.productID = colors.productID":
$qr .= " INNER JOIN(SELECT s.productID, GROUP_CONCAT";
$qr .= "(s.availSizes) AS size_list FROM availSizes AS s";
$qr .= " GROUP BY s.productID) AS sizes ON p.productID";
$qr .= " = sizes.productID";
$qr .= " INNER JOIN(SELECT avp.productID, avp.productImg";
$qr .= " FROM availImg AS avp ORDER BY avp.productID";
$qr .= " LIMIT 3) AS images ON images.productID = ";
$qr .= " p.productID";
$qr .= " WHERE p.productID = ?";
$qr .= " GROUP BY p.productID";
$stm = $mysqli->prepare($qr);
$stm->bind_param('s',$id);
$stm->execute();
$stm->store_result();
If($stm->num_rows == 1){
$stm->bind_result($pid,$desc,$qty,$pr,$type,$gender,
$date,$colID,$color,$sizeID,$sizes,$imgID,$imgUrl);
$stm->fetch();
......
}
When I execute the script I get an error saying:
Mysqli_stmt::bind_result(): Number of bind variables doesn't
Match number of fields in the prepared statement in...
I understand what this error means, but I have rechecked and recounted the number of bind variables in the bind_result() against the number of SELECTed columns, I just can't figure out what is wrong. I don't know how PHP evaluates values returned from a mysql subquery. Can anyone offer help on this? I have been on this all day! Thanks for any help!
$qr = "
Select
p.productID,
p.productDesc,
p.productQty,
p.productPr,
p.type,
p.gender,
p.date
From
products AS p
INNER JOIN(
Select
c.productID,
GROUP_CONCAT(DISTINCT c.availCol) AS color_list
FROM
availColors AS c GROUP BY c.productID) AS colors
ON
p.productID = colors.productID
INNER JOIN(
SELECT
s.productID,
GROUP_CONCAT(s.availSizes) AS size_list
FROM
availSizes AS s
GROUP BY
s.productID
) AS sizes
ON
p.productID = sizes.productID
INNER JOIN(
SELECT
avp.productID,
avp.productImg
FROM
availImg AS avp
ORDER BY
avp.productID
LIMIT
3) AS images
ON
images.productID = p.productID
WHERE
p.productID = ?
GROUP BY
p.productID";
Try formatting your query like this muti-line strings are perfectly fine in PHP, and it's almost impossible to make sense of it concatenated line by line. If I have it right you are missing at least a closing parentheses in there, the first inner join open parentheses is not closed.
You are only joining your other tables/columns not selecting the columns. Try adding the columns to the beginning of the query (before the FROM)
$qr = "SELECT p.productID,p.productDesc,p.productQty,";
$qr .= "p.productPr,p.type,p.gender,p.date,";
// colors columns
$qr .= "colors.productID, colors.color_list,";
// sizes columns
$qr .= "sizes.productID, sizes.size_list,";
// images columns
$qr .= "images.productID, images.productImg ";
$qr .= "From products AS p";
$qr .= " INNER JOIN(Select c.productID, GROUP_CONCAT(";
$qr .= "DISTINCT c.availCol) AS color_list FROM";
$qr .= " availColors AS c GROUP BY c.productID) AS colors";
$qr .= " ON p.productID = colors.productID":
$qr .= " INNER JOIN(SELECT s.productID, GROUP_CONCAT";
$qr .= "(s.availSizes) AS size_list FROM availSizes AS s";
$qr .= " GROUP BY s.productID) AS sizes ON p.productID";
$qr .= " = sizes.productID";
$qr .= " INNER JOIN(SELECT avp.productID, avp.productImg";
$qr .= " FROM availImg AS avp ORDER BY avp.productID";
$qr .= " LIMIT 3) AS images ON images.productID = ";
$qr .= " p.productID";
$qr .= " WHERE p.productID = ?";
$qr .= " GROUP BY p.productID";
I finally figured it out, thanks to MYSQL Workbench! I ran the query on mysql workbench and counted the number of columns returned, and declared variables for each on the bind_result().
I like to use self explaining names for associative selects, and sometimes it's even mandatory to avoid duplicates, so I use the AS keyword alot. But it's giving me some trouble with left joins.
This works:
$sql = "SELECT *,
projects.id as projects_id
FROM projects";
$sql .= " LEFT JOIN".
" (SELECT
projectfiles.id as projectfiles_id,
projectfiles.fileID as projectfiles_fileID,
projectfiles.projectID as projectfiles_projectID
FROM projectfiles
) AS projectfiles".
" ON projects.id = projectfiles_projectID";
However now I end up with useless data from projects, because it also picks up the fields userID and name, which I don't need. It's also picking up the id twice.
So I tried changing it to;
$sql = "SELECT
projects.id as projects_id
FROM projects";
With the ON line becoming
" ON projects_id = projectfiles_projectID";
But that gave the error Unknown column projects_id
So I tried
" ON projects.projects_id = projectfiles_projectID";
But still the same error
I then started experimenting, and tried (as a test)
$sql = "SELECT id,name,userID FROM projects";
$sql .= " LEFT JOIN".
" (SELECT
projectfiles.id as projectfiles_id,
projectfiles.fileID as projectfiles_fileID,
projectfiles.projectID as projectfiles_projectID
FROM projectfiles
) AS projectfiles".
" ON projects.id = projectfiles_projectID";
And to my surprise, the LEFT JOIN didn't seem to pick up anything at all.
Code:
$sql = "SELECT id,name,userID FROM projects";
$sql .= " LEFT JOIN".
" (SELECT
projectfiles.id as projectfiles_id,
projectfiles.fileID as projectfiles_fileID,
projectfiles.projectID as projectfiles_projectID
FROM projectfiles
) AS projectfiles".
" ON projects.id = projectfiles_projectID";
$res = mysql_query($sql);
if(!$res) die(mysql_error());
if(mysql_num_rows($res) > 0)
{
$rownum = 0;
while($row = mysql_fetch_assoc($res))
{
print_r($row);
echo "<br/><br/>";
$rownum++;
}
}
Output:
Which is weird because there is only one row in projects but 3 in projectfiles with that projectID... what am I doing wrong?
To select only from the projectfiles table:
$sql = "SELECT projectfiles.*,
projects.id as projects_id
FROM projects";
// rest of the code is the same
Update
$sql = "SELECT projectfiles.* FROM projects";
// rest of the code is the same
Use short form of the query:
$sql = "SELECT projects.id,projects.name,projects.userID FROM projects LEFT JOIN
projectfiles ON projects.id = projectfiles.projectID";
SELECT p.*, pf.id, pf.fileId
FROM projects p LEFT JOIN projectfiles pf
on p.id = pf.projectID
You can use "as" to do as you will then. No need for a subselect.
$sql = "SELECT p.id,p.name,p.userID FROM projects p";
$sql .= " LEFT JOIN".
" projectfiles pf ".
" ON p.id = p.projectID";
$sql = "SELECT prj.id as prjId,
prj.name as prjName,
prj.userID as prjUid,
pf.id as pfId,
pf.fileID as pfFileId,
pf.projectID as pfProjecId
FROM projects as prj
LEFT JOIN projectfiles AS pf
ON prj.id = pf.projectID";