Doctrine and aliases from the select clause in the where clause - php

I am using an alias in my select clause (AVG(u.rating) as avg_rating) and would then like to add this in my where clause avg_rating > 3 but when I try and run this query I get a Unknown column 'u3__1' in 'where clause'.
Does anyone happen to know how I can get my where clause to see the alias? This alias works in the orderBy with no issue, just not the where.
EDIT: (for more details)
The above was an example, but here is the real rendered SQL, not as simple. My issue is actually with an alias on value with a bunch of conditionals. And the alias I am having trouble with is the generated date which has recurrences and doesn't have to every date field populated. So I am posting a simple SQL query that gives me the same issue.
SELECT t.type_id as type_alias, t.* FROM theme as t WHERE t.id > 1 AND type_alias = 3
And here is the real query if you are so interested:
SELECT t.id AS t__id, t.created_by AS
t__created_by, t.type_id AS
t__type_id, t.url_slug AS t__url_slug,
t.name AS t__name, t.description AS
t__description, t.summary AS
t__summary, t.start_month AS
t__start_month, t.start_day AS
t__start_day, t.start_year AS
t__start_year, t.duration_unit AS
t__duration_unit, t.duration_length AS
t__duration_length, t.is_active AS
t__is_active, t.is_public AS
t__is_public, t.needs_moderation AS
t__needs_moderation, t.recurrence AS
t__recurrence, t.tag_string AS
t__tag_string, t.date_created AS
t__date_created, t.date_updated AS
t__date_updated, AVG(t2.rating) AS
t2__0, IF(t.recurrence = "none",
STR_TO_DATE(CONCAT(t.start_month,
t.start_day, t.start_year), "%m%d%Y"),
(IF(STR_TO_DATE(CONCAT(t.start_month,
t.start_day, YEAR(NOW())), "%m%d%Y") >
NOW(),
STR_TO_DATE(CONCAT(t.start_month,
t.start_day, YEAR(NOW())), "%m%d%Y"),
STR_TO_DATE(CONCAT(t.start_month,
t.start_day, (YEAR(NOW())+1)),
"%m%d%Y")))) AS t__1, (COUNT(u.id) +
COUNT(e.id)) AS u__2 FROM theme t LEFT
JOIN theme_rating t2 ON t.id =
t2.theme_id LEFT JOIN
user_saves_themes u ON t.id =
u.theme_id LEFT JOIN event e ON
((e.is_active = 1 AND e.theme_id =
t.id)) WHERE t.id IN ('3', '2', '1')
AND (IF(t.recurrence = "none",
STR_TO_DATE(CONCAT(t.start_month,
t.start_day, t.start_year), "%m%d%Y"),
(IF(STR_TO_DATE(CONCAT(t.start_month,
t.start_day, YEAR(NOW())), "%m%d%Y") >
NOW(),
STR_TO_DATE(CONCAT(t.start_month,
t.start_day, YEAR(NOW())), "%m%d%Y"),
STR_TO_DATE(CONCAT(t.start_month,
t.start_day, (YEAR(NOW())+1)),
"%m%d%Y")))) >=
FROM_UNIXTIME(1278001295) AND
t.is_public = ? AND t.is_active = ?)
GROUP BY t.id ORDER BY t__1

Look at this:
http://dev.mysql.com/doc/refman/5.0/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. For
example, the following query is illegal:
Either you have to add HAVING clause or repeat your alias in WHERE clause.

Try having instead of where.

Related

Remove duplicates from result using MySQL and PHP

I have a query given below
SELECT A.order_no, A.order_date,
COUNT(B.reaction_no) as tot_reaction_no,
SUM(CASE
WHEN (B.purification != '') THEN 1
ELSE 0
END) as tot_purification
FROM order_header A
LEFT JOIN order_reactions B ON A.order_no = B.order_no
WHERE A.order_date BETWEEN '2015-10-01 00:00:00' AND '2016-09-01 00:00:00'
AND A.order_no = '23746'
GROUP BY A.order_no
this will results as shown in the picture. But the result is wrong because some of the entries are duplicates. So I have to remove the duplicate and print the count. Count required is the count of "column" from the table 1.
I think you need to leave out the A.order_date in your select or you should add it to the group by clause. That gives you a different result though.
You may also use a subquery in your select clause:
SELECT A.order_no, A.order_date,
COUNT(B.reaction_no) as tot_reaction_no,
(SELECT count(*) FROM order_reactions as or WHERE or.order_no=A.order_no AND purification!='') as tot_purification,
(SELECT count(*) FROM order_reactions as or2 WHERE or.order_no=A.order_no) as tot_reaction_no
FROM order_header A
WHERE A.order_date BETWEEN '2015-10-01 00:00:00' AND '2016-09-01 00:00:00'
AND A.order_no = '23746'
This is just from the top of my head, since your screenshots are not showing the full tables I'm not sure this is 100% right, but it might point you in the right direction.
I would propose the query
SELECT COUNT(DISTINCT clone_name) AS tot_purification, COUNT(*) AS tot_reaction_no FROM Table2 WHERE `purification`='Column' AND `order_no`=23746;
Please excuse errors in quotation, MySQL is very confusing when it comes to quotation imo.
EDIT:
Added AS tot_purification
I'm not sure what you are expecting as tot_reaction_no, so I just counted all rows where Order and purification match as described in my WHERE clause.
Its because you are grouping only on A.order_no, make following changes in the query and try again:
Replace the line:
GROUP BY A.order_no;
to
GROUP BY A.order_no, A.clone_name;

criteria->group not works in yii

I want to use criteria->group in yii query but it gives error like
CDbCommand failed to execute the SQL statement: SQLSTATE[42S21]
currently i use is:
$criteria->group = 'reg.user_first_name';
$criteria->order = 't.inout_time';
when i use only order by then it works proper like:
SELECT `t`.`attendant_id`, `t`.`user_id` FROM `attendance_master` `t`
LEFT JOIN registration_master reg on reg.ai_sync_id = t.user_id
WHERE (((t.well_master_id=:ycp0) AND (t.status=:ycp1)) AND (t.user_type_id=:ycp2)) AND (t.inout_time LIKE :time)
ORDER BY t.inout_time LIMIT 10.
Bound with :ycp0='1429082167', :ycp1='in', :ycp2='2', :time='2015-05-06%'
but when i add group by condition then error occurs like:
1060 Duplicate column name 'ai_sync_id'. The SQL statement executed was:
SELECT COUNT(*) FROM (SELECT * FROM `attendance_master` `t`
LEFT JOIN registration_master reg on reg.ai_sync_id = t.user_id
WHERE (((t.well_master_id=:ycp0) AND (t.status=:ycp1)) AND (t.user_type_id=:ycp2)) AND (t.inout_time LIKE :time)
GROUP BY reg.user_first_name) sq.
Bound with :ycp0='1429082167', :ycp1='in', :ycp2='2', :time='2015-05-06%'
i know this is a small issue but i cant find as i am new in yii.
You can't group by reg.user_first_name when do SELECT t.attendant_id, t.user_id FROM ... group field must be in result set.
So try just:
SELECT `t`.`attendant_id`, `t`.`user_id`, reg.user_first_name FROM
and if you do GROUP BY you should use any aggregate function (SUM, COUNT, MAX ...)usually.

How to optimise this MySQL SQL query?

I'm working with the join plus union plus group by query, and I developed a query something like mentioned below:
SELECT *
FROM (
(SELECT countries_listing.id,
countries_listing.country,
1 AS is_country
FROM countries_listing
LEFT JOIN product_prices ON (product_prices.country_id = countries_listing.id)
WHERE countries_listing.status = 'Yes'
AND product_prices.product_id = '3521')
UNION
(SELECT countries_listing.id,
countries_listing.country,
0 AS is_country
FROM countries_listing
WHERE countries_listing.id NOT IN
(SELECT country_id
FROM product_prices
WHERE product_id='3521')
AND countries_listing.status='Yes')) AS partss
GROUP BY id
ORDER BY country
And I just realised that this query is taking a lot of time to load results, almost 8 seconds.
I was wondering if there is the possibility to optimize this query to the fastest one?
If I understand the logic correctly, you just want to add a flag for the country as to whether or not there is a price for a given product. I think you can use an exists clause to get what you want:
SELECT cl.id, cl.country,
(exists (SELECT 1
FROM product_prices pp
WHERE pp.country_id = cl.id AND
pp.product_id = '3521'
)
) as is_country
FROM countries_listing cl
WHERE cl.status = 'Yes'
ORDER BY country;
For performance, you want two indexes: countries_listing(status, country) and
product_prices(country_id, product_id)`.
Depending on how often it is executed, prepared statements could help. See PDO for more information.

Filtering and restricting in query

I would like to seek some help in my query...i want to do is if specific atic and oaic is empty in the table...the interview_sum or other_sum to that specific atic oaic should be empty too....can anyone know how to do that?
picture of current output:
current query: my query still gives numbers to other_sum or interview_sum even its empty.
SELECT DISTINCT
IF(t.inttotal=NULL,0,(SELECT SUM(t2.inttotal)
FROM app_interview2 AS t2
WHERE t2.atic = t.atic AND t2.inttotal>0)/7)
AS interview_sum,
IF(o.ototal=NULL,0,(SELECT SUM(o2.ototal)
FROM other_app2 AS o2
WHERE o2.oaic = o.oaic AND o2.ototal>0)/7)
AS other_sum,
atid,
atic,
atname,
region,
town,
uniq_id,
position,
salary_grade,
salary
FROM app_interview2 AS t, other_app2 AS o
GROUP BY t.atname HAVING COUNT(DISTINCT t.atic)
I made a few assumptions:
You probably have a table that app_interview2.atic and other_app2.oaic are the foreign keys of, but since you did not share it, I derived a table in the FROM clause.
This assumes atname is always the same for atid.
You are also dividing by 7 - which I assume is to get the average, so I used the AVG function.
Solution---
SELECT t1.id AS atid
,interview.atname AS atname
,COALESCE(interview.interviewsum, 0) AS interviewsum
,COALESCE(interview.interviewavg,0) AS interviewavg
,COALESCE(other.othersum, 0) AS othersum
,COALESCE(other.otheravg) AS otheravg
FROM (SELECT DISTINCT atid AS id
FROM app_interview2
UNION
SELECT DISTINCT oaic
FROM other_app2) AS t1
LEFT JOIN (SELECT atid, atname, SUM(inttotal) AS interviewsum, AVG(inttotal) AS interviewavg
FROM app_interview2
GROUP BY atid, atname) as interview
ON interview.atid = t1.id
LEFT JOIN (SELECT oaic, SUM(ototal) AS othersum, AVG(ototal) AS otheravg
FROM other_app2
GROUP BY oaic) AS other
ON other.oaic = t1.id;
--
If this gives the results your were hoping for, I would replace the t1 derived table in the FROM clause with the table whose primary key I described above AND probably has those columns (e.g., region, town, etc) that I did not include

Need help in optimising query

I have two tables - incoming tours(id,name) and incoming_tours_cities(id_parrent, id_city)
id in first table is unique, and for each unique row from first table there is the list of id_city - s in second table(i.e. id_parrent in second table is equal to id from first table)
For example
incoming_tours
|--id--|------name-----|
|---1--|---first_tour--|
|---2--|--second_tour--|
|---3--|--thirth_tour--|
|---4--|--hourth_tour--|
incoming_tours_cities
|-id_parrent-|-id_city-|
|------1-----|---4-----|
|------1-----|---5-----|
|------1-----|---27----|
|------1-----|---74----|
|------2-----|---1-----|
|------2-----|---5-----|
........................
That means that first_tour has list of cities - ("4","5","27","74")
AND second_tour has list of cities - ("1","5")
Let's assume i have two values - 4 and 74:
Now, i need to get all rows from first table, where my both values are in the list of cities. i.e it must return only the first_tour (because 4 and 74 are in it's list of cities)
So, i wrote the following query
SELECT t.name
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc0 ON tc0.id_parrent = t.id
AND tc0.id_city = '4'
JOIN `incoming_tours_cities` tc1 ON tc1.id_parrent = t.id
AND tc1.id_city = '74'
And that works fine.
But i generate the query dynamically, and when the count of joins is big (about 15) the query slowing down.
i.e. when i try to run
SELECT t.name
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc0 ON tc0.id_parrent = t.id
AND tc0.id_city = '4'
JOIN `incoming_tours_cities` tc1 ON tc1.id_parrent = t.id
AND tc1.id_city = '74'
.........................................................
JOIN `incoming_tours_cities` tc15 ON tc15.id_parrent = t.id
AND tc15.id_city = 'some_value'
the query run's in 45s(despite on i set indexes in the tables)
What can i do, to optimaze it?
Thanks much
SELECT t.name
FROM incoming_tours t INNER JOIN
( SELECT id_parrent
FROM incoming_tours_cities
WHERE id IN (4, 74)
GROUP BY id_parrent
HAVING count(id_city) = 2) resultset
ON resultset.id_parrent = t.id
But you need to change number of total cities count.
SELECT name
FROM (
SELECT DISTINCT(incoming_tours.name) AS name,
COUNT(incoming_tours_cities.id_city) AS c
FROM incoming_tours
JOIN incoming_tours_cities
ON incoming_tours.id=incoming_tours_cities.id_parrent
WHERE incoming_tours_cities.id_city IN(4,74)
HAVING c=2
) t1;
You will have to change c=2 to whatever the count of id_city you are searching is, but since you generate the query dynamically, that shouldn't be a problem.
I'm pretty sure this works, but a lot less sure that it is optimal.
SELECT * FROM incoming_tours
WHERE
id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=4)
AND id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=74)
...
AND id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=some_value)
Just an hint.
If you use the IN operator in a WHERE clause, you can hope that the short-circuit of operator AND may remove unnecessary JOINs during the execution for the tours that do not respect the constraint.
Seems like an odd way to do that query, here
SELECT t.name FROM `incoming_tours` as t WHERE t.id IN (SELECT id_parrent FROM `incoming_tours_cities` as tc WHERE tc.id_city IN ('4','74'));
I think that does it, but not tested...
EDIT: Added table alias to sub-query
I've written this query using CTE's and it includes the test data in the query. You'll need to modify it so that it queries the real tables instead. Not sure how it performs on a large dataset...
Declare #numCities int = 2
;with incoming_tours(id, name) AS
(
select 1, 'first_tour' union all
select 2, 'second_tour' union all
select 3, 'third_tour' union all
select 4, 'fourth_tour'
)
, incoming_tours_cities(id_parent, id_city) AS
(
select 1, 4 union all
select 1, 5 union all
select 1, 27 union all
select 1, 74 union all
select 2, 1 union all
select 2, 5
)
, cityIds(id_city) AS
(
select 4
union all select 5
/* Add all city ids you need to check in this table */
)
, common_cities(id_city, tour_id, tour_name) AS
(
select c.id_city, it.id, it.name
from cityIds C, Incoming_tours_cities tc, incoming_tours it
where C.id_city = tc.id_city
and tc.id_parent = it.id
)
, tours_with_all_cities(id_city) As
(
select tour_id from common_cities
group by tour_id
having COUNT(id_city) = #numCities
)
select it.name from incoming_tours it, tours_with_all_cities tic
where it.id = tic.id_city

Categories