SELECT All Posts In A Certain Category - php

I indeed read this post (Get all posts from a specific category) but it does not seem to apply to my situation.
My situation is that i have two tables as follows:
1/ table categories
category_id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
lang_id TINYINT UNSIGNED NOT NULL,
name VARCHAR(60) NOT NULL,
PRIMARY KEY (category_id),
UNIQUE (name)
) ENGINE = INNODB';
in which lang_id values are 1 (equivalent to English) and 2 (equivalent to Vietnamese) which is used for filtering by using $_SESSION['lid'].
category_id lang_id name
1 1 Arts and Entertainment
2 1 Computers
3 2 Nghệ thuật và Giải trí
4 2 Máy tính
2/ table posts:
'CREATE TABLE posts (
post_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
category_id TINYINT UNSIGNED NOT NULL,
lang_id TINYINT(3) UNSIGNED NOT NULL,
user_id INT UNSIGNED NOT NULL,
subject VARCHAR(150) NOT NULL,
PRIMARY KEY (post_id),
INDEX (category_id),
INDEX (lang_id),
INDEX (user_id)
) ENGINE = MYISAM';
In which the category_id is the foreign key of the first table.
question_id category_id lang_id user_id subject
1 1 1 1 arts
2 4 2 1 máy tính
3 5 1 1 business and money
I would like to select the posts in a certain category when we mouse-click on it. So, I run this query:
$q = "SELECT subject
FROM categories AS ca
INNER JOIN questions AS q
USING (category_id)
WHERE q.lang_id = {$_SESSION['lid']}
GROUP BY ca.category_id
$r = mysqli_query($database_connect, $q)
if(mysqli_num_rows($r) > 0) {
while ($subject = mysqli_fetch_array($r, MYSQLI_ASSOC)) {
echo '<ul>
<li>'. $subject['subject']. '</li>
</ul>';
}
But the result does not return as desired. For example, When I click on category 1 (Arts and Entertainment), the result returns two subjects (arts posted in category_id 1, business and money posted in category_id 5 ).
Can you help me to re-build the query, please? I really really got stuck here.

Add the category id in WHERE clause to select post of a given category
SELECT subject
FROM categories AS ca
INNER JOIN questions AS q
USING (category_id)
WHERE q.lang_id = {$_SESSION['lid']}
AND ca.category_id = 1

SELECT categories.*, posts.* from posts left join posts on categories.category_id=posts.category_id where posts.lang_id = {$_SESSION['lid']} and posts.category_id={your given category}

Related

Mysql Select specific data from 2 tables base on the third table

I have three tables
tbl_project
db_projectid db_projectname
1 test
2 xxx
tbl_activities
db_id db_projectid db_category
1 1 Civil Work
2 1 Mechanical
3 1 Electrical
tbl_dailypercentage
db_dpid db_aid db_projectid db_status
1 1 1 red
2 1 1
3 2 1
db_projectid is a primary key in tbl_project
db_id is a primary key and db_projectid is a foreign key in tbl_activities
db_dpid is a primary key and db_aid is a foreign key in tbl_dailypercentage
I tried this query
select
activities.db_id,
activities.db_category as cat,
dailypercentage.db_status,
dailypercentage.db_aid,
dailypercentage.db_projectid
from tbl_activities as activities,tbl_dailypercentage as dailypercentage
where
dailypercentage.db_projectid='$projectId'
and
activities.db_id=dailypercentage.db_aid
and
dailypercentage.db_status='red'
But i Have ab error
Undefined variable: cat
while($row=mysqli_fetch_array($statusQuery)){
$status=$row['db_status'];
$cat=$row['cat'];
}
<td> <?php if($cat=="Civil Work" && $status="red"){
echo"<p style='color:$status'>".($sumcivil/$civilCount)."</p>";}
else{echo ($sumcivil/$civilCount);}?>
</td>
I try also many thing the left join and the right join
to have the result i want
The Result i want is
For Project who have an id=1
category status
civil work red
mechanical work
electrical work
For Project who have an id=2
category status
civil work
mechanical work
electrical work
You showed this code:
while($row=mysqli_fetch_array($statusQuery)){
$status=$row['db_status'];
$cat=$row['cat'];
}
If your query returns no rows, $status and $cat will never get defined. I guess this is what went wrong. What happens if you run that query with a MySQL client like phpMyadmin?
Similarly, if your query returns more than one row, $status and $cat will capture the values of only the last row.
It's important to work out what you want to happen with no rows and multiple rows.
Based only on the tables in your question I have put together the following schema (I've not added constraints to the foreign keys as this is just for testing).
create table tbl_project (
`db_projectid` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`db_projectname` VARCHAR(255) NOT NULL DEFAULT 'Undefined',
PRIMARY KEY (`db_projectid`)
);
create table tbl_activities (
`db_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`db_projectid` INT(1) NOT NULL,
`db_category` VARCHAR(255) NOT NULL DEFAULT 'Undefined',
PRIMARY KEY (`db_id`)
);
create table tbl_dailypercentage (
`db_dpid` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`db_aid` INT(1) NOT NULL,
`db_projectid` INT(1) NOT NULL,
`db_status` VARCHAR(255) NULL,
PRIMARY KEY (`db_dpid`)
);
insert into tbl_project (db_projectname) values ('Test'), ('xxx');
insert into tbl_activities (db_projectid, db_category) values ('1', 'Civil Work'), ('1', 'Mechanical'), ('1', 'Electrical');
insert into tbl_dailypercentage (db_aid, db_projectid, db_status) values
('1', '1', 'red'),
('1', '1', null),
('2', '1', null);
select a.db_category as cat, dp.db_status from tbl_project p
left join tbl_activities a on p.db_projectid = a.db_projectid
left join tbl_dailypercentage dp on dp.db_aid = a.db_id
where p.db_projectid = 1
group by a.db_id;
I've had to add the group by into the final query as you have multiple rows in tbl_dailypercentage with the same db_aid and db_projectid values.
After that, you want to tweak your php code, putting the td stuff inside the while loop:
<?php while($row=mysqli_fetch_array($statusQuery)):?>
$status=$row['db_status'];
$cat=$row['cat'];
<td> <?php if($cat=="Civil Work" && $status="red"){
echo"<p style='color:$status'>".($sumcivil/$civilCount)."</p>";}
else{echo ($sumcivil/$civilCount);}?>
</td>
<?php endwhile; ?>

How to check if values from the table 1 are used in table 2?

I have two tables employees and departments.
Departments:
create table dept (
id INT NOT NULL AUTO_INCREMENT,
dept_name VARCHAR(50) NOT NULL,
PRIMARY KEY (id)
);
Employees:
create table department_master (
id INT NOT NULL AUTO_INCREMENT,
dept_id INT NOT NULL,
emp_name VARCHAR(100) NOT NULL,
PRIMARY KEY (id)
);
I want to prevent departments being deleted from the UI if they are assigned to one of the employees in employee table. Left join is giving me duplicate values.
How do I see if the departments are being used in the employees table.
If you want to prevent a department from being deleted, you can simply add a foreign constraint to the table department_master for dept_id column.
create table department_master (
id INT NOT NULL AUTO_INCREMENT,
dept_id INT NOT NULL,
emp_name VARCHAR(100) NOT NULL,
PRIMARY KEY (id),
constraint con_dm foreign key dept_id references dept( id )
);
It's default behavior is ON DELETE RESTRICT which means that if there is atleast one row present in the department_master for a given dept_id, it can't be deleted from dept table.
If you want to fetch, the department that don't have any employee record, you can use NOT EXISTS:
select *
from dept d
where not exists (
select 1
from department_master m
where d.id = m.dept_id
);
I believe you want a count of the number of employees grouped by the department, like so:
SELECT count(*) as employees, d.dept_name FROM dept AS d LEFT JOIN department_master AS e ON e.dept_id = d.id group by e.dept_id

Selecting a users forum activity while limiting results based on permission

I have a forum split into multiple tables: categories, topics and threads.
CREATE TABLE forum_categories (
cat_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
role_id INTEGER UNSIGNED NOT NULL DEFAULT 0,
cat_name VARCHAR(50) NOT NULL,
PRIMARY KEY(cat_id),
FOREIGN KEY (role_id)
REFERENCES roles(role_id)
);
CREATE TABLE forum_topics (
topic_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
cat_id INTEGER UNSIGNED NOT NULL,
topic_name VARCHAR(50) NOT NULL,
topic_desc VARCHAR(100) NOT NULL,
PRIMARY KEY(topic_id),
FOREIGN KEY (cat_id)
REFERENCES forum_categories(cat_id)
);
CREATE TABLE forum_threads (
thread_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
parent_id INTEGER UNSIGNED NOT NULL DEFAULT 0,
topic_id INTEGER UNSIGNED NOT NULL,
user_id INTEGER UNSIGNED NOT NULL,
title VARCHAR(100) NOT NULL,
body TEXT NOT NULL,
create_date DATETIME NOT NULL,
PRIMARY KEY (thread_id),
FOREIGN KEY (parent_id)
REFERENCES forum_threads(thread_id),
FOREIGN KEY (topic_id)
REFERENCES forum_topics(topic_id),
FOREIGN KEY (user_id)
REFERENCES users(user_id)
);
The category table has a field named role_id, which if set to any value other than 0 means that only users with that role are allowed to view or interact with the topics in that category.
The problem I'm facing is when attempting to pull a specific users recent activity for everyone to see. I want to COUNT(*) on the threads table containing the requested user_id, but I need to exclude threads having a topic_id associated with a restricted category unless the user requesting the information has permission.
If viewing a specific thread, I would simply extract the topic_id and check like this:
// validate topic id and check for permission
$forum = new Forum();
$valid_topics = $forum->getTopics();
if (!array_key_exists($topic_id, $valid_topics)) {
// invalid topic id
}
$valid_categories = $forum->getCategories();
$role_id = $valid_categories[$valid_topics[$topic_id]['cat_id']]['role_id'];
if ($role_id == 0 || array_key_exists($role_id, $session_user_roles)) {
// user has permission
}
Now I'm trying to convert my PHP logic into SQL. Here is a pseudo-code example of what I'm after:
SELECT COUNT(*),
(SELECT role_id,
(SELECT cat_id
FROM forum_topics AS t2
WHERE topic_id = t1.topic_id) AS cat_id
FROM forum_categories
WHERE cat_id = t2.cat_id) AS role_id
FROM forum_threads AS t1
WHERE user_id = $user_id AND (role_id != 0 OR FIND_IN_SET(role_id, $session_user_roles) > 0)
Any help, please?
Try this way
SELECT count(*)
FROM forum_threads thr
JOIN forum_topics top ON thr.topic_id = top.topis_id
JOIN forum_categories fc ON top.cat_id = fc.cat_id
WHERE thr.user_id = $user_id
AND fc.role_id IN ( 0, 24, 55, 888, .... list of user roles ... )
In the list of user roles (last condition) always put 0 as a first number, then the rest of his roles.

How to select and sort data with a parent / child relationship

I'm storing threads for a forum with a parent / child relationship as follows:
CREATE TABLE forum_threads (
thread_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
parent_id INTEGER UNSIGNED NOT NULL DEFAULT 0,
topic_id INTEGER UNSIGNED NOT NULL,
user_id INTEGER UNSIGNED NOT NULL,
title VARCHAR(100) NOT NULL,
body TEXT NOT NULL,
create_date DATETIME NOT NULL,
PRIMARY KEY (thread_id),
FOREIGN KEY (parent_id)
REFERENCES forum_threads(thread_id),
FOREIGN KEY (topic_id)
REFERENCES forum_topics(topic_id),
FOREIGN KEY (user_id)
REFERENCES users(user_id)
);
New threads have parent_id = 0, whereas replies have parent_id = the thread_id being replied to.
I want to select the most recently updated (replied to) threads and display the results in a table as follows:
How can I do this?
SELECT * FROM forum_threads
WHERE topic_id = whatever AND parent_id = 0
WHAT NEXT???
I'm not sure if this can be done with pure SQL, or if I should manipulate the results with PHP, or if I should try another approach all together?
Use the below query:
SELECT * FROM forum_threads
WHERE topic_id = whatever AND parent_id = 0
ORDER BY updated_date DESC limit 1;
this will give you the most update record.
You can simply do this in SQl
SELECT ft.* FROM forum_threads AS ft
JOIN forum_threads AS ft1 ON ft.id = ft1.thread_id
WHERE topic_id = whatever AND parent_id = 0
ORDER BY ft.create_date DESC
LIMIT 1

How to display a students rank out of hundred students using PHP & MySQL?

I'm trying to get the rank of a certain student out of a class of a hundred, I want to be able to display the students rank.
I'm trying to get the rank of a student by grades and grade points. For example if student 1 has 2 A+ grades with a total of 10 points and student 2 has 3 B- grades with a total of 10 points student 1 will rank higher. I was wondering how would I be able to do this using PHP & MySQL?
Here is the PHP & MySQL code I have so far.
$gp = array();
$dbc = mysqli_query($mysqli,"SELECT grades.*, homework_grades.*, users_homework.*
FROM grades
LEFT JOIN homework_grades ON grades.id = homework_grades.grade_id
LEFT JOIN users_homework ON homework_grades.users_homework_id = users_homework.id
WHERE users_homework.user_id = '$user_id'
AND users_homework.grade_average = 'A+'");
if (!$dbc) {
print mysqli_error($mysqli);
} else {
while($row = mysqli_fetch_array($dbc)){
$gp[] = $row['grade_points'];
}
}
echo array_sum($gp);
Here is my MySQL tables.
CREATE TABLE homework_grades (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
grade_id INT UNSIGNED NOT NULL,
users_homework_id INT UNSIGNED NOT NULL,
user_id INT UNSIGNED NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE grades (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
letter_grade VARCHAR NOT NULL,
grade_points FLOAT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (id)
);
CREATE TABLE users_homework (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
user_id INT UNSIGNED NOT NULL,
homework_content LONGTEXT NOT NULL,
grade_average VARCHAR DEFAULT NULL,
PRIMARY KEY (id)
);
UPDATED
You need an aggregate. Do a SUM() and COUNT(). COUNT will tell you number of assignments, sum will tell you the total grade points. GROUP BY user_id to get this for each student.
$gp = array();
$dbc = mysqli_query($mysqli,"SELECT SUM(grade_points) as grade_points, user_id, count(*) as num_assignments
FROM grades
LEFT JOIN homework_grades ON grades.id = homework_grades.grade_id
LEFT JOIN users_homework ON homework_grades.users_homework_id = users_homework.id
GROUP BY user_id
ORDER BY grade_points DESC , num_assignments ASC'");
if (!$dbc) {
print mysqli_error($mysqli);
} else {
$i=1;
while($row = mysqli_fetch_array($dbc)){
$user[$row['user_id']] = $i++;
$rank[] = $row['user_id'];
$gp[] = $row['grade_points'];
}
}
// the rank of user 10 is
echo "the rank of user_id 10 is {$user[10]}";
echo "the rank of all users are: " ;
print_r($rank);
This will add up the grade points, and count the number of assignments. Sorting will make sure that a student with 10 points from 3 assignments, will have a higher rank than a student with 10 points from 4 assignments.
See the COUNT SUM and GROUP BY aggregates.

Categories