Doctrine limit is breaking my query? - mysql

I have the following code:
$params = array();
$query_questions_visibles = questionTable::getInstance()->createQuery("q")
->select("q.*, ua.*, a.*, u.*, c.*")
->leftJoin("q.Answers a")
->leftJoin("a.UserAnswers ua")
->Where("q.blocked = false")
->andWhere("ua.user_id = :user_id")
->orderBy("q.id DESC")
->groupBy("q.id");
//Subquery --> Calculates when a question is active or not
$format = sfConfig::get("app_datetime_format");
$active_time = date($format, strtotime(sfConfig::get("app_question_active_time")));
$sub_query_is_active = $query_questions_visibles->createSubQuery()
->select("MAX(ua0.created_at)")
->from("question q0")
->leftJoin("q0.Answers a0")
->leftJoin("a0.UserAnswers ua0")
->where("q0.id = q.id");
$query_questions_visibles->addSelect("COALESCE((".$sub_query_is_active.") > :active_time, false) as Active");
//Set param values
$params["user_id"] = $guardUser->id;
$params["active_time"] = $active_time;
$result = $query_questions_visibles->execute($params);
The previous code works as expected.
Generated SQL is complete and works:
SELECT q.id AS q__id, q.user_id AS q__user_id, q.category_id AS q__category_id, q.gender_restriction AS q__gender_restriction, q.question AS q_question, q.photo AS q_photo, q.latitude AS q_latitude, q.longitude AS q_longitude, q.multiple AS q_multiple, q.blocked AS q_blocked, q.created_at AS q__created_at, q.updated_at AS q__updated_at, a.id AS a__id, a.question_id AS a__question_id, a.text AS a_text, u.id AS u_id, u.user_id AS u__user_id, u.answer_id AS u__answer_id, u.created_at AS u__created_at, u.updated_at AS u__updated_at, COALESCE((SELECT MAX(u2.created_at) AS u2__0 FROM question q2 LEFT JOIN answer a2 ON q2.id = a2.question_id LEFT JOIN user_answer u2 ON a2.id = u2.answer_id WHERE (q2.id = q.id)) > :active_time, 0) AS u2__0 FROM question q LEFT JOIN answer a ON q.id = a.question_id LEFT JOIN user_answer u ON a.id = u.answer_id WHERE (q.blocked = 0 AND u.user_id = :user_id) GROUP BY q.id ORDER BY q.id DESC
But, if I want to limit results, I modify the end lines as:
$query_questions_visibles->limit(10);
$result = $query_questions_visibles->execute($params);
Doctrine throws an error:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
at Doctrine_Connection->execute('SELECT DISTINCT q2.id FROM question q2 LEFT JOIN answer a2 ON q2.id = a2.question_id LEFT JOIN user_answer u2 ON a2.id = u2.answer_id WHERE q2.blocked = 0 AND u2.user_id = :user_id GROUP BY q2.id ORDER BY q2.id DESC LIMIT 10', array('user_id' => '1', 'active_time' => '2013-03-17 17:12:12')) in SF_ROOT_DIR\lib\vendor\symfony\lib\plugins\sfDoctrinePlugin\lib\vendor\doctrine\Doctrine\Query.php line 1290 ...
My purpose is only limit the query to 10 results, ¿where is my Subquery with COALESCE and MAX functions? ¿Why there's a SELECT DISTINCT who I never specified? ¿Why is selecting only q.id?
I spend all day trying to figure it out, i have no answer...
Any Ideas why setting a limit causes this?

When you add limit() to the Doctrine query then the Doctrine internals create in fact two queries. The first one select a limited set of distinct ids based on the conditions of your query. The second query selects the actual objects limiting the select to the ids found with the first query.
The problem with your query is that you use params inside of the select part, which is not used in the first query.
The only solutuion that comes to my mind is to add the value of the active_time parameter directly to the select part, without using the named param. It might not be the nicest solution but I can't think of a different one right now. The addSelect() does not accept additional parameters like where() does which could fix the issue (with where() you can use: ->where('field > ?', $value)).

Related

SQL error as a result of rewriting a query using subquery into a query using join

The original query:
SELECT o.offering_number,
o.english_description,
o.french_description,
fop.price_amount,
fop.price_type_code,
fop.price_status_code,
fop.offering_id,
(SELECT fop1.price_amount from facility_offering_price fop1
WHERE fop.offering_id = fop1.Offering_Id
AND fop1.price_type_code = 5
AND fop1.price_status_code = 3
) as 'priceAmount'
from facility_offering_price fop
join offering o on fop.offering_id = o.offering_id
WHERE fop.price_start_date = '15-10-28'
AND fop.price_status_code IN (1,2)
/*AND (price_status_code IS NULL)*/
AND fop.price_type_code = 5
/*AND (o.offering_number IS NULL)*/
ORDER BY o.offering_number ASC, fop.price_sequence_number ASC;
It produces a result of one entry.
The result query:
SELECT o.offering_number,
o.english_description,
o.french_description,
fop.price_amount,
fop2.price_amount,
fop.price_type_code,
fop.offering_id,
fop2.offering_id
from facility_offering_price fop
join offering o on fop.offering_id = o.offering_id
inner join
(select
fop1.offering_id,
fop1.price_amount
from facility_offering_price fop1
WHERE fop1.price_type_code = 5
AND fop1.price_status_code = 3
) fop2 on fop.offering_id = fop2.offering_id
WHERE fop.price_start_date = '15-10-28'
AND fop.price_status_code IN (1,2)
/*AND (price_status_code IS NULL)*/
AND fop.price_type_code = 5
/*AND (o.offering_number IS NULL)*/
ORDER BY o.offering_number ASC, fop.price_sequence_number ASC;
It's result set is empty. However, an entry is found if I ask for fop1.price_status_code = 1.
Unable to wrap my head around this one I would appreciate your help.
Try using LEFT JOIN instead. The conversion from SELECT a, subquery AS val FROM ... to a join is more accurately reflected that way. The original query would return rows with NULL val when the subquery has no results; your version ends up omitting such rows completely.

My where clause is returning the opposite of what I want

This is my query.
select sp.name, spi.sku, sum(spi.price), count(sp.name), spi.in_stock, spi.price, sp.is_published, spi.is_reorderable
from shop_product_category spc
inner join shop_product_category_xref spcx
on spc.shop_product_category_id = spcx.shop_product_category_id
inner join shop_product sp
on sp.shop_product_id = spcx.shop_product_id
inner join shop_product_item spi
on spi.shop_product_id = sp.shop_product_id
inner join shop_order_item soi
on spi.shop_product_item_id = soi.shop_product_item_id
where (spc.shop_product_category_id in (1316))
and sp.is_published = 1
group by sp.name
order by count(sp.name) desc
It returns everything just fine EXCEPT I want it to return lines where sp.is_published = 1 Hence the where clause. Yet to get the desired output, I have to change the current where clause to
sp.is_published <> 1
So the questions is this, why does <> 1 return rows with ones, and =1 return rows with zeros. Thanks
If sp.is_published = 1 is a string, you'll need to put it in ticks IE sp.is_published = '1'

MOODLE MySQL using 'and' in SELECT part of statement

In MOODLE, I'm using the following script to pull some numbers -- and they come out fine:
SELECT
qc.name,
q.category,
SUM(IF(qs.grade = "1",1,0)) AS Correct,
SUM(IF(qs.grade = "0",1,0)) AS Wrong
FROM
mdl_question_states qs,
mdl_quiz_attempts qa,
mdl_quiz qz,
mdl_course c,
mdl_question q,
mdl_question_categories qc
WHERE
qa.id = qs.attempt
AND qs.event = 6
AND qa.quiz = qz.id
AND ((qz.name = 'Pre-Test') OR (qz.name = 'Post-Test'))
AND qz.course = c.id
AND q.id = qs.question
AND q.category = qc.id
AND q.category > 601
GROUP BY q.category
ORDER BY qc.name
My question is this: I want to have a column (after the 'SUM(IF...' columns) that are 'Correct -AND- Pre-Test' followed by 'Correct -AND- Post-Test'.
What is the syntax to use to accomplish this?
Try
SUM(IF(sq.grade = '1' AND qz.name='pre-test', 1, 0)) AS cor_and_pre
and similarly for the other value.

How to use MYSQL's "AS" returned value inside WHERE clause?

I have a query like below...
SELECT
contents.id, contents.title, contents.createdBy,
(SELECT userGroup FROM suser_profile WHERE userId =
(SELECT users.id
FROM
users
WHERE
login = contents.createdBy)
) as userGroupID
FROM
contents
WHERE
contents.id > 0
AND contents.contentType = 'News'
**AND userGroupID = 3**
LIMIT 0, 10
When I try to assign the userGroupID inside WHERE clause the SQL fires an error saying SQL Error(1054):Unknown column "userGroupID" in "where clause"
meantime, if I make little changes like below,,
SELECT
contents.id, contents.title, contents.createdBy
FROM
smart_cms_contents
WHERE
contents.id > 0
AND contents.contentType = 'News'
**AND (SELECT userGroup FROM user_profile WHERE userId =
(SELECT users.id
FROM
users
WHERE
users.login = contents.createdBy)
) = 3**
LIMIT 0, 10
then the query works fine.
I have to use multiple userGroupID checking so that, 2nd style will make the query big, I have to have an style like first one, any help appreciated.
*NOTE : Table names are not original name what I am using in my project. You may ignore it if there are mistakes in table name. My main concern is on using the values assign to a variable by AS inside the WHERE clause.
Ignore the STARS in query*
use HAVING. example:
WHERE
contents.id > 0
AND
contents.contentType = 'News'
HAVING
userGroupID = 3
LIMIT 0, 10
If I'm understanding your initial query properly, then I believe what you want to do is a join:
SELECT DISTINCT
contents.id, contents.title, contents.createdBy
FROM
contents INNER JOIN users
ON contents.createdBy = users.login
INNER JOIN user_profile
ON user_profile.userId = users.id
WHERE
contents.id > 0
AND contents.contentType = 'News'
AND user_profile.userGroupID = 3
LIMIT 0, 10
Totally not the answer to the question you asked, but...
SELECT DISTINCT c.id, c.title, c.createdBy, s.userGroup AS userGroupID
FROM contents AS c
INNER JOIN users AS u
ON c.createdBy = u.login
INNER JOIN suser_profile AS s
ON s.userId = u.id
WHERE c.id > 0
AND c.contentType = 'News'
AND s.userGroup = 3

MySQL LEFT JOIN Problem - Missing LEFT column

I'm having problems with an SQL query used to display custom profile fields and any (optional) corresponding values.
Here is the SQL query I'm using:
SELECT pf.`id`, pf.`name`, pv.`value` FROM `profile_fields` AS pf
LEFT JOIN `profile_values` AS pv ON (pf.`id` = pv.`field_id`)
WHERE (pf.`site_id` = '0' OR pf.`site_id` = '%d') AND (pv.`user_id` = '%d' OR pv.`user_id` IS NULL)
ORDER BY pf.`order` ASC
The problem I'm having is that any columns with no corresponding profile_values records are not shown at all, when they should show, but just with an empty value.
Many thanks!
Try moving the profile values conditions to the JOIN statement:
SELECT pf.`id`, pf.`name`, pv.`value` FROM `profile_fields` AS pf
LEFT JOIN `profile_values` AS pv ON (
pf.`id` = pv.`field_id` AND
(pv.`user_id` = '%d' OR pv.`user_id` IS NULL)
)
WHERE (pf.`site_id` = '0' OR pf.`site_id` = '%d')
ORDER BY pf.`order` ASC