I'm trying to get data from two tables: users and posts using left join.
$items = '';
$sql = "
SELECT u.id as uid
, u.name as uname
, p.id as pid
, p.date as pdate
, p.title as ptitle
, p.user as puser
FROM users u
LEFT
JOIN posts p
ON u.id = p.user
WHERE u.role = 'mod'
GROUP
BY p.title;";
$stmt = $db->query($sql);
while($row = $stmt->fetch()){
$date = strtotime($row['pdate']);
$date = date("d-m-Y", $date);
$items.= "<div class='itemp' data-id=" . $row['pid'] . " data-user='" . $row['uname'] . "'>" .
"<span class='spandate'>" . $date . "</span>" .
"<span class='spantitle'>" . $row['ptitle'] . "</span>" .
"<span class='spanuser'>" . $row['uname'] . "</span>" .
"</div>\n";
}
echo $items;
Output is ok except first row where I see the date - 1.1.1970 - but there is no any row in posts with that date. Plus - in the same row ptitle is missing.
Also, is there a better way to create this query, avoiding as keyword ?
desired output (single block):
<div class='itemp' data-id=116 data-user='JOHN SMITH'><span class='spandate'>01-12-2017</span><span class='spantitle'>BLUE SKY</span><span class='spanuser'>JOHN SMITH</span></div>
Also, is there a better way to create this query, avoiding as keyword ?
Yes (but not better in my opinion):
SELECT users.id,
users.name,
posts.id,
posts.date,
posts.title,
posts.user
FROM users
LEFT
JOIN posts
ON users.id = posts.user
WHERE users.role = 'mod'
GROUP
BY posts.title;
But as mentioned in the comments you have to modify your while loop in this case to get access to your values. But I think this is not a better way of writing this query cause it makes it harder to read.
Regarding your JOIN problem. this depends on what your result should be (I guess you only want users with posts ). So you should take a look at INNER JOIN instead of LEFT JOIN. You will get only results which also have posts entrys.
Due to the nature of LEFT JOIN all entrys on the left table (in your case users) will be used, even if they donĀ“t have an entry in the posts table.
INNER JOIN will only return results which match results in both tables.
Related
I'm trying to get the results from 'comments' table with the exception of the ones in the 'readsbaby' table.
The result i'm getting is from comments but no effect of the NOT EXISTS statement, so the result is all the comments.
Both tables have common data that should not be included in the result.
I checked the data and the syntax many times.
Still this query will return all comments without taking in consideration the AND NOT EXISTS close.
public function get_user_comments($post_id)
{
$user_id = $this->session->userdata('id');
$group_id = $this->session->userdata('group_id');
$sql = "SELECT *
FROM comments
WHERE DATE(created_on) > DATE_SUB(CURDATE(), INTERVAL 1 DAY)
AND comments.group_id = " . $group_id . "
AND comments.user_id != " . $user_id . "
AND NOT EXISTS ( SELECT *
FROM readsbaby
WHERE comments.id = readsbaby.notification_id
AND comments.group_id = readsbaby.group_id
AND readsbaby.user_id = " . $this->session->userdata('id') . "
AND comments.nature1 = readsbaby.notification_type
) ";
return $data=$this->db->query($sql)->result_array();
}
Expecting to get the result filtered by the NOT EXISTS close.
I'd change the query this way, to have only the rows without any match in the table readsbaby:
public function get_user_comments($post_id)
{
$user_id = $this->session->userdata('id');
$group_id = $this->session->userdata('group_id');
$sql = "SELECT *
FROM comments
LEFT OUTER JOIN readsbaby ON comments.id = readsbaby.notification_id
AND comments.group_id = readsbaby.group_id
AND readsbaby.user_id = " . $this->session->userdata('id') . "
AND comments.nature1 = readsbaby.notification_type
WHERE DATE(created_on) > DATE_SUB(CURDATE(), INTERVAL 1 DAY)
AND comments.group_id = " . $group_id . "
AND comments.user_id != " . $user_id . "
AND ISNULL(readsbaby.notification_id )";
return $data=$this->db->query($sql)->result_array();
}
This is easier to accomplish using the correct mysql JOIN.
From your post, I have gathered that you want to retrieve all the values from comments where they don't exist in readsbaby. The id column in comments associates with the notification_id in readsbaby for any 'matching' (duplicate) entries.
On this assumption, you can do this at a simplistic level like so
SELECT c.* FROM comments c
LEFT JOIN readsbaby r ON c.id = r.id WHERE r.notification_id IS NULL;
...which should translate to your context as something like:
SELECT c.* FROM comments c
LEFT JOIN readsbaby r ON c.id = r.notification_id
WHERE
r.notification_id IS NULL
AND DATE(c.created_on) > DATE_SUB(CURDATE(), INTERVAL 1 DAY)
AND c.group_id = " . $group_id . "
AND c.user_id != " . $user_id . "
If, I have this wrong and you're looking to only get the data that isn't present in both, you'd need to use something like:
SELECT c.* FROM comments c
LEFT JOIN readsbaby r ON c.id = r.notification_id
WHERE
r.notification_id IS NULL
AND DATE(c.created_on) > DATE_SUB(CURDATE(), INTERVAL 1 DAY)
AND c.group_id = " . $group_id . "
AND c.user_id != " . $user_id . "
UNION
SELECT r.* FROM readsbaby r
LEFT JOIN comments c ON c.id = r.notification_id
WHERE
c.id IS NULL
AND r.group_id = " . $group_id . "
AND r.user_id != " . $user_id . "
This may need tweaking to suit, as there's very little to explain the data and table relationship.
Note: Do not inject SQL as you've done. Consider parameterising your query with PDO or any other prepared statements (e.g. http://php.net/manual/en/pdo.prepare.php)
Using this query I'm selecting rows from multiple tables. Unfortunately, if a row does not exist in one table, then rows in all tables won't return. It's because I'm using AND operator.
So, I want this query to be modified, where will ignore a table if value is not found, but return rest of the tables where the value is found.
Here's the MySQL query:
foreach ($courseArr as $term) {
$term = trim($term);
if (!empty($term)) {
$courseSectionSql[] = "courseDataApp.course = '$term' AND courseDataApp.section = '$sectionArr[$i]'";
$i++;
}
}
$data = $db->rawQuery("SELECT courseDataApp.*, facultyDatabase.*, books.*
FROM courseDataApp
INNER JOIN facultyDatabase ON facultyDatabase.initial = courseDataApp.faculty
INNER JOIN books ON books.course = courseDataApp.course WHERE ".implode(' OR ', $courseSectionSql));
Here's what is returns:
{
"id":11,
// courseDataApp values
"faculty":"AKH1",
"course":"CSE241",
"section":"7",
.
.
.
.
.
.
.
// facultyDatabasevalues
"initial":"AKH1",
"name":"Ms. Kamal Habi",
"dept":"ECE",
.
.
.
.
.
.
// books values
"books": "Digital Logic Design"
},
So the problem is, when a value from facultyDatabase or books tables not found, rest of the data won't return. I just want it to ignore that, show what's found. Like Union.
As some of the comments point out you are using outdated syntax that INNER JOINs the tables which leads to the result you get. You need to LEFT JOIN the tables. Hence you will have a result even though there are no entries in the LEFT JOINed tables. Something like this should work
SELECT courseDataApp.*, facultyDatabase.*, books.*
FROM courseDataApp
LEFT JOIN facultyDatabase ON facultyDatabase.initial = courseDataApp.faculty
LEFT JOIN books ON books.course = courseDataApp.course
WHERE courseDataApp.course = '$term'
AND courseDataApp.section = '$sectionArr[$i]'
Written like this you would have an equivalent to your query in current syntax that will not return anything if there are no entries in the INNER JOINed tables.
SELECT courseDataApp.*, facultyDatabase.*, books.*
FROM courseDataApp
INNER JOIN facultyDatabase ON facultyDatabase.initial = courseDataApp.faculty
INNER JOIN books ON books.course = courseDataApp.course
WHERE courseDataApp.course = '$term'
AND courseDataApp.section = '$sectionArr[$i]'
I have three table:
Article:
|id|title|timestamp|......
group_tags:
|id|content_id|tags_id
tags_name:
|id|name|
I need to list article title with any tag id:
function _tags_search_($id,$type){
$DB_QUERY = mySqli::f("SELECT title FROM " . ARTICLES . " LEFT JOIN " . POSTS_TAGS . " ON " . ARTICLES . ".id = " . POSTS_TAGS . ".content_id WHERE
" .POSTS_TAGS . ".tags_id = ? AND approved = 1 ORDER BY timestamp DESC LIMIT 12", $id);
foreach($DB_QUERY as $row){
$data[] = $row;
}
return $data;
}
this worked for me and show list of article title.
But I need to show tag name for tags id in addition to list title like this:
Search result for : Linux
I have two way :
three left join method ( if true how do?)
fetch another query for show tag name.
I think three join is better and faster. how do show tags name with three join method?!
try this
SELECT title, name from
group_tags g
INNER JOIN article ON a.id = g.content_id
INNER JOIN tags_name t ON t.id = g.tags_id
Let me know if you face any issue
I am doing a sql query but it is not returning any data from the tables. I am not sure why, I have changed from INNER to LEFT but no luck. I have revised the query several times but i cant find an issue. Any thoughts of why I am not getting anything displayed?
TABLE STRUCTURE
TABLE CREATE QUERY
PHP
$query = ("SELECT class.class_name, class.class_caption, class.class_credit_hours, class.class_description, faculty_fname, faculty_lname
FROM class
LEFT JOIN section
ON class.id = section.class_id
LEFT JOIN faculty
ON faculty.id = section.faculty_id OR faculty.id = office_hours.faculty_id
LEFT JOIN faculty_titles
ON faculty_titles.faculty_id = faculty.id
LEFT JOIN faculty_education
ON faculty_education.faculty_id = faculty.id
LEFT JOIN major_class_br
ON major_class_br.class_id = class.id
LEFT JOIN major_minor
ON major_class_br.major_minor_id = major_minor.id
LEFT JOIN sched_sect_br
ON sched_sect_br.section_id = section.id
LEFT JOIN schedule
ON schedule.id = sched_sect_br.schedule_id
LEFT JOIN semester
ON semester.id = schedule.semester_id
LEFT JOIN office_hours
ON schedule.id = office_hours.schedule_id AND faculty.id = office_hours.faculty_id
");
//execute query
$result = mysql_query($query);
if ($result){
$totalhours = 0;
while ($row = mysql_fetch_assoc( $result ))
{
print "<b>" . $row['class_name'] . "</b><br>";
print $row['class_caption'] . "<br>";
print $row ['class_credit_hours'] . "hrs. <br>";
print $row ['faculty_lname'] . "hrs. <br>";
print $row ['faculty_fname'] . "hrs. <br>";
print $row['class_description'] . "<br>";
print "------------------------------<br />";
$totalhours += $row['class_credit_hours'];
}
}
print "<p>Total hours for Major: " . $totalhours . ".</p>";
Desired display:
Computer Programming I
CP1000
4
James Doe
This course offers introduction to programming.
UPDATE: The issue was found here but I am not sure why
ON faculty.id = section.faculty_id OR faculty.id = office_hours.faculty_id
Copy the SQL, go to MySQL admin, execute the SQL there and see if it returns any results.
Remove all the JOIN and execute again, you should see at least something
Add the JOIN one by one
Try to identify which JOIN resulted in no rows being returned
Check the left and right hand side of that join and ensure there actually are valid data to join
Alternatively use OUTER JOIN
I have a small database, holding the details of just under 400 ponies. I wish to query that table and return a table showing the pertinant details of each pony, and it's owner's and breeder's names. The data is held primarily like so:
profiles - a table holding all info assigned to each individual pony, including it's sire's and dam's reg numbers, and it's owner's and breeder's DB assigned id's.
contacts - a table for the people's info. Joined as 'owner' and again as 'breeder' in the query below.
prm_* - multiple parameter tables, holding broad details such as colour, breed, etc.
Where I am running into trouble is when trying my first self join: querying the profiles table three times in order to retrieve the names of the sire and dam for each profile, as well as the pony's own name to begin with. When I run the query, it returns duplicate rows for many (not all) profiles. Using DISTINCT eliminated most of these, but the issue remains with the non-identical results, particularly for those ponies where no sire or dam is on record.
I have googled the problem, and it does appear here and there, but I cant quite grasp what happening in the solutions given. I'm not even certain why the problem occurs at all. Can someone please step me through the issue and the solving of it? I'd be most grateful.
My query as it stands (returns 408 results, from only 387 ponies!):
include 'conn.php';
?>
<table class="admin-display">
<thead><tr><th>No:</th><th>Name:</th><th>Sire:</th><th>Dam:</th><th>Age:</th><th>Colour:</th><th>Gender:</th><th>Owner:</th><th>Breeder:</th></tr></thead>
<?php
$i=1;
$sql = mysql_query("SELECT DISTINCT p.ProfileID, p.ProfileOwnerID, p.ProfileBreederID, p.ProfilePrefix, p.ProfileSireReg, p.ProfileDamReg,
p.ProfileGenderID, p.ProfileAdultColourID, p.ProfileColourModifierID, p.ProfileYearOfBirth,
p.ProfileYearOfDeath, p.ProfileLocalRegNumber, p.ProfileName,
sire.ProfileName AS sireName, sire.ProfilePrefix AS sirePrefix,
dam.ProfileName AS damName, dam.ProfilePrefix AS damPrefix,
owner.ContactFirstName AS owner_fname, owner.ContactLastName AS owner_lname,
breeder.ContactFirstName AS breeder_fname, breeder.ContactLastName AS breeder_lname,
BreedGender, BreedColour, BreedColourModifier
FROM profiles AS p
LEFT JOIN profiles AS sire
ON p.ProfileSireReg = sire.ProfileLocalRegNumber
LEFT JOIN profiles AS dam
ON p.ProfileDamReg = dam.ProfileLocalRegNumber
LEFT JOIN contacts AS owner
ON p.ProfileOwnerID = owner.ContactID
LEFT JOIN contacts AS breeder
ON p.ProfileBreederID = breeder.ContactID
LEFT JOIN prm_breedgender
ON p.ProfileGenderID = prm_breedgender.BreedGenderID
LEFT JOIN prm_breedcolour
ON p.ProfileAdultColourID = prm_breedcolour.BreedColourID
LEFT JOIN prm_breedcolourmodifier
ON p.ProfileColourModifierID = prm_breedcolourmodifier.BreedColourModifierID
WHERE p.ProfileName != 'Unknown'
ORDER BY p.ProfileID ASC");
while($row = mysql_fetch_array($sql)) {
$id = $row['ProfileID'];
$name = $row['ProfilePrefix'] . ' ' . $row['ProfileName'];
if ($row['ProfileYearOfDeath'] > 0000) { $age = ($row['ProfileYearOfDeath'] - $row['ProfileYearOfBirth']); }
elseif ($row['ProfileYearOfDeath'] <= 0000) { $age = (date('Y') - $row['ProfileYearOfBirth']); }
$reg = $row['ProfileLocalRegNumber'];
$sire = $row['sirePrefix'] . ' ' . $row['sireName'];
$dam = $row['damPrefix'] . ' ' . $row['damName'];
$colour = $row['BreedColour'];
$gender = $row['BreedGender'];
$owner = $row['owner_fname'] . ' ' . $row['owner_lname'];
$breeder = $row['breeder_fname'] . ' ' . $row['breeder_lname'];
echo '<tr><td>' . $i++ . '</td><td>' . $name . '</td><td>' . $sire . '</td>';
echo '<td>' . $dam . '</td><td>' . $age . '</td><td>' . $colour . '</td><td>' . $gender. '</td>';
echo '<td>' . $owner . '</td><td>' . $breeder. '</td></tr>';
}
echo '</table>';
mysql_close($con);
Use GROUP BY over DISTINCT:
http://msmvps.com/blogs/robfarley/archive/2007/03/24/group-by-v-distinct-group-by-wins.aspx
The problem is going to be in the data - one of the tables that you're joining against has multiple rows on associated to the join key.
I recommend executing the query in stages. Start with the base query (taking out the field list):
SELECT count(*)
FROM profiles AS p
WHERE p.ProfileName != 'Unknown'
And then add the join tables in one at a time until you see the count increase...
SELECT count(*)
FROM profiles AS p
LEFT JOIN profiles AS sire
ON p.ProfileSireReg = sire.ProfileLocalRegNumber
WHERE p.ProfileName != 'Unknown'
You should then be able to see where the duplicate is. If you want to easily see which record is duplicated, you can run this query:
SELECT p.Profile_id, count(*) cnt
FROM profiles AS p
LEFT JOIN profiles AS sire
ON p.ProfileSireReg = sire.ProfileLocalRegNumber
-- (all other joins)
WHERE p.ProfileName != 'Unknown'
GROUP BY p.Profile_id
HAVING count(*) > 1
Then you can look at the details of the duplicated records.