Adding up row number and displaying total using COUNT (PHP MySQL) - php

I'm attempting to run a query that adds up the total number of subjects in a class. A class has many subjects. There is a 'teachersclasses' table between teachers (the user table) and classes. The principles sounds pretty simple but I'm having some trouble in getting my page to display the number of subjects for each class (directly associated with the teacher)
This is what I have so far, trying to make use of the COUNT with a nested SELECT:
SELECT (SELECT count(*) FROM subjects WHERE subjects.classid = class.classid) AS total_subjects, class.classname, class.classid
FROM class
Then I am calling up 'num_subjects' to present the total within a while loop:
<?php echo $row['total_subjects']?>
From the above, I am receiving the total subjects for a class, but within the same table row (for one class) and my other while loop doesnt run anymore, which returns all of the classes associated with a teacher :( ... Bit of a mess now!
I know to return the classes for a particular teacher, I can do an additional WHERE clause on the session of 'teacherid' but I think my query is getting too complicated for me that errors are popping up everywhere. Anyone have a quick fix for this! Thanks very much

Your query is probably not optimal. It might be a good idea to rewrite it as a join:
SELECT
total_subjects,
class.classname,
class.classid
FROM class
JOIN (
SELECT classid, count(*) AS total_subjects
FROM subjects
GROUP BY classid
) AS T1
ON T1.classid = class.classid
As for your problem, you don't need two loops. This is a single result set with three columns, as my rewrite clearly shows. You only need one loop to read all the results.

SELECT count(*) FROM subjects GROUP BY subjects.classid

You don't need the "subselect", you can just do a JOIN and count()
SELECT
class.*,
count(subjects.*) AS total_subjects
FROM
class
LEFT JOIN subjects ON class.classid = subjects.classid
WHERE
class.teacherid = ?
GROUP BY
class.classid

Related

Displaying INNER JOIN results as HTML table on webpage?

I have the following query:
$sql = "SELECT first, COUNT(FIRST) FROM techs INNER JOIN ros ON techs.id = ros.writtenby GROUP BY ID";
That gives the desired output of:
first
COUNT(FIRST)
Eric
88
John
11
I have no earthly idea how to display this EXACT table onto a PHP/HTML page. I've created tables based off of queries but it's basically just displaying database table data. I have a feeling the INNER JOIN is the root of my issue since it's not an actual table in the database, rather just results from my query. If this isn't apparent enough already I'm very much a beginner at coding in general so be kind. Lol.
From comments:
I don't understand how to call and then display the "count(first)" column of my query results, since "`count(first)" isn't an actual column in either of the tables I am generating the result from.
If only that's your problem, use alias, like:
SELECT first, COUNT(FIRST) AS my_count FROM techs INNER JOIN ros ON techs.id = ros.writtenby GROUP BY ID
Note that above is the query you posted, just with " AS my_count" added.

Add Column to one Table that is COUNT of another

I have a list of subscribers in table Subscribers. Every time they receive a copy of their subscription, a new record is created in Subscriptions_Fulfilments for each Subscribers.ID.
I can create a table showing each Subscriber ID and the number of copies they received with the following query:
SELECT Sub_ID, COUNT(Sub_ID) fcount FROM `Subscriptions_Fulfilments`
GROUP BY Sub_ID
But I need to create a compound query that returns Subscribers along with a column showing the COUNT(Sub_ID) of Subscriptions_Fulfilments.
So I have two questions:
A) How would you make a query to create a table that shows each Subscriber and the number of times they've received their subscription, based on the COUNT of that Subscriber's ID in Subscriptions_Fulfilments?
B) I'm operating under the assumption that a single MySql query accomplishing this would be more efficient than, say, running two queries, the one above and a SELECT * FROM Subscriptions, and combining the resulting arrays in PHP. I have a feeling I know the answer but I'd like to positively learn something new today.
Unfortunately, after too many tries, I'm clearly not good enough at queries for this and I have very little past the above query to show for it. I apologize if this ends up being a dup, I searched long and hard before asking, but it's quite difficult to search precisely for Query help...
Here is a simple example showing the Subscribers ID and the no of subscription they have received. Hope it helps.
Step 1: select the ids from the Subscriber table
Step 2: select the no of counts of subscriptions received by each subscriber.
Step 3: Join both the table ON the basis of ID.
SELECT SubId, noSub FROM
Subscribers sb JOIN (SELECT SubId AS sid, COUNT(*)AS noSub FROM Subscriptions_Fulfilments GROUP BY SubId)AS ss ON sb.SubId = ss.sid
One of the big advantages of a relational database is the ability to do joins and combinations of the data in your tables in a way that allows for this functionality without having to actually store it in a separate table.
You can accomplish this with a subquery like this:
SELECT Subscribers.name, fulfilments.count FROM Subscribers
INNER JOIN (
SELECT id, count(*) as count FROM Subscriptions_Fulfilments
GROUP BY Sub_Id
)fulfilments ON subscribers.id = fulfilments.id
This might not be 100% what you're looking for and I might have messed up your names, but hopefully this will start to get you in the neighborhood of being correct?
Simply try execute this query:
Select distinct Sub_ID, count from (SELECT Sub_ID, COUNT(Sub_ID) fcount FROM Subscriptions_Fulfilments
GROUP BY Sub_ID);

How to get only 1 row of each similar content?

I Have a private message system on my site and i'm trying to pull all subject's on the messages.
I need to show any subject once.
so if I have this subjects:
hey
hello
hey
good morning
good morning
I need to print this:
hey
hello
good morning
I can just cross it out with if, but I guess there is a better way with sql.
Thank you.
Option 1 : DISTINCT
SELECT DISTINCT subject
FROM my_table
Option 2 : GROUP BY
SELECT subjects
FROM my_table
GROUP BY subjects
Difference between GROUP BY and DISTINCT
Distinct is used to filter unique records out of the records that satisfy the query criteria.
Group by clause is used to group the data upon which the aggregate functions are fired and the output is returned based on the columns in the group by clause. It has its own limitations such as all the columns that are in the select query apart from the aggregate functions have to be the part of the Group by clause.
See this and this for the reference .
Try something like:
SELECT DISTINCT subject FROM emails;
If you use SQL.
select distinct subjects
from YOUR_TABLE.
or
Select subjects
from YOU_TABLE
group by subjects

Include NULL as 0 in COUNT SQL Query

I know for a fact this has been asked a few times before, but none of the answered questions relating to this seem to work or are far too confusing for me..
I should probably explain.
I'm trying to create an AJAX script to run to order some results by the number of 'Likes' it has.
My current code is this:
SELECT COUNT(*) AS total, likes.palette_id, palette.*
FROM likes LEFT JOIN palette ON likes.palette_id = palette.palette_id
GROUP BY likes.palette_id
ORDER BY total DESC
Which works fine, however it doesn't list the results with 0 likes for obvious reasons, they don't exist in the table.
I've attached images of the current tables:
Likes table:
http://imgur.com/EGeR3On
Palette table:
http://imgur.com/fKZmSve
There are no results in the likes table until the user clicks 'Like'. It is then that the database gets updated and the palette_id and user_id are inserted.
I'm trying to count how many times *palette_id* occurs in the likes table but also display 0 for all palettes that don't appear in the likes table.
Is this possible? If so, can someone help me out at all?
Thank you
It might not be the exact MySQL syntax (I'm used to SQL Server), but should be pretty straight forward to translate if needed.
SELECT p.*, IFNULL(l.total, 0) AS total
FROM palette p
LEFT JOIN (
SELECT palette_id, COUNT(*) AS total
FROM likes
GROUP BY palette_id
) l
ON l.palette_id = p.palette_id
ORDER BY total
Try this:
SELECT COUNT(likes.palette_id) AS total, palette.palette_id, palette.*
FROM palette LEFT JOIN likes ON likes.palette_id = palette.palette_id
GROUP BY palette.palette_id
ORDER BY total DESC
EDIT:
In regards to the discussion about listing columns that are not in the GROUP BY, there's a good explanation in this MySql documentation page.
MySQL extends the use of GROUP BY so that the select list can refer
to nonaggregated columns not named in the GROUP BY clause. This means
that the preceding query is legal in MySQL. You can use this feature
to get better performance by avoiding unnecessary column sorting and
grouping. However, this is useful primarily when all values in each
nonaggregated column not named in the GROUP BY are the same for each
group. The server is free to choose any value from each group, so
unless they are the same, the values chosen are indeterminate.
In this example, the palette information not added to the GROUP BY will be the same for each group because we are grouping by palette_id so there won't be any issue using palette.*
Your join is written backwards. It should be palette LEFT JOIN likes, because you want all rows in palette and rows in likes, if they exist. The "all rows in palette" will get you a palette_id for the entries there without any matching "likes."

Can I have a loop within an SQL SELECT statement?

I'm trying to create an SQL SELECT statement on my PHP file which can select all rows that have an unknown number of different values in one of the column. To explain better I'll say the exact situation. I have three tables in my database; tests, categories, sections. Each test belongs to a category, there are around 50 categories, each category belongs to a section, there are 10 sections. However, in my tests table, it only has a column for the category it belongs to. I now want to be able to display all tests within a section.
So to make things clearer:
SELECT * FROM tests WHERE category = '$categoryId' ORDER BY id ASC
This lets me select all tests in a particular category, but I want to make a loop of some sort, where, depending on which section is selected, the category id's are put in this statement separated by OR. Thank you.
SELECT t.*
FROM tests t
JOIN category c on t.category = c.id AND c.section = ' . $section . '
ORDER BY t.id ASC
This is to show you the way, in your production environment you should sanitize the $section parameter.
The idea is to join tables together to take advantage of the powerful relational database features over programmatic loops.
Internally, the RDBMS is doing loops for you, calculating intermediate resulset of each JOINed table.
If you want to select all tests in one section then you should not use the or statement on category id but should use join on these tables:
something like:
SELECT tests.* FROM (tests JOIN categories ON tests.category = categories.id) WHERE categories.section = $section
where $section is the id of section you want to select tests.
You can also specify columns to use instead of * to select only those you are interested in.
$section should be escaped to be sure that it cannot be injected.
I do not know your table schema but when you have relations like these you should have foreign keys in these tables and the query should be fast and you need only one! This is how to perform queries on data model as relations are stored right in the DB.
use special character for Example pipe symbole |
and do this :
$str="|".$cat1."|".$cat2."|".$cat3+"|";
and use Like condition :
SELECT * FROM tests WHERE $str like '%|'+cast(category as varchar) +'|%' oRDER BY id ASC

Categories