SQL count problems - mysql

I have a query problem with count. I want to have a column with the number of persons registered to the course.
So far, this is my query:
select
courses.id,
name,
location,
capacity,
(
SELECT count(courses_requests.IDcourse)
FROM courses_requests, courses
WHERE courses_requests.IDcourse = courses.id AND status != "rejected"
) as Registered,
begin_date,
end_date,
price,
active
from courses
But this is giving me problems, it displays the same value for all rows, even if the course doesn't have persons registered in the course
E.G
Capacity Registered
2 1
30 1

It may be simplier to aggregate the outer select, to eliminate the subquery, so something like:
SELECT c.id,
c.name,
c.location,
c.capacity,
COUNT(cr.IDcourse) AS RequestCount
c.begin_date,
c.end_date,
c.price,
c.active
FROM courses c
INNER JOIN courses_requests cr
ON cr.IDcourse = c.id
AND status != "rejected"
GROUP BY c.id,
c.name,
c.location,
c.capacity,
c.begin_date,
c.end_date,
c.price,
c.active

You should connect your subquery to main query:
select courses.id,
courses.name,
courses.location,
courses.capacity,
(SELECT count(courses_requests.IDcourse)
FROM courses_requests,
WHERE courses_requests.ID = courses.id
and status != "rejected" ) as Registered,
begin_date,
end_date,
price,
active
from courses

You can use join to simplify your query ans using SUM() with a condition will give you the count
select
c.id,
c.name,
c.location,
c.capacity,
SUM(cr.status != "rejected") as Registered,
c.begin_date,
c.end_date,
c.price,
c.active
from courses c
JOIN courses_requests cr ON (cr.IDcourse = c.id)
GROUP BY c.id

Related

Get attempts of exams for every course of every student

I'm new to SQL. I want to get attempts of exams for every course of every student.
I've made this query in my database:
SELECT students.id, students.surname, students.name, courses.name AS "course" FROM `students`
JOIN exam_student
ON exam_student.student_id = students.id
JOIN exams
ON exam_student.exam_id = exams.id
JOIN courses
ON exams.course_id = courses.id
ORDER BY students.surname ASC, students.name ASC;
The query produces this
Now, what I want is to get for every user, the attempts of exams of every course name.
I have the exams pivot with user_id and course_id.
How can I reach this result?
Seems you want a total.
So let's COUNT the attempts by aggregating it.
SELECT s.id, s.surname, s.name
, c.name AS course
, COUNT(e.id) AS exam_attempts
FROM students s
LEFT JOIN exam_student es ON es.student_id = s.id
LEFT JOIN exams e ON e.id = es.exam_id
LEFT JOIN courses c ON c.id = e.course_id
GROUP BY s.id, s.surname, s.name, c.id, c.name
ORDER BY s.surname, s.name, c.name;

Using SUM with Joins in MySQL returns unexpected result

I have these tables : customers, customer_invoices, customer_invoice_details, each customer has many invoices, and each invoice has many details.
The customer with the ID 574413 has these invoices :
select customer_invoices.customer_id,
customer_invoices.id,
customer_invoices.total_price
from customer_invoices
where customer_invoices.customer_id = 574413;
result :
customer_id invoice_id total_price
574413 662146 700.00
574413 662147 250.00
each invoice here has two details (or invoice lines) :
first invoice 662146:
select customer_invoice_details.id as detail_id,
customer_invoice_details.customer_invoice_id as invoice_id,
customer_invoice_details.total_price as detail_total_price
from customer_invoice_details
where customer_invoice_details.customer_invoice_id = 662146;
result :
detail_id invoice_id detail_total_price
722291 662146 500.00
722292 662146 200.00
second invoice 662147 :
select customer_invoice_details.id as detail_id,
customer_invoice_details.customer_invoice_id as invoice_id,
customer_invoice_details.total_price as detail_total_price
from customer_invoice_details
where customer_invoice_details.customer_invoice_id = 662147;
result :
detail_id invoice_id detail_total_price
722293 662147 100.00
722294 662147 150.00
I have a problem with this query :
select customers.id as customerID,
customers.last_name,
customers.first_name,
SUM(customer_invoices.total_price) as invoice_total,
SUM(customer_invoice_details.total_price) as details_total
from customers
join customer_invoices
on customer_invoices.customer_id = customers.id
join customer_invoice_details
on customer_invoice_details.customer_invoice_id = customer_invoices.id
where customer_id = 574413;
unexpected result :
customerID last_name first_name invoice_total details_total
574413 terry amine 1900.00 950.00
I need to have the SUM of the total_price of the invoices, and the SUM of the total_price of the details for each customer. In this case I'm supposed to get 950 as total_price for both columns (invoice_total& details_total) but it's not the case. what am I doing wrong & how can I get the correct result please. The answers in similar topics don't have the solution for this case.
When you mix normal columns with aggregate functions (for example SUM), you need to use GROUP BY where you list the normal columns from the SELECT.
The reason for the excessive amount in total_price for invoices is that the SUM is also calculated over each detail row as it is part of the join. Use this:
select c.id as customerID,
c.last_name,
c.first_name,
SUM(ci.total_price) as invoice_total,
SUM((select SUM(d.total_price)
from customer_invoice_details d
where d.customer_invoice_id = ci.id)) as 'detail_total_price'
from customers c
join customer_invoices ci on ci.customer_id = c.id
where c.id = 574413
group by c.id, c.last_name, c.first_name
db-fiddle
I used join against sub queries and then did a sum on the sums
SELECT c.id as customerID,
c.last_name,
c.first_name
SUM(i.sum) as invoice_total,
SUM(d.sum) AS details_total
FROM customers c
JOIN (SELECT id, customer_id, SUM(total_price) AS sum
FROM customer_invoices
GROUP BY id, customer_id) AS i ON i.customer_id = c.id
JOIN (SELECT customer_invoice_id as id, SUM(total_price) AS sum
FROM customer_invoice_details
GROUP BY customer_invoice_id) AS d ON d.id = i.id
WHERE c.id = 574413
GROUP BY c.id, c.name
The issue is in the joining logic. The table customers is used as the driving table in the joins. But in the second join, you are using a derivative key column from the first join, to join with the third tables. This is resulting in a Cartesian output doubling the records from the result from the nth-1 join, which is leading to customer_invoices.total_price getting repeated twice, hence the rolled up value of this field is doubled.
At a high level I feel that the purpose of rolling up the prices is already achieved in SUM(customer_invoice_details.total_price).
But if you have a specific project requirement that SUM(customer_invoices.total_price) should also be obtained and must match with SUM(customer_invoice_details.total_price), then you can do this:
In a separate query, Join customer_invoice_details and customer_invoices. Roll up the pricing fields, and have a result such that you have only one record for one customer ID.
Then use this as a sub-query and join it with the customers table.
You are aggregating along multiple dimensions. This is challenging. I would suggest doing the aggregation along each dimension independently:
select c.id as customerID, c.last_name, c.first_name,
ci.invoice_total,
cid.details_total
from customers c join
(select ci.sum(ci.total_price) as invoice_total
from customer_invoices ci
group by ci.customer_id
) ci
on ci.customer_id = c.id join
(select ci.sum(cid.total_price) as details_total
from customer_invoices ci join
customer_invoice_details cid
on cid.customer_invoice_id = ci.id
group by ci.customer_id
) cid
on cid.customer_id = c.id
where c.id = 574413;
A faster version (for one customer) uses correlated subqueries:
select c.id as customerID, c.last_name, c.first_name,
(select ci.customer_id, sum(ci.total_price) as invoice_total
from customer_invoices ci
where ci.customer_id = c.id
) as invoice_total,
(select ci.customer_id, sum(cid.total_price) as details_total
from customer_invoices ci join
customer_invoice_details cid
on cid.customer_invoice_id = ci.id
where ci.customer_id = c.id
) as details_total
from customers c
where c.id = 574413;

Error #1241 SQL Query

I keep getting error code #1241. I have been looking to find an answer but I can't find an answer that helped me.
Here is my code:
SELECT name, address, city, phone
FROM customer
WHERE customer.ID IN (
SELECT customer.ID, COUNT(*) AS amount_reservations
FROM customer, (
SELECT ID
FROM customer, reservations
WHERE rent_time = 'weekend' AND
ID = customer_ID
) AS foo
WHERE customer.ID = foo.ID
GROUP BY customer.ID
HAVING amount_reservations > 1
)
The subquery SELECT customer.ID, COUNT(*) AS amount_reservations should have a SINGLE column, not two.
Change it as:
SELECT name, address, city, phone
FROM customer
WHERE customer.ID IN (
SELECT customer.ID
FROM customer, (
SELECT ID FROM customer, reservations
WHERE rent_time = 'weekend' AND ID = customer_ID
) AS foo
WHERE customer.ID = foo.ID
GROUP BY customer.ID HAVING count(*) > 1
)
I'd highly recommend rewriting your query. Remove the subqueries -- they aren't needed. Then use explicit joins instead of commas.
select c.id, c.name, c.address, c.city, c.phone
from customer c
join reservations r on c.id = r.customer_id
where r.rent_time = 'weekend'
group by c.id, c.name, c.address, c.city, c.phone
having count(*) > 1
If you want to use in, you can radically simplify the query:
SELECT c.name, c.address, c.city, c.phone
FROM customer c
WHERE c.ID IN (SELECT r.customer_id
FROM reservations r
WHERE r.rent_time = 'weekend'
GROUP BY r.customer_id
HAVING COUNT(*) > 1
) ;
Notes:
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
Use table aliases and qualified column names for all column references.
You don't need a JOIN in the subquery, because you have the customer id in the reservations table.

SQL LEFT JOIN COUNT

Been pounding my head with this one.
I have two tables
employee
id
name
active
user_id
report
id
employee_id
user_id
created_at
and a lot more
I want to select employees which have a specific user_id and furthermore add a column with the count of reports for that specific employee (employee_id) for a specific year.
Here's what i have tried, but failed to succeed.
SELECT c.id, c.name, c.active, c.user_id, COUNT( u.id ) no_of_reports
FROM employee c
LEFT JOIN report u ON c.id = u.employee_id
WHERE c.user_id =1
AND YEAR( u.created_at ) = '2014'
GROUP BY c.id, c.name
ORDER BY c.name ASC
Everything works fine, except when i put in a condition for my LEFT JOIN. I only want it to count the u.id if the created_at column is within the year 2014. That works fine, BUT if there are NO u.ids (meaning there are no reports for that employee), the whole employee is left out, instead of just setting the no_of_reports to 0, and still give me the id, name, active and user_id as a row in my result.
Removing AND YEAR(u.created_at)='2014' gives me the correct result, except it includes the reports created outside 2014.
You can put multiple conditions in your JOIN clause:
SELECT c.id, c.name, c.active, c.user_id, COUNT( u.id ) no_of_reports
FROM employee c
LEFT JOIN report u ON (c.id = u.employee_id AND YEAR( u.created_at ) = '2014')
WHERE c.user_id =1
GROUP BY c.id, c.name
ORDER BY c.name ASC
This will select all users, but only join the reports created in 2014

mysql query to arrange data from four tables according to timestamp

i am trying to get data from four tables with respect to the the "type". Types can be comment, cover pic change, friend request accept etc. but the problem is the query i made is not working by repeating the types for all and timestamp for all. the query i made is
SELECT c.up_date, c.user_id, c.id, f.id,
f.up_date, f.friend1, f.friend2, f.status,
s.postdate, s.status, s.id, s.display_name, s.userid, s.userid1, s.type,
c.type, f.type
FROM cover_pic c, wp_userstatus s, wp_friends f
WHERE s.userid = f.friend1
AND s.userid = c.user_id
AND f.status =3
AND c.user_id =4
ORDER BY s.postdate
LIMIT 0 , 30
can anyone help me with the right query with respect to timestamp and the type
here is the result its giving me
what i want
timestamp userid_id id display_name type
233232323 1 1 paramveer comment
1212121212 1 2 paramveer coverpic
Maybe you want an union of joins
(select distinct s.postdate as postdate, s.userid, c.id, c.type
from wp_userstatus s
join cover_pic c on s.userid = c.user_id)
union
(select distinct s.postdate, s.userid, f.id, f.type
from wp_userstatus s
join wp_friends f on s.userid = f.friend1)
order by postdate
limit 30
It's really hard to tell.