MySQL count() within subquery - mysql

I am trying to count the number of bookings for the next 7 days with the following query.
select calendarDate,
(
select COUNT(*)
FROM isBooked INNER JOIN booking
ON isbooked.BookingID = booking.bookingID
where specificday between booking.startDate and booking.endDate
)
from calendar as specificday
where calendardate between '2015-08-23' and DATE_ADD('2015-08-23', INTERVAL 6 DAY);
I have used SQL server which allows the use of 'as specificday' however MySQL does not, how would i rewrite the query in mysql.

specificday refers to a table, not a column. You need a column name for the WHERE clause:
select c.calendarDate,
(select COUNT(*)
from isBooked ib INNER JOIN
booking b
ON ib.BookingID = b.bookingID
where c.calendarDate between b.startDate and b.endDate
)
from calendar c
where c.calendardate between '2015-08-23' and DATE_ADD('2015-08-23', INTERVAL 6 DAY);

Related

Query shows values from tables differently [duplicate]

This question already has answers here:
sql sum data from multiple tables
(6 answers)
Closed 2 years ago.
I have 3 tables (attendance, allowances and deductions) with some records in attendance.Wage, allowances.Amount, deductions.Amount columns. And I want to "SUM" values in these columns with selected date.
Summed up values must be
attendance.Wage:100
allowances.Amount:150
deductions.Amount:120
but with my query values are seeing very different.
SELECT Name, SUM(attendance.Wage), SUM(allowances.Amount), SUM(deductions.Amount) FROM employees
INNER JOIN attendance USING (EmployeeID)
INNER JOIN allowances USING (EmployeeID)
INNER JOIN deductions USING (EmployeeID)
WHERE MONTH(attendance.Date) = 6 AND YEAR(attendance.Date) = 2020
AND
MONTH(allowances.Date) = 6 AND YEAR(allowances.Date) = 2020
AND
MONTH(deductions.Date) = 6 AND YEAR(deductions.Date) = 2020
GROUP BY employees.EmployeeID;
Output of the query:
attendance.Wage:400
allowances.Amount:900
deductions.Amount:720
Why the values are multiplying or increasing? How can I fix that?
Because you are getting multiple rows from each table and the join is multiplying them.
Without additional information, I would recommend correlated subqueries:
SELECT e.Name,
(SELECT SUM(a.Wage)
FROM attendance a
WHERE a.EmployeeID = e.EmployeeID AND
a.date >= '2020-06-01' AND a.date < '2020-07-01'
),
(SELECT SUM(a.Amount)
FROM allowances a
WHERE a.EmployeeID = e.EmployeeID AND
a.date >= '2020-06-01' AND a.date < '2020-07-01'
),
(SELECT SUM(d.Amount)
FROM deduction d
WHERE d.EmployeeID = e.EmployeeID AND
d.date >= '2020-06-01' AND d.date < '2020-07-01'
)
FROM employees e;
With an index on (EmployeeId, date, amount/wage) in each of the three tables, this should also have better performance than alternatives using explicit aggregations and joins.
You would need to push the aggregation down in subqueries, otherwise the sums count each value multiple times.
SELECT e.Name, ad.total_attendance, aw.total_allowances, dd.total_deductions
FROM employees e
INNER JOIN (
SELECT EmployeeID, SUM(wage) total_attendance
FROM attendance
WHERE date >= '2020-06-01' and date < '2020-07-01'
GROUP BY EmployeeID
) ad USING (EmployeeID)
INNER JOIN (
SELECT EmployeeID, SUM(amount) total_allowances
FROM allowances
WHERE date >= '2020-06-01' and date < '2020-07-01'
GROUP BY EmployeeID
) aw USING (EmployeeID)
INNER JOIN (
SELECT EmployeeID, SUM(amount) total_deductions
FROM deductions
WHERE date >= '2020-06-01' and date < '2020-07-01'
GROUP BY EmployeeID
) dd USING (EmployeeID)

Combine two conditions with diffrent tables MySQL

Can I make one query with this two conditions? And if yes, which way should I dig?
SELECT c.ID, c.DateEnd FROM conference c WHERE DateEnd = DATE_ADD(CURDATE(),INTERVAL 1 DAY)
SELECT a.ID, a.IDConf FROM application a GROUP BY a.IDConf HAVING COUNT(a.IDConf) >= 2
if you want join only the result for HAVING COUNT(a.IDConf) >= 2 you could use a inner join on subselect
SELECT c.ID, c.DateEnd
FROM conference c
INNER JOIN (
SELECT a.ID, a.IDConf
FROM application a
GROUP BY a.IDConf
HAVING COUNT(a.IDConf) >= 2
) t ON c.ID=t.IDConf
WHERE c.DateEnd = DATE_ADD(CURDATE(),INTERVAL 1 DAY)
You can use a left join. Try this:
SELECT c.ID, a.ID a_ID, c.DateEnd
FROM conference c LEFT JOIN application a
ON c.ID=a.IDConf
WHERE DateEnd=DATE(DATE_ADD(CURDATE(),INTERVAL 1 DAY))
GROUP BY c.ID, a.ID
HAVING COUNT(a.IDConf)>=2;
See MySQL Join Made Easy for insight on using joins.

MYSQL - Issue with sub-query

SELECT DISTINCT(id_no), lastname,
(SELECT COUNT(purchasedate) num_of_purch
FROM sales JOIN Artist ON
sales.id = Artist.id_no
WHERE DATE_SUB(CURDATE(),INTERVAL 1
YEAR) <= purchasedate
) AS num_of_purch
FROM Artist
This query returns the all Artist's ID_no, and their last name and the total number of purchases, altho i want to specify which purchases were to which artist. Help in solving this would be greatly apprciated.
EDIT - DISTINCT(id_no) is redundant as it is a primary key.
This shows the number of sales for each artist_id:
SELECT artist.id_no, count(sales.id) as num_of_purch
FROM artist left join sales on sales.id = artist.id_no
WHERE DATE_SUB(CURDATE(), INTERVAL 1 YEAR) <= purchasedate
GROUP BY artist.id
To return also the last names, and all of the details:
SELECT art_tot.id_no, art_tot.lastname, art_tot.num_of_purch, sales.*
FROM (SELECT artist.id_no, artist.lastname, count(sales.id) as num_of_purch
FROM artist left join sales on sales.id = artist.id_no
WHERE DATE_SUB(CURDATE(), INTERVAL 1 YEAR) <= purchasedate
GOUP BY artist.id, artist.lastname) art_tot
left join sales on art_tot.id_no = sales.id
This should give you artist and number of purchases per artist
select a.id_no, a.lastname, count(s.purchasedate) num_of_purch
from artists a
join sales s on a.id_no = s.id
where date_sub(curdate(), interval 1 year) <= s.purchasedate
group by a.id_no, a.lastname
You should use a GROUP BY to get the count per artist.
And you should use an outer join to include artists who have no sales within the last year.
SELECT a.id_no, a.lastname, COUNT(s.purchasedate) AS num_of_purch
FROM Artist a
LEFT OUTER JOIN sales s ON s.id = a.id_no
AND s.purchasedate => CURDATE() - INTERVAL 1 YEAR
GROUP BY a.id_no;
PS: Using DISTINCT(id_no) is meaningless not only because id_no is already a unique key, but because DISTINCT always applies to all columns in the select list, even if you add parentheses to make it look like a function that applies only to one column.

using two cases of exists in sql query

I am trying to make a query that says If the customer has no invoice, but has an appointment in the last 6 months, please give me their clientId and name The following result returns and empty set.
SELECT clients.clientId, clients.studentFirstName, clients.studentLastName
FROM clients, invoices, appointments
WHERE (NOT EXISTS
(SELECT *
FROM invoices, clients
WHERE invoices.clientId = clients.clientId))
AND (EXISTS
(SELECT * FROM appointments, clients
WHERE appointments.clientId = invoices.clientId
AND appointments.date >= DATE_ADD(curdate(), INTERVAL 6 MONTH)));
EDIT: The query that ended up working was created after a little tweaking of john's answer:
SELECT a.clientID,
a.studentFirstName,
a.studentLastName
FROM clients a
LEFT JOIN invoices b
on a.clientID = b.clientID
LEFT JOIN appointments c
on a.clientID = c.clientID
WHERE b.clientId IS NULL AND
c.`date` >= DATE_SUB(curdate(), INTERVAL 6 MONTH)
Use LEFT JOIN instead.
SELECT a.ClientID,
a.studentFirstName,
a.clients.studentLastName
FROM clients a
LEFT JOIN invoices b
on a.ClientID = b.ClientID
LEFT JOIN appointments c
on a.ClientID = c.ClientID
WHERE b.Client IS NULL AND
c.`Date` >= DATE_SUB(curdate(), INTERVAL 6 MONTH)
Are you sure it's supposed to be DATE_ADD and not DATE_SUB ?
You can use joins:
SELECT a.clientId,
a.studentFirstName,
a.studentLastName
FROM clients a
JOIN appointments b ON a.clientId = b.clientId
AND b.date >= CURDATE() - INTERVAL 6 MONTH
LEFT JOIN invoices c ON a.clientId = c.clientId
WHERE c.clientId IS NULL

Select where column is null or not in subquery

I have 2 tables with names and a schedule of dates related to those names. I am trying to get a list of all names that have never been scheduled or have not been scheduled in the last 2 months.
SELECT n.name, MAX(s.date)
FROM names n
LEFT JOIN schedule s ON n.id = s.nameid
WHERE s.nameid IS NULL
OR s.nameid NOT IN (SELECT nameid
FROM schedule
WHERE date > NOW() - INTERVAL 2 MONTH)
GROUP BY n.id
When I run this query MySQL takes over the CPU and doesn't respond.
When I change it to either of these I get results, but only half the results I am looking for:
SELECT n.name, MAX(s.date)
FROM names n
LEFT JOIN schedule s ON n.id = s.nameid
WHERE s.nameid IS NULL
GROUP BY n.id
SELECT n.name, MAX(s.date)
FROM names n
LEFT JOIN schedule s ON n.id = s.nameid
WHERE s.nameid NOT IN (SELECT nameid
FROM schedule
WHERE date > NOW() - INTERVAL 2 MONTH)
GROUP BY n.id
I am not sure how to get this query working to return all the results or why it takes over the CPU.
OR is a notorious poor performer, in every database I can think of. A UNION if often a better alternative:
SELECT n.name, MAX(s.date)
FROM names n
LEFT JOIN schedule s ON n.id = s.nameid
WHERE s.nameid IS NULL
GROUP BY n.id
UNION
SELECT n.name, MAX(s.date)
FROM names n
LEFT JOIN schedule s ON n.id = s.nameid
WHERE s.nameid NOT IN (SELECT nameid
FROM schedule
WHERE date > NOW() - INTERVAL 2 MONTH)
GROUP BY n.id
UNION will remove duplicates -- if there's no concern about duplicates, use UNION ALL (it's faster, because it doesn't remove duplicates).
Additionally, the latter query has criteria against the OUTER JOIN'd table in the WHERE clause -- this criteria is applied after the JOIN. You might get different results using:
SELECT n.name, MAX(s.date)
FROM names n
LEFT JOIN schedule s ON s.nameid = n.id
AND s.nameid NOT IN (SELECT nameid
FROM schedule
WHERE date > NOW() - INTERVAL 2 MONTH)
GROUP BY n.id
In the example above, the criteria will be applied before the OUTER JOIN. For INNER JOINs, this can be ignored -- criteria in either spot is equivalent.
Without knowing your full schema, is there something wrong with
SELECT n.name, max(s.date)
FROM names n
LEFT JOIN schedule s
ON n.id = s.nameid
WHERE s.nameid IS NULL
OR s.date <= DATE_SUB(CURDATE(), INTERVAL 2 MONTH)
GROUP BY n.id