criteria->group not works in yii - php

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.

Related

Solution for "Subquery returns more than 1 row"

I'm trying to substitute my join SQL code to a different code without any of JOIN statements for faster data retrieval. However, i'm getting the error below.
#1242 - Subquery returns more than 1 row
What i would like to do, get all rows from one table 'tbl_my_itemlist' and JOIN to other more tables, tbl_register and tbl_register without using JOIN statements.
The Code using JOIN statement (works fine).
SELECT
tbl_screenshots.screenshot_image_url,
mit.my_itemlist_id,
mit.item_name,
mit.item_initial_cost,
mit.item_offer_cost,
mit.offer_date_from,
mit.offer_date_to
FROM
(
SELECT
my_itemlist_id
FROM
tbl_my_itemlist
WHERE
offer_date_from >='2020-10-20' AND offer_date_to <= '2020-10-30' AND
item_deleted_status = 'active'
) mlist
JOIN tbl_my_itemlist mit ON
mit.my_itemlist_id = mlist.my_itemlist_id
RIGHT JOIN tbl_screenshots ON mit.my_itemlist_id =
tbl_screenshots.my_itemlist_id
RIGHT JOIN tbl_register ON tbl_register.register_id = mit.register_id
GROUP BY
mit.my_itemlist_id
ORDER BY mit.offer_date_to ASC LIMIT 2
The code i'm substituting the JOIN statement code with.
SELECT
mit.my_itemlist_id,
mit.item_name,
mit.item_initial_cost,
mit.item_offer_cost,
mit.offer_date_from,
mit.offer_date_to,
(
SELECT
reg.business_name
FROM
tbl_register reg
WHERE
reg.register_id = mit.register_id
) reg_sql,
(
SELECT
sshots.screenshot_image_url
FROM
tbl_screenshots sshots
WHERE
sshots.my_itemlist_id = mit.my_itemlist_id
) sshots_sq
FROM
tbl_my_itemlist mit
WHERE
mit.offer_date_from >= '2020-10-20' AND mit.offer_date_to <= '2020-10-30' AND mit.item_deleted_status = 'active'
GROUP BY
mit.my_itemlist_id
ORDER BY
mit.offer_date_to ASC
LIMIT 2
I'm trying to build an SQL query that can retrieve data from million records within very short period of time as compared to using the JOIN statement.

Two SQL queries returning odd results

I am going to run a query which gives latest arrears when provided with admission_code, but there is some logical error:
SELECT *
FROM fees_invoice_information AS fii
WHERE fii.admission_code = 12111
This SQL returns:
enter image description here
While when I want to get latest record from following query
SELECT
MAX(fii.id),fii.*,
sep.registration_code,
sep.admission_code,
fii.arrears,
sep.is_enabled
FROM
fees_invoice_information AS fii
JOIN
std_education_profile AS sep ON fii.admission_code = sep.admission_code
WHERE
fii.`admission_code` = 12111
I get:
enter image description here
In which "arrears" column is not '0'
Move the MAX criteria to a subquery in the WHERE clause:
SELECT fii.*,
sep.registration_code,
sep.admission_code,
sep.is_enabled
FROM fees_invoice_information AS fii
INNER JOIN std_education_profile AS sep
ON fii.admission_code = sep.admission_code
WHERE fii.admission_code = 12111 AND
fii.id = (SELECT MAX(id) FROM fees_invoice_information)
Or you could use a LIMIT 1 trick:
SELECT fii.*,
sep.registration_code,
sep.admission_code,
sep.is_enabled
FROM fees_invoice_information AS fii
INNER JOIN std_education_profile AS sep
ON fii.admission_code = sep.admission_code
WHERE fii.admission_code = 12111
ORDER BY fii.id DESC
LIMIT 1
Note: This assumes that it makes logical sense to return only a single record based on the max ID. If the join isn't one to one then you might want to return a group of records, or an aggregate of a group of records.

Make SQL query faster

Can anyone tell me how to make this query faster?
$session_id = '000000000015';
$start = 0;
$finish = 30;
try {
$stmt = $conn->prepare("SELECT TOPUSERS.ID, TOPUSERS.USERNAME, TOPUSERS.NAME, TOPUSERS.NAME2, TOPUSERS.PHOTO, TOPUSERS.FB_USERID, TOPUSERS.IMAGE_TYPE, TOPUSERS.TW_USERID, TOPUSERS.TW_PHOTO,
COALESCE((SELECT COUNT(USERS_BUCKETS.ID) FROM USERS_BUCKETS WHERE USERS_BUCKETS.USERID=TOPUSERS.ID),0) AS NUM_ALL,
COALESCE((SELECT SUM(CASE WHEN USERS_BUCKETS.STATUS='Completed' THEN 1 ELSE 0 END) FROM USERS_BUCKETS WHERE USERS_BUCKETS.USERID=TOPUSERS.ID),0) AS NUM_DONE,
COALESCE((SELECT COUNT(USERS_LIKES.ID) FROM USERS_LIKES WHERE USERS_LIKES.USERID=TOPUSERS.ID),0) AS NUM_LIKES,
(SELECT USERS_BUCKETS.BUCKETID FROM USERS_BUCKETS WHERE USERS_BUCKETS.USERID=TOPUSERS.ID ORDER BY USERS_BUCKETS.DATE_MODIFIED DESC LIMIT 1) AS RECENT_BUCKET,
(SELECT BUCKETS_NEW.BUCKET_NAME FROM BUCKETS_NEW WHERE BUCKETS_NEW.ID=RECENT_BUCKET) AS REC,
COALESCE((SELECT COUNT(ID) FROM FOLLOW WHERE FOLLOW.USER_ID=TOPUSERS.ID),0) AS FOLLOWING,
COALESCE((SELECT COUNT(ID) FROM FOLLOW WHERE FOLLOW.FOLLOW_ID=TOPUSERS.ID),0) AS FOLLOWERS,
(SELECT IF(TOPUSERS.NAME = '',0,1) + IF(TOPUSERS.BIO = '',0,1) + IF(TOPUSERS.LOCATION = '',0,1) + IF(TOPUSERS.BIRTHDAY = '0000-00-00',0,1) + IF(TOPUSERS.GENDER = '',0,1)) as COMPLETENESS,
CASE WHEN ? IN (SELECT USER_ID FROM FOLLOW WHERE FOLLOW_ID = TOPUSERS.ID) THEN 'Yes' ELSE 'No' END AS DO_I_FOLLOW_HIM
FROM TOPUSERS
LEFT JOIN FOLLOW ON TOPUSERS.ID = FOLLOW.FOLLOW_ID
LEFT JOIN USERS_BUCKETS ON USERS_BUCKETS.USERID=TOPUSERS.ID
LEFT JOIN BUCKETS_NEW ON BUCKETS_NEW.ID=USERS_BUCKETS.BUCKETID
WHERE NOT TOPUSERS.ID = ?
GROUP BY TOPUSERS.ID ORDER BY TOPUSERS.RANDOM, TOPUSERS.USERNAME LIMIT $start, $finish");
When I run this in a browser it takes about 7 seconds to load. Without a few lines (the COALESCE in the middle, the two SELECTS above and the line below them) the time is reduced to 3-4 seconds.
The result of the query is a list of people with names, profile picture and some data.
TL,DR: you need to rewrite the query.
You need to rewrite your query to make it more efficient. I had to rewrite a similar query at work last week and here is what I have done.
The structure of your query should look like this to be efficient:
select ...
...
from ...
join ...
where ...
what you have now is something like:
select ...
inner select
inner select
from ...
join ...
where ...
That's the inner selects that kill your query. You need to find a way to move the inner select into the from section. Especially that you already query the tables.
What you need to understand is that your inner selects run for every records you have. So if you have 10 records, it would be alright (speed wise). But with hundred or thousand of records, it would be very slow.
If you want more information on your query run it with the explain keyword in from of it.

Zend Frameworks 1.12: how to join custom subquery table without returning results

I need to create the following query (this is just an example) using Zend Framework 1.12 as part of a larger query:
SELECT `s`.*
FROM `s`
INNER JOIN SELECT id FROM table where id = 13 AS `t`
Here's my attempt:
$query = $this->getDbTable()->select()
->from($this->getDbTable(), array('*'))
->join(array('t' => new Zend_Db_Expr('(SELECT id FROM tables where id = 13)')), array())
->setIntegrityCheck(false);
However, this is the output:
SELECT `students`.*, `t`.*
FROM `students`
INNER JOIN SELECT id FROM tables where id = 13 AS `t`
I do not require the t.* from the select since the t table will be used in other ways within the complex query.
Do you know how not to select the t.* but still have the inner join using the subquery?
The Zend_Db_Select->join command is build of two/three parameters.
table name (with possible alias)
on part (ON table1.a = table2.a..)
and the columns you want to select (if you define no parameter here, you end up selecting all the possible fields "t`.*")
In your query you are missing the last parameter. If you assign another parameter to the join (see example below) you should get only the results from the table in your ->from(... part.
->join(array('t' => new Zend_Db_Expr('(SELECT id FROM tables where id = 13)')), array(), array())

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.

Categories