MYSQL Select user name and SUM the reviews for them - mysql

I need to create a sql that contains a list of users, and for each user the number they have
reviewed.
I tried this, but it didnt give the desired output because i didnt know how to work the SUM into it.
SELECT review.revID, reviewer.name FROM review , reviewer WHERE review.revID = reviewer.revID
Any assistance would be apprectiated
here are my tables
CREATE TABLE reviewer (
revID INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(40),
email VARCHAR(40),
password VARCHAR(125)
);
CREATE TABLE movie (
movID INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(30),
release_date date
);
CREATE TABLE review (
revID INT,
movID INT,
rating INT CHECK (rating > 0 AND rating < 10) ,
review_date datetime(6),
comment VARCHAR (300),
helpful INT,
PRIMARY KEY (revID,movID),
FOREIGN KEY (revID)
REFERENCES reviewer(revID),
FOREIGN KEY (movID)
REFERENCES movie(movID)
);

Try this query:
SELECT
count(movId) AS Total_Movie_Count,
r.name AS Reviewer_Name,
r.revId as Reviewer_Id
FROM review
INNER JOIN reviewer r on r.revId = review.revId
GROUP BY review.revId
You have to use GROUP BY for aggregated column movId. And to get the reviewer name, you have to INNER JOIN with revId.

Select count(*) as no, revId from review
Group by revId
You can use the above query

Try to use explicit join syntax (e.g. inner join, left join, cross join). Because the relationships among different tables are better explained using explicit join syntax.
SELECT
review.revID,
reviewer.name,
SUM(rating) As totalReview
FROM review
INNER JOIN reviewer ON review.revID = reviewer.revID
GROUP BY reviewer.revID;
Note: You need to use GROUP BY revID in order to get output for each reviewer.
And using aggregate function SUM along with group by will provide total rating / review for each reviewer.
Btw, MYSQL doesn't support CHECK constraint.

Related

How to create a query with JOIN and WHERE or how to make them friends?

I need to make a query, where there are columns of client's names and their orders per month.
Some clients don't have orders at some months and there fields must have 0.
The problem is, when i use WHERE and OUTER JOIN (no matter which one) at one query*, nessesary zero`s cutteed by WHERE. So how can i solve that?
Descripton of tables are pinned.
SELECT name
, ordering.id_client
, COUNT(order_date)
FROM ordering
RIGHT
OUTER
JOIN client
ON client.id_client = ordering.id_client
WHERE month(order_date) = 1
GROUP
BY name;
**Descripton**: (https://i.imgur.com/TrUGOLW.png)
**Example of my query** (there are 6 notes about clients at my db, showed only 4 of 6):
(https://i.imgur.com/ABP6pP0.png)
**MRE stuff**
Client: create table client(id_client int primary key auto_increment, name var char(50), passport_code int, addr varchar(70));
insert into client values(null, 'Penny Anderson', 6485, 'New Orlean');
Ordering: create table ordering(id_order int primary key auto_increment, id_client int, order_date date, foreign key(id_client) references client(id_client));
insert into ordering values(null, 1, date('2020-05-01'));
Try a simple left join starting from client's table
SELECT client.name
, client.id_client
, COUNT(order_date)
FROM client
LEFT JOIN ordering ON client.id_client = ordering.id_client
AND month(ordering.order_date) = 1
GROUP BY client.id_client;
If the condition for join is related to the left joined table then add this condition in the related ON clause and not in where otherwise this work as an inner join

mysql get max status ordered by date

I'm facing MySQL query problem with ordering grouped rows.
Tables:
statuses (
  id int primary key auto_increment,
name varchar(30)
);
orders (
id int primary key auto_increment,
order_code varchar(10),
order_date timestamp default current_timestamp,
user_id int -- fk to users
);
orders_statuses (
id int primary key auto_increment,
status_changed timestamp default current_timestamp,
order_id int, -- fk to orders(id)
status_id int -- fk to orders(id)
);
Now, I need to join them in ONE query (this is important due to database object limitation with my PHP software - no sub-queries allowed, not even union) and get all possible orders, but only the latest status change as current status.
Statuses from status table may be inserted randomly - there is no way to use max function on status_id field where order_id (currently id 1 is new, 2 is canceled, 4 is paid etc.).
Grouping by order_id (id in orders or order_code) always returns first available status inserted into orders_statuses, even if ordered by date.
I've also tried using having status_changed=max(status_changed), but it won't work.
So my question is:
How should I group them by order_id to get last, not first status name available for each row?
// edit
Here is the code I'm trying to move from my Workbench to PHP DB Object:
select
(select l.name from statuses l where l.id = (select t.status_id from orders_statuses t where t.order_id = oh.id order by t.status_changed desc limit 1)) as status,
oh.order_code,
oh.id,
oh.order_total,
su.name as order_user,
oh.order_date as ordered,
max(os.status_changed) as updated,
oh.id as uid
from orders oh
left join orders_statuses os on (oh.id = os.order_id)
left join users su on (oh.shop_user_id = su.id)
group by
oh.id
order by
oh.order_date desc,
os.created desc
So basically I need simpler query to understand it and put it into $this->db->use('table', on condition)->...->select(array(fields))
// edit
After hours of thinking I can tell I'm lacking know-how. This problem can be solved by using
SELECT
status_id,
created,
order_id
FROM
orders_statuses
GROUP BY
order_id,
status_id
ORDER BY
created DESC;
and transforming it to return just one status_id for each order_id with max created within single order_id group - this is where I need your help.

MySQL query using different tables and filters

I have one table called 'vacancies' which has a 'vacancy_id' PK. It looks like this:
create table vacancies
(
vacancy_id int not null auto_increment,
org_id int not null,
name varchar(255) not null comment 'title',
vacancy_visibility_start_date datetime comment 'vacancy visibility date, when it needs to be active on the website',
vacancy_visibility_end_date datetime,
primary key (vacancy_id)
);
Following this I have a couple of other tables which are linked to this one.
create table vacancy_calendar
(
vacancy_calendar_id int not null auto_increment,
vacancy_id int,
date_from datetime not null,
date_to datetime not null,
primary key (vacancy_calendar_id)
);
create table vacancy_interests
(
vacancy_id int,
interest_id int
);
create table vacancy_skills
(
vacancy_id int,
skill_id int
);
All of these tables can contain multiple rows for the same vacancy_id.
My page has different filters which I want to process via AJAX.
I want to have one line per vacancy containing all data I need + it has to match my filtering criteria. However I am not sure how my query has to look like in order to retrieve the result I am looking for.
It is possible to filter on 'interest_id' , 'skill_id', 'date_from' and 'date_to'.
I started with the following query but I am stuck very fast:
SELECT v.*, vi.interest_id
FROM `vacancies` as v
INNER JOIN `vacancy_interests` as vi on v.vacancy_id = vi.vacancy_id
GROUP BY v.vacancy_id
This query will only return me 1 interest_id for a vacancy, even if the vacancy has 3 interest_id rows in the vacancy_interest table. If I remove the GROUP BY statement I will get 3 rows for the same vacancy which is not what I want either.
Ideally I would want the interest_id's to be each in a separate column or in the same field separated by comma's. Or if there are any other possibilities/suggestions feel free to share!
You can use group_concat for get interest_id separated by comma
SELECT v.*, group_concat(vi.interest_id)
FROM `vacancies` as v
INNER JOIN `vacancy_interests` as vi on v.vacancy_id = vi.vacancy_id
GROUP BY v.vacancy_id
Referring to you comment about add where eg:
You can add where condition
SELECT v.*, group_concat(vi.interest_id)
FROM `vacancies` as v
INNER JOIN `vacancy_interests` as vi on v.vacancy_id = vi.vacancy_id
INNER JOIN `vacancy_skills` as vs ON vs.vacancy_id = v.vacancy_id
WHERE vs.skill_id IN (4) AND vi.interest_id IN (1,3)
GROUP BY v.vacancy_id
In this case the gorup_concat is applied on the resulting rows .. because group by perform the related action on the selected resulting rows .

How can I write a query that shows the Institutions that have more than one one contact at them?

CREATE TABLE Institutions
(
Institution_ID INTEGER PRIMARY KEY,
Institution_Name VARCHAR(200))
CREATE TABLE Contact_Persons
(
Contact_No INTEGER PRIMARY KEY,
First_Name VARCHAR(60) NOT NULL,
Last_Name VARCHAR(60) NOT NULL,
Institution_ID INTEGER,
FOREIGN KEY (Institution_ID) REFERENCES Institutions(Institution_ID))
How can I write a mysql query that shows the Institutions that have more than one one Contact Person at them? The Query should show Institution_ID and Institution_Name from Table Institutions. The following Query works but It only shows Institution_ID. I want to see Institution_Name too. I think there must be a join between these two tables. Please help.
SELECT Institution_ID
FROM Contact_Persons
GROUP BY Institution_ID
HAVING COUNT(*)>1;
You were right, you just need to join your two tables, and make sure you also group by everything you want to select (unless it is an aggregate), so in this case add Institution_Name to the group by clause:
SELECT i.Institution_ID, i.Institution_Name
FROM Contact_Persons AS cp
INNER JOIN Institutions AS i
ON i.Institution_ID = cp.Institution_ID
GROUP BY i.Institution_ID, i.Institution_Name
HAVING COUNT(*) > 1;
Try this
SELECT I.Institution_ID,I.Institution_name
FROM Contact_Persons as C inner join Institutions as I on
C.Institution_ID=I.Institution_ID
GROUP BY I.Institution_ID,I.Institution_name
HAVING COUNT(*)>1;

Using Count and Max in SQL Query

I have two tables that I am trying to query from, Enrollment and Course. In the course Table, there is just one entry for each course, but in the Enrollment table, there is an entry for each student that is enrolled in any course, so there may be 30 entries for one course. My task is to find The course that has the most enrollments, and print out that course name, as well as the number of enrollments for that course. Here is my query so far
select c.CourseCode ,(SELECT count( * ) FROM Enrollment WHERE CourseCode = c.CourseCode) as test from Course c ;
this gives me the results:
CS227 - 29
CS228 - 34
CS309 - 31
CS311 - 25
, ect, which is good, but NOW, how do I print out only the class that has the most enrollments(in this case, CS228). I have tried using the max(), but I can't get anything to work.
Here is the table structure
create table Course(
CourseCode char(50),
CourseName char(50),
PreReq char (6));
create table Enrollment (
CourseCode char(6) NOT NULL,
SectionNo int NOT NULL,
StudentID char(9) NOT NULL references Student,
Grade char(4) NOT NULL,
primary key (CourseCode,StudentID),
foreign key (CourseCode, SectionNo) references Offering);
Just take the top 1 after ordering by the count.
That is:
Select Top 1 A.CourseCode, Count(*) From Course A inner join Enrollment B on (A.CourseCode=B.CourseCode)
Group By A.CourseCode
Order By Count(*) DESC
Also - use an inner join as I've shown here rather than a subquery. I do tend to like SubQueries and this one will work but it is just not appropriate in this kind of query!
Based on your comment, I think the blow query is what you want, although it is untested and I am not entirely sure on the HAVING clause being valid. From the documentation on MySQL's page, it seems it should work.
SELECT A.CourseCode, COUNT(*) AS count FROM Course A
JOIN Enrollment B ON A.CourseCode = B.CourseCode
GROUP BY A.CourseCode
HAVING count = MAX(count)
As for performance, I cannot tell if it's a good idea to run a MAX on an aggregate function (probably not).
Otherwise, just use the other query to return the top X and simply run through comparing to the previous number.
SELECT
c.CourseCode,
c.CourseName,
COUNT(*) AS cnt
FROM
Course AS c
INNER JOIN
Enrollment AS e
ON c.CourseCode = e.CourseCode
GROUP BY
c.CourseCode
HAVING
COUNT(*) =
( SELECT
COUNT(*) AS cnt
FROM
Enrollment AS e
GROUP BY
e.CourseCode
ORDER BY
cnt DESC
LIMIT 1
)