I use some sql like this:
SELECT COALESCE(group.display,item.display) as display....
I would like to add in the WHERE clause:
WHERE display='1'
WHERE display is the result of the coalesce.
Similarly I'd like to be able to do the same with something like this:
IF(ISNULL(gd.group_main_image),p.main_image,gd.group_main_image) AS image
... WHERE image IS NOT NULL
How can I do this please?
You can't use aliases in the same level of query.
You must repeat yourself.
WHERE COALESCE(group.display,item.display) = '1'
EDIT
Well, I've been too restrictive. You can use alias in an having clause in MySql. You can't do that in other DBMS (Oracle, SQl Server). Generally it's also not permitted in ANSI SQL.
You can't use column aliases in WHERE clause
So:
WHERE COALESCE(group.display,item.display)='1'
OR:
HAVING display='1'
However, HAVING is performed after all the result-set is discovered, so basically this is more memory consuming
As described in Problems with Column Aliases:
An alias can be used in a query select list to give a column a different name. You can use the alias in GROUP BY, ORDER BY, or HAVING clauses to refer to the column:
SELECT SQRT(a*b) AS root FROM tbl_name
GROUP BY root HAVING root > 0;
SELECT id, COUNT(*) AS cnt FROM tbl_name
GROUP BY id HAVING cnt > 0;
SELECT id AS 'Customer identity' FROM tbl_name;
Standard SQL disallows references to column aliases in a WHERE clause. This restriction is imposed because when the WHERE clause is evaluated, the column value may not yet have been determined. For example, the following query is illegal:
SELECT id, COUNT(*) AS cnt FROM tbl_name
WHERE cnt > 0 GROUP BY id;
The WHERE clause determines which rows should be included in the GROUP BY clause, but it refers to the alias of a column value that is not known until after the rows have been selected, and grouped by the GROUP BY.
Related
I need to use an alias in the WHERE clause, but It keeps telling me that its an unknown column. Is there any way to get around this issue? I need to select records that have a rating higher than x. Rating is calculated as the following alias:
sum(reviews.rev_rating)/count(reviews.rev_id) as avg_rating
You could use a HAVING clause, which can see the aliases, e.g.
HAVING avg_rating>5
but in a where clause you'll need to repeat your expression, e.g.
WHERE (sum(reviews.rev_rating)/count(reviews.rev_id))>5
BUT! Not all expressions will be allowed - using an aggregating function like SUM will not work, in which case you'll need to use a HAVING clause.
From the MySQL Manual:
It is not allowable to refer to a
column alias in a WHERE clause,
because the column value might not yet
be determined when the WHERE clause
is executed. See Section B.1.5.4,
“Problems with Column Aliases”.
I don't know if this works in mysql, but using sqlserver you can also just wrap it like:
select * from (
-- your original query
select .. sum(reviews.rev_rating)/count(reviews.rev_id) as avg_rating
from ...) Foo
where Foo.avg_rating ...
This question is quite old and one answer already gained 160 votes...
Still I would make this clear: The question is actually not about whether alias names can be used in the WHERE clause.
sum(reviews.rev_rating) / count(reviews.rev_id) as avg_rating
is an aggregation. In the WHERE clause we restrict records we want from the tables by looking at their values. sum(reviews.rev_rating) and count(reviews.rev_id), however, are not values we find in a record; they are values we only get after aggregating the records.
So WHERE is inappropriate. We need HAVING, as we want to restrict result rows after aggregation. It can't be
WHERE avg_rating > 10
nor
WHERE sum(reviews.rev_rating) / count(reviews.rev_id) > 10
hence.
HAVING sum(reviews.rev_rating) / count(reviews.rev_id) > 10
on the other hand is possible and complies with the SQL standard. Whereas
HAVING avg_rating > 10
is only possible in MySQL. It is not valid SQL according to the standard, as the SELECT clause is supposed to get executed after HAVING. From the MySQL docs:
Another MySQL extension to standard SQL permits references in the HAVING clause to aliased expressions in the select list.
The MySQL extension permits the use of an alias in the HAVING clause for the aggregated column
https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
SELECT * FROM (SELECT customer_Id AS 'custId', gender, age FROM customer
WHERE gender = 'F') AS c
WHERE c.custId = 100;
If your query is static, you can define it as a view then you can use that alias in the where clause while querying the view.
Example:
SELECT customer_id, address_id as addressID
FROM customer
WHERE addressID = 5
But, using the HAVING clause works perfectly fine. So why aliases don't work in the where clause?
Only MySQL permits alises in HAVING, it is not standard SQL (see here: https://dba.stackexchange.com/questions/50391/why-does-mysql-allow-having-to-use-select-aliases ) please note that no other major RDBMS allows the use of aliases in WHERE or HAVING.
The reason you can't use aliases in WHERE (and HAVING) is because SELECT is actually evaluated after most other sub-clauses: https://stackoverflow.com/a/21693272/159145
A SELECT query is evaluated, conceptually, in the following order:
The FROM clause
The WHERE clause
The GROUP BY clause
The HAVING clause
The SELECT clause
The ORDER BY clause
So your query:
SELECT
customer_id,
address_id AS addressID
FROM
customer
WHERE
addressID = 5
Is evaluated in this order:
1: FROM
customer
2: WHERE
address_id = 5
3: SELECT
customer_id,
address_id AS addressID
As you cans see, if the WHERE part referenced addressID instead of address_id the query execution engine would complain because addressID is not defined at that point.
MySQL does permit the referencing of (normal) aliases in HAVING by doing a (non-standard) neat trick where it partially evaluates the SELECT before it evaluates HAVING - and because MySQL has a handling of aliases that means the evaluation engine can be sure that the alias is valid (which is why most other RDBMS engines don't allow the use of aliases in HAVING when they otherwise should be able to). But you can't use an alias in WHERE because if there's a GROUP BY then it might render an alias meaningless, consider:
SELECT
SUM( foo ) AS baz,
created
FROM
foo
WHERE
baz > 5 -- Meaningless: the GROUP BY hasn't been evaluated yet, so `baz` is unavailable
GROUP BY
created
MySQL explains this in their manual: https://dev.mysql.com/doc/refman/5.7/en/problems-with-alias.html
Standard SQL disallows references to column aliases in a WHERE clause. This restriction is imposed because when the WHERE clause is evaluated, the column value may not yet have been determined.
The WHERE clause determines which rows should be included in the GROUP BY clause, but it refers to the alias of a column value that is not known until after the rows have been selected, and grouped by the GROUP BY.
I have question about priority operation in sql statement. For example:
SELECT t1.c2, COUNT(DISTINCT t2.c1) as count_c1 FROM t1 JOIN t2
WHERE t2.c2 > 1 GROUP BY t1.c2 HAVING count_c1 > 1;
Which filter from this query will be applied first and which last. As I understand condition in HAVING will be last, it means that server generate full record set and after that remove all rows with count_c1 < 1 and return result to client.
Condition under WHERE will be first, it means that server don't even get rows with t2.c2 < 1, but what's about DISTINCT and GROUP BY? Result will be different if server will apply DISTINCT before GROUP BY from the opposite situation(GROUP BY first and DISTINCT second). I can't find anything in documentation about this, may be you help me.
Frist, like Thorsten Kettner said, your SQL syntax is actually invalid. Secondly,
The order of operations I was able to find (source) is as follows:
FROM clause (this includes JOIN's)
WHERE clause
GROUP BY clause
HAVING clause
SELECT clause
ORDER BY clause
The priority operation in SQL in as:
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
You have learn about it in MVA here
The DBMS is free to either join first and then apply the WHERE clause or use the WHERE clause already to restrict rows to join.
Aggregation. Grouping by c2, counting distinct c1 in the process. You count distinct c1 per c2.
The HAVING clause (as it is dealing with the aggregated rows). MySQL allows for an alias name here, which doesn't comply with standard SQL (as the SELECT clause is not yet executed).
SELECT clause: Show the results.
According to w3schools group by needs an aggregate_function(column_name).
SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
What it will happen if you commit this aggregate_function?
Thanks
If you are looking for best practice, do not use GROUP BY unless you are using an aggregate function. MySQL is unique in that it allows you to specify additional columns without using aggregates. This is not found in other DBMS's.
MySQL extends the use of GROUP BY to permit selecting fields that are not mentioned in the GROUP BY clause.
The other effect that GROUP BY has is it's sorting property.
If you use GROUP BY, output rows are sorted according to the GROUP BY columns as if you had an ORDER BY for the same columns.
If you do not include any aggregate functions, it will most likely show the DISTINCT values of the grouped column.
Depending on MySQL version and ONLY_FULL_GROUP_BY mode, it either rejects the query or picks any value from each group (it is undefined which one it chooses).
Here is a thorough description on this: MySQL Handling of GROUP BY
I need to use an alias in the WHERE clause, but It keeps telling me that its an unknown column. Is there any way to get around this issue? I need to select records that have a rating higher than x. Rating is calculated as the following alias:
sum(reviews.rev_rating)/count(reviews.rev_id) as avg_rating
You could use a HAVING clause, which can see the aliases, e.g.
HAVING avg_rating>5
but in a where clause you'll need to repeat your expression, e.g.
WHERE (sum(reviews.rev_rating)/count(reviews.rev_id))>5
BUT! Not all expressions will be allowed - using an aggregating function like SUM will not work, in which case you'll need to use a HAVING clause.
From the MySQL Manual:
It is not allowable to refer to a
column alias in a WHERE clause,
because the column value might not yet
be determined when the WHERE clause
is executed. See Section B.1.5.4,
“Problems with Column Aliases”.
I don't know if this works in mysql, but using sqlserver you can also just wrap it like:
select * from (
-- your original query
select .. sum(reviews.rev_rating)/count(reviews.rev_id) as avg_rating
from ...) Foo
where Foo.avg_rating ...
This question is quite old and one answer already gained 160 votes...
Still I would make this clear: The question is actually not about whether alias names can be used in the WHERE clause.
sum(reviews.rev_rating) / count(reviews.rev_id) as avg_rating
is an aggregation. In the WHERE clause we restrict records we want from the tables by looking at their values. sum(reviews.rev_rating) and count(reviews.rev_id), however, are not values we find in a record; they are values we only get after aggregating the records.
So WHERE is inappropriate. We need HAVING, as we want to restrict result rows after aggregation. It can't be
WHERE avg_rating > 10
nor
WHERE sum(reviews.rev_rating) / count(reviews.rev_id) > 10
hence.
HAVING sum(reviews.rev_rating) / count(reviews.rev_id) > 10
on the other hand is possible and complies with the SQL standard. Whereas
HAVING avg_rating > 10
is only possible in MySQL. It is not valid SQL according to the standard, as the SELECT clause is supposed to get executed after HAVING. From the MySQL docs:
Another MySQL extension to standard SQL permits references in the HAVING clause to aliased expressions in the select list.
The MySQL extension permits the use of an alias in the HAVING clause for the aggregated column
https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
SELECT * FROM (SELECT customer_Id AS 'custId', gender, age FROM customer
WHERE gender = 'F') AS c
WHERE c.custId = 100;
If your query is static, you can define it as a view then you can use that alias in the where clause while querying the view.