Using pseudonym in WHERE clause in MYSQL query - mysql

Please don't bite me for this, but I'm new to mysql and I have some problem with using pseudonym in WHERE clause. I thought that it is possible to use pseudonym for aggregate function, defined in the select statement.
Here is my query
SELECT a.name, s.name, COUNT(e.id) as total FROM athletes a
INNER JOIN sports s on s.id = a.sport_id
INNER JOIN events e on s.id = e.sport_id
WHERE total >=2 GROUP BY a.name
But, I catch an error "Unknown column total in WHERE clause".
Could anyone tell me if it is right to do query like this?

You can not use alias in the where clause. You need to use that in having
SELECT
a.name,
s.name,
COUNT(e.id) as total FROM athletes a
INNER JOIN sports s on s.id = a.sport_id
INNER JOIN events e on s.id = e.sport_id
GROUP BY a.name having total >=2

Instead of WHERE total >=2 you can use HAVING (total >= 2 )
HAVING:
SELECT a.name, s.name, COUNT(e.id) as total
FROM athletes a
INNER JOIN sports s on s.id = a.sport_id
INNER JOIN events e on s.id = e.sport_id
GROUP BY a.name, s.name
HAVING (total >= 2 );

Yo can not use an column alias in where clause. you have to use the expression COUNT(e.id) in where clasue or you can use the alias in a having clause:
SELECT a.name, s.name, COUNT(e.id) as total FROM athletes a INNER JOIN sports s on s.id = a.sport_id INNER JOIN events e on s.id = e.sport_id WHERE COUNT(e.id)>=2 GROUP BY a.name
or
SELECT a.name, s.name, COUNT(e.id) as total FROM athletes a INNER JOIN sports s on s.id = a.sport_id INNER JOIN events e on s.id = e.sport_id having total>=2 GROUP BY a.name

Related

MY SQL : please confirm if my query is right else provide right query

i using this query but test case not passed
select ct.name,cm.name,sl.quantity
from sales as sl
inner join country as ct on sl.country_id=ct.id
inner join car_model as cm on cm.id=sl.model_id
where sl.sales_date BETWEEN '01-01-2020' AND '12-31-2020'
order by ct.quantity asc;
select
ct.name,
cm.name,
sl.quantity
from
sales as sl
inner join country as ct
on sl.country_id = ct.id
inner join car_model as cm
on sl.model_id = cm.id
where
sl.sales_date BETWEEN '2020-01-01' AND '2020-12-31'
order by
sl.quantity asc;

Display results which have no count/zero as well

I am trying to get a count of the number of logins during a given timeframe, currently my SQL query displays only results that had at least one login, I'd like it to display even those which have zero logins.
Query i'm using:
SELECT c.FullName, COUNT(l.Id)
FROM LoginsTable l JOIN UsersTable u ON u.Email = l.Email JOIN Organisations c ON c.Id = u.OrganisationId
WHERE l.AttemptTime > "2019-10-01" AND l.AttemptTime < "2019-11-01" AND l.Success = 1
GROUP BY c.Name
ORDER BY c.Name ASC;
You have a few issues. Firstly, you either need to use a RIGHT JOIN from LoginsTable or reorder the JOINs to put the JOIN to LoginsTable last and use a LEFT JOIN. Given the nature of your query the latter probably makes more sense.
Secondly, you need to put any conditions on fields from a table which has been LEFT JOINed into the join condition, otherwise MySQL converts the LEFT JOIN into an INNER JOIN (see the manual). Finally, you should GROUP BY the same fields as specified in your SELECT. This should work:
SELECT c.FullName, COUNT(l.Id)
FROM Organisations c
JOIN UsersTable u ON u.OrganisationId = c.Id
LEFT JOIN LoginsTable l ON u.Email = l.Email AND l.AttemptTime > "2019-10-01" AND l.AttemptTime < "2019-11-01" AND l.Success = 1
GROUP BY c.FullName
ORDER BY c.FullName
I found 2 issues here:
your group by column is not listed on your column
date condition is using double quotes.
try below query.
SELECT c.FullName, COUNT(l.Id)
FROM LoginsTable l
LEFT JOIN UsersTable u ON u.Email = l.Email
LEFT JOIN Organisations c ON c.Id = u.OrganisationId
WHERE l.AttemptTime between '2019-10-01' AND '2019-11-01' AND l.Success = 1
GROUP BY c.FullName
ORDER BY c.FullName ASC;
As Roman Hocke said you need to use left join as below :
SELECT c.FullName, COUNT(l.Id)
FROM UsersTable u
JOIN Organisations c ON c.Id = u.OrganisationId
LEFT JOIN LoginsTable l ON u.Email = l.Email
WHERE l.AttemptTime > "2019-10-01" AND l.AttemptTime < "2019-11-01" AND l.Success = 1
GROUP BY c.Name
ORDER BY c.Name ASC;
Moreover, you should fix your group by or select using the same field : SELECT c.Name or GROUP BY c.FullName ORDER BY c.FullName
EDIT : Nick's answer is the one. As he said perfectly well, you need to put your conditions in the on clause of your left join.
SELECT c.FullName, COUNT(l.Id)
FROM UsersTable u
JOIN Organisations c ON c.Id = u.OrganisationId
LEFT JOIN LoginsTable l ON (u.Email = l.Email AND l.AttemptTime > "2019-10-01" AND l.AttemptTime < "2019-11-01" AND l.Success = 1)
GROUP BY c.FullName
ORDER BY c.FullName ASC;

Left join Count disturbing left join SUM

When i added a left join for getting count of foreign table, its multiply my sum value of other left join table with the count, also I cant use distinct sum here as two values can be same:
SELECT c.id as company_id, SUM(ct.amount) as total_billed, count(l.id) as load_count
FROM tbl_companies c
LEFT JOIN tbl_company_transactions ct ON c.id = ct.company_id
LEFT JOIN tbl_loads l ON c.id = l.company_id
GROUP BY c.id;
You need to pre-aggregate the data:
SELECT c.id as company_id, ct.total_billed,
l.load_count
FROM tbl_companies c LEFT JOIN
(SELECT ct.company_id, SUM(ct.amount) as total_billed
FROM tbl_company_transactions ct
GROUP BY ct.company_id
) ct
ON c.id = ct.company_id LEFT JOIN
(SELECT l.company_id, COUNT(*) as load_count
FROM tbl_loads l
GROUP BY l.company_id
) l
ON c.id = l.company_id;
As you have observed, the JOIN multiplies the number of rows and affects the aggregations.
You could isolate aggregate statistics and join results afterwards.
WITH
tranStats AS (
SELECT company_id, SUM(amount) AS total_billed
FROM tbl_company_transactions
GROUP BY company_id
),
loadStats AS (
SELECT company_id, COUNT(1) AS load_count
FROM tbl_loads
GROUP BY company_id
)
SELECT id, total_billed, load_count
FROM tbl_companies c
LEFT JOIN tranStats t ON t.company_id = c.id
LEFT JOIN loadStats l ON l.company_id = c.id
Gordon's answer is more scalable but for this specific query you only need one subquery — which may also offer a performance boost since joins on the pre-aggregated data may not be able to use indexes.
SELECT c.id as company_id, SUM(ct.amount) as total_billed, l.load_count
FROM tbl_companies c
LEFT JOIN tbl_company_transactions ct ON c.id = ct.company_id
LEFT JOIN (
SELECT company_id, count(*) as load_count
FROM tbl_loads
GROUP BY company_id
) l ON c.id = l.company_id
GROUP BY c.id;
The important thing to grasp is that if you need results of an aggregate function like SUM() or COUNT(), you need to be careful when you perform more than one join with multiple rows.

inner join 4 tables with group, order by, having clause

I have 4 table and i want to extract: id, nume, localitate, masina_id, nr_inmatriculare, an_fabricatie, rafinarie, marca, and sum (quantity+deliver_quantity) as total_quantity group by an_fabricatie , Order by marca, and put some having clouse.
I don’t know how to make this.
My query is as bellow , but I think isn't correct.
select c.id, c.nume,c.localitate,l.masina_id, i.nr_inmatriculare, i.an_fabricatie,
i.rafinarie, m.marca from clienti c inner join livrari l on c.id = l.id inner join incarcari I on l.incarcare_id = l.livrari_id inner join masina m on i.id_marca = m.id, sum(select quantity, deliver_quantity) as total_quantity group by an_fabricatie having quantity >1000 order by marca;
Incarcari table
Id|livrari_id|id_marca|nr_inmatriculare|an_fabricatie|rafinarie|aviz_incarcare|quantity|
Livrari table
Id|masina_id|client_id|incarcare_id|deliver_quantity|aviz_livrare
Masini table
Id|numar_inmatriculare|marca|an_fabricatie|
Clienti table
Id|nume|localitate|date_add|date_upd|
SELECT c.id, c.nume, c.localitate, l.masina_id, i.nr_inmatriculare, i.an_fabricatie, i.rafinarie, m.marca, (SUM(i.quantity) + SUM(l.deliver_quantity)) AS total_quantity
FROM clienti c
INNER JOIN livrari l ON c.id = l.id
INNER JOIN incarcari i ON l.incarcare_id = i.livrari_id
INNER JOIN masini m ON i.id_marca = m.id
GROUP BY i.an_fabricatie, c.id, c.nume,c.localitate,l.masina_id, i.nr_inmatriculare, i.rafinarie, m.marca
HAVING i.quantity > 1000
ORDER BY m.marca DESC;

MYSQL SUM and INNER JOIN

I want to have the name in the first colomn but i get an error. When i Let P.name out, the query works but I can't see the player name.
Right now I have the following query:
SELECT P.Name, P.Playernr, SUM (F.Amount)
FROM FINES F
INNER JOIN PLAYERS P
ON F.Playernr = P.Playernr
GROUP BY P.Playernr
Thanks in advance for help
Onno
You should add it to the GROUP BY clause.
SELECT P.Name, P.Playernr, SUM (F.Amount)
FROM FINES F
INNER JOIN PLAYERS P
ON F.Playernr = P.Playernr
GROUP BY P.Name,P.Playernr
Try this:
SELECT MAX(P.Name) as Name, P.Playernr, SUM (F.Amount)
FROM FINES F
INNER JOIN PLAYERS P
ON F.Playernr = P.Playernr
GROUP BY P.Playernr
or add P.Name to the Group BY
SELECT P.Name, P.Playernr, SUM (F.Amount)
FROM FINES F
INNER JOIN PLAYERS P
ON F.Playernr = P.Playernr
GROUP BY P.Name,P.Playernr
When GROUP BY used, only group by column and aggregation function can be projected. Remove P.Name in projection column or add P.Name in GROUP BY
SELECT P.Name, P.Playernr, SUM (F.Amount)
FROM FINES F
INNER JOIN PLAYERS P
ON F.Playernr = P.Playernr
GROUP BY P.Playernr, P.Name
In other RDBMS, your query produces error.
think about below data:
P.Playernr P.Name
A B
A C
A D
then, P.Name is not in GROUP BY, which value is produced in SELECT P.Playernr. so, you must use aggregation function or add P.Name in GROUP BY