Custom sub-select requests and where clauses with MySQL - mysql

I'm trying to list the content of a table using sub-selects and select only the one that match my WHERE clause:
SELECT DISTINCT `torrentItem` as ti,
(SELECT COUNT(*) FROM votes WHERE `torrentItem` = ti AND `voteType` = 0) AS `badVotes`,
(SELECT COUNT(*) FROM votes WHERE `torrentItem` = ti AND `voteType` = 1) AS `goodVotes`,
(SELECT TIMESTAMPDIFF(WEEK,(SELECT MAX(`date`) FROM votes WHERE `torrentItem` = ti),CURRENT_TIMESTAMP)) AS `weeksSinceLastVote`
FROM `votes`
WHERE (`badVotes` > 1 AND `goodVotes` = 0 AND `weeksSinceLastVote` > 1);
It's not working : MySQL tells me that I can't just use badVotes or goodVotes in the WHERE clause :
Error Code: 1054. Unknown column 'badVotes' in 'where clause'
Can you explain me why ? And how to do it ?

For each row in your table each subquery is executed. Performance nightmare :)
You can rewrite your query as
SELECT `torrentItem` as ti,
SUM(`voteType` = 0) AS `badVotes`,
SUM(`voteType` = 1) AS `goodVotes`,
TIMESTAMPDIFF(WEEK, MAX(`date`), CURRENT_TIMESTAMP) AS `weeksSinceLastVote`
FROM `votes`
GROUP BY ti
HAVING (`badVotes` > 1 AND `goodVotes` = 0 AND `weeksSinceLastVote` > 1);
This will run much, much better than your subqueries.
The reason why you can't use an alias in the where clause is the order in which a query is interpreted.
FROM
WHERE
GROUP BY
HAVING
ORDER BY
SELECT

You can not use the column alias on where clause.
However you can use having clause for the same.
Check more details here http://dev.mysql.com/doc/refman/5.0/en/problems-with-alias.html

Related

MYSQL: Error Code: 1054. Unknown column in 'where clause'

I'm trying to pass a column from the outer query as shown below to the inner query in the WHERE clause and MySQL does not like it. I'm unsure how to rewrite this query to make it work.
The error message I am getting is Unknown column 'y.DateShipped' in where clause
What I am trying to do is to join to the row in the inner table with an EffectiveDate that is less than the DateShipped and also is the max EffectiveDate in the inner join (there can be multiple rows for the same group by with different EffectiveDate(s))
I would love to know how to get this working or rewrite it so that it will work. I am using MySQL 5.6, so I don't have window functions available otherwise I think that could work.
select
x.id,
y.id,
y.DateShipped
from Shipment y inner join
(select id, SourceId, DestinationId, SourcePPFContractId, EffectiveDate
from Relationship where EffectiveDate <= y.DateShipped order by
EffectiveDate desc limit 1) x
on x.DestinationId = y.DestinationCustomerId
and x.SourceId = y.OriginCustomerId
and x.SourcePPFContractId = y.OriginContractId;
The inner select (from Relationship) is executed first and then merged with the first select. That's why it doesn't work. You should move the DateShipped to the where clause of the first select:
select
x.id,
y.id,
y.DateShipped
from Shipment y inner join
(select id, SourceId, DestinationId, SourcePPFContractId, EffectiveDate
from Relationship order by
EffectiveDate desc limit 1) x
on x.DestinationId = y.DestinationCustomerId
and x.SourceId = y.OriginCustomerId
and x.SourcePPFContractId = y.OriginContractId
and x.EffectiveDate <= y.DateShipped;
You are attempting something called a lateral join -- and MySQL does not support those. Because you want only one column, you can use a correlated subquery:
select (select r.id
from Relationship r
where r.DestinationId = s.DestinationCustomerId and
r.SourceId = s.OriginCustomerId and
r.SourcePPFContractId = s.OriginContractId and
r.EffectiveDate <= s.DateShipped
order by r.EffectiveDate desc
limit 1
) as x_id,
s.id, s.DateShipped
from Shipment s ;
Note that I also changed the table aliases to be abbreviations for the table names -- so the query is easier to read.
you would need to list the shipment table in the sub query to be able to call it properly try:
select
x.id,
y.id,
y.DateShipped
from Shipment y inner join
(select id, SourceId, DestinationId, SourcePPFContractId, EffectiveDate
from Relationship, Shipment where EffectiveDate <= Shipment.DateShipped order by
EffectiveDate desc limit 1) x
on x.DestinationId = y.DestinationCustomerId
and x.SourceId = y.OriginCustomerId
and x.SourcePPFContractId = y.OriginContractId;

MySQL Count as {name} and WHERE {name} = X, Unknown column

I am trying to filter results based on the name assigned on count() and get this:
Unknown column 'total_submissions' in 'where clause'
SELECT SQL_CALC_FOUND_ROWS patient.*,count(patient_data.id) as total_submissions
FROM patient
LEFT JOIN patient_data ON (patient_data.patient_id = patient.id AND patient_data.date_finished IS NOT NULL)
WHERE patient.doc_id = 2 AND total_submissions = 5
GROUP BY patient.id
ORDER BY patient.id DESC
LIMIT 0,40
After more research I did find out about not being able to use a column alias in the WHERE but I am unsure how to execute this query then. I assume it's possible but how would I be able to filter the results based on the count() calculation of the query?
total_submissions is a column alias and the result of an aggregation function. You need to do that check in a havingclause:
SELECT SQL_CALC_FOUND_ROWS p.*, count(pd.id) as total_submissions
FROM patient p LEFT JOIN
patient_data pd
ON pd.patient_id = p.id AND pd.date_finished IS NOT NULL
WHERE p.doc_id = 2
GROUP BY p.id
HAVING total_submissions = 5
ORDER BY p.id DESC
LIMIT 0, 40;
Notes:
Table aliases make the query easier to write and to read.
The condition on doc_id should still be in the WHERE clause.
You can't use column alias in where clause because the precedence in sql evaluation don't let the db engine know the alias name when evaluate the where clause
First is evaluated the FROM clase then the WHERE clause and after the SELECT cluase ..
In your case you have an aggregation function related to yu alias and this can be evaluated only after the group by is performed, pratically at the end of query process
for this reason there is a proper filter based on HAVING that work on the result of the aggreated query
SELECT SQL_CALC_FOUND_ROWS patient.*, count(patient_data.id) as total_submissions
FROM patient
LEFT JOIN patient_data ON (patient_data.patient_id = patient.id AND patient_data.date_finished IS NOT NULL)
WHERE patient.doc_id = 2
GROUP BY patient.id
HAVING total_submissions = 0
ORDER BY patient.id DESC
LIMIT 0,40

mySQL 'where name NOT IN' not working?

I have this statement:
SELECT id, name
FROM players
WHERE this = 1
AND name NOT IN (SELECT name
FROM players_online
WHERE this = 'that')
ORDER BY RAND()
LIMIT 3, 6
All columns are correctly named. No SQL errors occur, it just returns no results.
From what I've read in documentation it should work, but doesn't.
Any idea?
Don't use NOT IN with subqueries. It has the wrong semantics if any value in the subquery is NULL. In that case, the NOT IN never evaluates to TRUE, so no rows are returned at all.
Instead, use NOT EXISTS:
SELECT p.id, p.name
FROM players p
WHERE p.this = 1 AND
NOT EXISTS (SELECT 1
FROM players_online po
WHERE po.name = p.name AND po.this = 'that'
)
ORDER BY RAND()
LIMIT 3, 6;

Get Count for the answer of the below query

Can somebody guide me how to get the count for the answer of this query?
SELECT wo.Client_id
FROM wish_order wo,
wish_order_fruit wof
WHERE wo.wish_order_id = wof.wish_order_id
GROUP BY wof.wish_order_id
HAVING Count(wo.Client_id) > 1;
Use a derived table to get the # of rows returned by the group by query
select count(*) from (
select wo.Client_id
from wish_order wo, wish_order_fruit wof
where wo.wish_order_id = wof.wish_order_id
Group by wof.wish_order_id
having Count(wo.Client_id) >1
) t1

MySQL unknown column using subquery

I receive an error when i execute this query:
SELECT
(SELECT count(cp_projeto_view.id) FROM cp_projeto_view WHERE cp_projeto_view.id_projeto = cp_projeto.id AND cp_projeto_view.id_pessoa = 467 LIMIT 1) AS qtde_visualizacoes
FROM cp_projeto
WHERE qtde_visualizacoes = 0
The error is: #1054 - Unknown column 'qtde_visualizacoes' in 'where clause'
Why qtde_visualizacoes does not exists?
Thank you very much!
You cannot use a column alias in a where clause (unless you use a subquery). MySQL has an extension where you can use having instead:
SELECT (SELECT count(cp_projeto_view.id)
FROM cp_projeto_view
WHERE cp_projeto_view.id_projeto = cp_projeto.id AND cp_projeto_view.id_pessoa = 467
LIMIT 1
) AS qtde_visualizacoes
FROM cp_projeto
HAVING qtde_visualizacoes = 0
EDIT:
The query that you probably want is more like:
select p.*
from cp_projecto p
where not exists (select 1 from cp_projeto_view pv where pv.id_projeto = p.id and pv.id_pessoa = 467)
This will return all cp_projectos that have no matching rows in cp_projeto_view. Your original query would only return rows with a single column of 0s, which doesn't make much sense. If you want the count, then do:
select count(*) as cnt
from cp_projecto p
where not exists (select 1 from cp_projeto_view pv where pv.id_projeto = p.id and pv.id_pessoa = 467)
And, for performance, create an index on cp_projeto_view(projeto, id_pessoa).