Two tables, display multiple results from one matching the ID - php

I have two tables:
post_languages with the following columns: languageID, languageName
post_to_languages with: postID, postLanguage
What I'm trying to achieve is to display all languages associated with a post.
example: Post 1, languages: French, Russian
Maybe my approach is wrong but this is one of the methods I have tried:
//get language id
$stmt2 = $db->prepare('SELECT languageID FROM post_to_languages WHERE postID = :postID');
$stmt2->execute(array(':postID' => $row['postID']));
//Count total number of rows
$rowCount2 = $stmt2->rowCount();
if ($rowCount2 > 0) {
$row2 = $stmt2->fetch(PDO::FETCH_ASSOC);
foreach ($row2 as $langID) {
$stmt3 = $db->prepare('SELECT languageName FROM post_languages WHERE languageID = :languageID');
$stmt3->execute(array(':languageID' => $langID));
$row3 = $stmt3->fetch();
$lang_string = $row3['languageName'];
}
} else {
$lang_string = "Unknown";
}
Doesn't matter what I tried, I get only one language. Maybe I should select post_to_languages by ID first.

You don't need this nested loop, try a join or a subquery. Showing you a subquery. If you have a large number of rows, an inner join will be faster. But a subquery is still heaps faster than a nested loop.
SELECT languageName FROM post_languages WHERE languageID IN
(SELECT languageID FROM post_to_languages WHERE postID = :postID')
If you still don't see any results, replace :postID with a real value and try it in the console.

you are selected different column from diff. table.
in table post_to_language must be same datatype as languageId.
please try this code
//get language id
$stmt2 = $db->prepare('SELECT postLanguage FROM post_to_languages WHERE postID = :postID');
$stmt2->execute(array(':postID'=>$row['postID']));
//Count total number of rows
$rowCount2 = $stmt2->rowCount();
if($rowCount2 > 0){
$row2 = $stmt2->fetch(PDO::FETCH_ASSOC);
foreach($row2 as $langID) {
$stmt3 = $db->prepare('SELECT languageName FROM post_languages WHERE languageID = :languageID');
$stmt3->execute(array(':languageID'=>$langID));
$row3 = $stmt3->fetch();
$lang_string = $row3['languageName'];
}
} else {
$lang_string = "Unknown";
}
Thank you.

Related

Deleting a row with inner join

I've created two tables, simplecomments and commentors, and connected them with INNER JOIN.
Simplecomments is details of each and every commenter, involving their comment, reg_date, commentorid etc...
Commentors is the personal info of a commenter with following columns: id, name, email..
I've joined them successfully, however I'm finding it hard to delete from the joined table.
I want to make it like this logic:
If there's last row of a commentor called --let's say A-- then delete both his/her comment details and A himself/herself from the table.
Else if A has commented plenty of times, with different comments, delete his/her comment details, but let his/her personal info remain since A has other comments there.
This is how I've made it:
if (!empty($_POST["delete"]))
{
foreach ($_POST["delete"] as $key => $value)
{
$resultid = $conn->query("SELECT commentorid FROM `simplecomments` WHERE id=".$value);
$rowid = $resultid->fetch_assoc();
$outputdelete = $rowid["name"] . " has been deleted" . "<br>";
$deletedname = $deletedname.$outputdelete;
$RES = mysql_num_rows($resultid);
$counter = 0;
while($row = $RES)
{
//IF IT'S LAST ROW, DELETE COMMENTOR AND HIS/HER COMMENTDETAILS
if(++$counter == $results) {
$resultid = $conn->query("DELETE FROM `commentor`");
}
//ELSE JUST DELETE HIS/HER COMMENTDETAILS, LET HIS/HER INFO REMAIN
else{
$resultid = $conn->query("DELETE FROM `simplecomments` WHERE id=".$value);
}
}
}
}
However code won't work. I get an error:
Warning: mysql_num_rows() expects parameter 1 to be resource [..]...
Consider running DELETE...INNER JOIN and DELETE with subquery conditionals and avoid PHP query fetch looping with if/else as the logic seems to be the following:
delete any commentor's profile and comments if he/she has only one comment
delete only commentor's comments if he/she has multiple (i.e., more than one) comments.
And yes, all three DELETE can be run at same time across all ids since mutually exclusive conditions are placed between the first two and last one. Therefore, either first two affects rows or last one affects rows per iteration. The unaffected one(s) will delete zero rows from either table.
Also, simplecomments records are deleted first since this table may have a foreign key constraint with commentor due to its one-to-many relationship. Finally, below assumes comment ids are passed into loop (not commentor id).
PHP (using parameterization, assuming $conn is a mysqli connection object)
foreach ($_POST["delete"] as $key => $value) {
// DELETE COMMENTS AND THEN PROFILE FOR COMMENTORS WITH ONE POST
$sql = "DELETE FROM `simplecomments` s
WHERE s.id = ?
AND (SELECT COUNT(*) FROM `simplecomments` sub
WHERE sub.commentorid = s.commentorid) = 1";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $value);
$stmt->execute();
$stmt->close();
$sql = "DELETE c.* FROM `simplecomments` c
INNER JOIN `simplecomments` s ON s.commentorid = c.id
WHERE s.id = ?
AND (SELECT COUNT(*) FROM `simplecomments` sub
WHERE sub.commentorid = s.commentorid) = 1";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $value);
$stmt->execute();
$stmt->close();
// DELETE COMMENTS FOR COMMENTORS WITH MULTIPLE POSTS BUT KEEP PROFILE
$sql = "DELETE FROM `simplecomments` s
WHERE s.id = ?
AND (SELECT COUNT(*) FROM `simplecomments` sub
WHERE sub.commentorid = s.commentorid) > 1";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $value);
$stmt->execute();
$stmt->close();
}
Alternatively, for a DRY-er approach, loop SQL statements in an array:
$sqls = array(
0 => "DELETE FROM `simplecomments` s WHERE s.id = ? AND (SELECT COUNT(*) FROM `simplecomments` sub WHERE sub.commentorid = s.commentorid) = 1",
1 => "DELETE c.* FROM `simplecomments` c INNER JOIN `simplecomments` s ON s.commentorid = c.id WHERE s.id = ? AND (SELECT COUNT(*) FROM `simplecomments` sub WHERE sub.commentorid = s.commentorid) = 1",
2 => "DELETE FROM `simplecomments` s WHERE s.id = ? AND (SELECT COUNT(*) FROM `simplecomments` sub WHERE sub.commentorid = s.commentorid) > 1"
);
foreach ($_POST["delete"] as $key => $value) {
foreach($sqls as $sql) {
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $value);
$stmt->execute();
$stmt->close();
}
}

get required result in sql

i have a sql database having two columns
1. id and 2. parent_id
i want to select all ids where parent_id=1 [let the results saved in X array] then,
select all the ids where parent_id in X[] [let the results saved in Y array] then... do the same upto 7 levels at last i want to sum all levels and get that sum in a variable name "number"
what i tried:
$sql = "SELECT count(id) as leadersearch FROM `$database`.`$mem` where parent_id = ".$parent[id];
$result = mysqli_query($con, $sql);
$lv1 = mysqli_fetch_array($result);
then again
$sql = "SELECT count(id) as leadersearch FROM `$database`.`$mem` where parent_id in ($lv1)";
$result = mysqli_query($con, $sql);
$lv2 = mysqli_fetch_array($result);
and so on.... it may give me required result but it is too much code...
i want to the same by using a loop or something else... to shorten the code.
Your first query gets count(id) and then second query uses it to get results. It seems you have many flaws in your requirement to begin with.
However, for your question you can use sub-query like following
$sql = "SELECT count(id) as leadersearch
FROM `$database`.`$mem`
WHERE parent_id in (
SELECT id FROM `$database`.`$mem` where parent_id = ".$parent['id']."
)";
$result = mysqli_query($con, $sql);
$lv2 = mysqli_fetch_array($result);
If you have many level nesting and you want to search records like this then you can consider functions:
function getLeader($parent_id){
$results = [];
$sql = "SELECT id as leadersearch FROM `$database`.`$mem` where parent_id in (".$parent_id.")";
$result = mysqli_query($con, $sql);
foreach($row = mysqli_fetch_array($result)){
$results[] = $row['id'];
}
return $results;
}
$leaders = [];
$ids = getLeader($parent['id']);
foreach($ids as $id){
$leaders[$id] = getLeader($id);
}

How can I show rows from one table that aren't in another table?

I have two tables in a database, one of them is a list of 'buildings' you could create. The other is a list of buildings that have been built by users.
On one page, (cityproduction.php), it displays a list of 'buildings' you can build.
I want it to display the buildings that you can build, that you haven't already built.
Here is my code:
$sql = "SELECT * FROM [The list of built buildings] WHERE building_owner = '$user'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$variable = $row["building_name"];
}
(...)
$sql = "SELECT * FROM [The list of ALL buildings] WHERE name != '$variable' ORDER BY id asc";
$result = mysqli_query($database,$sql) or die(mysqli_error($database));
while($rws = mysqli_fetch_array($result)){
echo $rws["name"]; (etc.)
What this is doing is only not-showing one of the buildings that the user has built, not all of them.
Without seeing the real table names or the schema it is tricky to answer accurately but you could try something along these lines:
SELECT * FROM `all_buildings`
WHERE `id` not in (
select `building_id` from `built_buildings` where `building_owner` = '$user'
)
ORDER BY `id` asc;
Another translation of your question into SQL (besides NOT IN) results in a Correlated Subquery:
SELECT * FROM `all_buildings` AS a
WHERE NOT EXISTS
(
select * from `built_buildings` AS b
where a.`id` = b.`building_id` -- Outer Select correlated to Inner
and b.`building_owner` = '$user'
)
ORDER BY `id` asc;
The main advantage over NOT IN: it's using only two-valued-logic (NULL is ignored = false) while NOT IN uses three-valued-logic (comparison to NULL returns unknown which might no return what you expect)
Why are you using while after the first query, it suppose to be a list or just a single value? because if you use $variable in your second query it will only have the value of the last value of the list you are getting
if ($result->num_rows > 0) {
$variable = array();
while($row = $result->fetch_assoc()) {
$variable[] = $row["building_name"];
}
Second query example:
foreach($variable as $building) {
$sql = "SELECT * FROM [The list of ALL buildings] WHERE name != '$building' ORDER BY id asc";
$result = mysqli_query($database,$sql) or die(mysqli_error($database));
$result = mysqli_fetch_assoc($result);
echo $result["name"];
}
Assuming both of your tables have some sort of id column to relate them, with this query:
SELECT building_name, building_owner FROM
test.all_buildings a
LEFT JOIN test.built_buildings b ON a.id = b.building_id AND b.building_owner = ?
ORDER BY building_owner DESC, building_name;
(where ? is the user), you can select all the buildings, first the ones that have been built, followed by the ones that haven't, in one query. If your tables don't have id's like that, you can join them on name instead; it should work as long as the names are distinct.
Then as you fetch the rows, you can sort them into "built" or "not built" by checking if the row has a building_owner.
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
if ($row['building_owner']) {
$built[] = $row['building_name'];
} else {
$not_built = $row['building_name'];
}
}
}

Query inside while loop repeats results from 2 tables

I am not sure if the title expresses the problem accurately or not. Anyways, here is the explanation:
I have 2 tables, the first one holds users IDs, the other one holds their posts.
The fist query selects user IDs from the fist table, and it loop through the second table to find the users (IDs) posts.
The problem is that when the query finds eg. 5 results (user IDs 1, 6, 999.. etc) in the fist table, then it loops 5 times to search in the second table, it shows 5 results even if the real results is 2 post only created by user 1 and 6.
How can I avoid this repeatation?
Here is the code:
$stmt = $conn->prepare('select userid from table where para=?');
$stmt->bind_param('i', $para);
$stmt->execute();
$result = $stmt->get_result();
while( $row = $result->fetch_assoc()) {
$userid = $row["userid "];
$qname = "select postid,title from posts where uid='$userid'";
$result2 = $conn->query($qname);
$row2 = $result2->fetch_array(MYSQLI_ASSOC);
if ($row2 > 0) {
$postid= $row2['postid'];
$title= $row2['title'];
}
echo $postid." ".$title."<br>";
}
Try
$qname = "select postid,title from posts as P left join table as T on T.userid=P.uid where where para=?";
Or
You can store the results in a common array during the loop.
like
$tempResult = array();
while( $row = $result->fetch_assoc()) {
$userid = $row["userid "];
$qname = "select postid,title from posts where uid='$userid'";
$result2 = $conn->query($qname);
$row2 = $result2->fetch_array(MYSQLI_ASSOC);
if ($row2 > 0) {
$tempResult[$userid][] = $row2['postid'];
$tempResult[$userid][] = $row2['title'];
}
}
you can try this query using a JOIN MYSQL.
SELECT u.userid,p.postid,p.title FROM TABLE `user` u
JOIN posts p ON
p.uid = u.userid
WHERE para=?
You can avoid it by only running one query that joins the two tables together. Something like this:
<?php
$stmt = $conn->prepare('select posts.* from table t inner join posts p on t.userid = p.uid where t.para = ? order by uid');
$stmt->bind_param('i', $para);
$stmt->execute();
$result = $stmt->get_result();
while( $row = $result->fetch_assoc()) {
// $row now has userid, and all post details
}
?>

How to Get another value in another table using a dynamic call

I currently have this query with an array that outputs the variables within using a dynamic input in my form (term), this creates a Dynamic Search with auto complete to fill in all of the details for a product.
$return_arr = array();
$param = $_GET["term"];
$fetch = mysql_query("SELECT * FROM crd_jshopping_products WHERE `name_en-GB` REGEXP '^$param'");
while ($row = mysql_fetch_array($fetch, MYSQL_ASSOC)) {
//$row_array['category_id'] = $row ['category_id'];
$row_array['product_id'] = $row['product_id'];
$row_array['product_names'] = $row['name_en-GB'];
$row_array['jshop_code_prod'] = $row['product_ean'];
$row_array['_ext_price_html'] = number_format($row['product_price'],2);
if (!empty($row['product_thumb_image']) AND isset($row['product_thumb_image'])){
$row_array['image'] = $row['product_thumb_image'];
}else {
$row_array['image'] = 'noimage.gif';
}
array_push( $return_arr, $row_array);
}
mysql_close($conn);
echo json_encode($return_arr);
Unfortunately I also need to get the category_id which is not in the same table, I have tried to modify my query as such, but to no avail:
$fetch = mysql_query("SELECT * FROM crd_jshopping_products WHERE `name_en-GB` REGEXP '^$param' AND `crd_jshopping_products_to_categories` = `product_id` ");
What step am I missing here ? The product_id's match in both tables?
try this query instead and try to understand what I have written in it:
$fetch = mysql_query("
SELECT
p.*,
c.category_id
FROM
crd_jshopping_products as p
INNER JOIN crd_jshopping_products_to_categories as c
ON p.product_id = c.product_id
WHERE
`p.name_en-GB` REGEXP '^$param'
");
This means:
SELECT:
Give me everything from p and the category_id from c.
FROM:
Do this from rows in the tables crd_jshopping_products (referred to as p) and crd_jshopping_products_to_categories (referred to as c), where the rows match on the count of p.product_id is the same as c.product_id.
WHERE:
Only return the rows where p.name_en-GB REGEXP '^$param'.

Categories