Express query using doctrine query builder - php

I have the following query that I would like to convert to use doctrine's query builder.
SELECT
u.user_id,
u.username,
u.create_date AS join_date,
u.last_login_date,
u.membership_level,
u.create_date,
avg(round((ug.toggle_count / ceil((g.ply_count + 1) / 2)) * 100, 1)) AS __avg_toggle_ratio,
count(g.game_id) AS __game_count,
ugse.rating AS __echess_rating,
ugse.total_win_count AS __echess_win_count,
ugse.total_loss_count AS __echess_loss_count,
ugse.total_draw_count AS __echess_draw_count,
(SELECT concat(ugsl.rating,'|',ugsl.total_win_count,'|',ugsl.total_loss_count,'|',ugsl.total_draw_count) FROM user_game_stats_live ugsl WHERE ugsl.user_id = u.user_id AND ugsl.game_time_class = 'lightning') AS __lightning_data,
(SELECT concat(ugsl.rating,'|',ugsl.total_win_count,'|',ugsl.total_loss_count,'|',ugsl.total_draw_count) FROM user_game_stats_live ugsl WHERE ugsl.user_id = u.user_id AND ugsl.game_time_class = 'blitz') AS __blitz_data,
(SELECT concat(ugsl.rating,'|',ugsl.total_win_count,'|',ugsl.total_loss_count,'|',ugsl.total_draw_count) FROM user_game_stats_live ugsl WHERE ugsl.user_id = u.user_id AND ugsl.game_time_class = 'standard') AS __standard_data,
(SELECT uts.rating FROM user_tactics_settings uts WHERE uts.user_id = u.user_id AND uts.attempt_count >= 10) AS __tactics_rating
FROM
game g
JOIN user_game ug ON g.game_id = ug.game_id
JOIN user_game_stats_email ugse ON ug.user_id = ugse.user_id
JOIN user u ON ug.user_id = u.user_id
WHERE
g.last_move_time >= DATE_SUB(NOW(), INTERVAL 5 DAY) AND
g.ply_count >= 20 AND
u.is_enabled = 1
GROUP BY
ug.user_id
HAVING
__avg_toggle_ratio >= 90 AND
__game_count >= 10
ORDER BY
__avg_toggle_ratio DESC
Is the query builder capable of rewriting this kind of query? Should I use other methods instead, if so, how?

I'm not sure about query builder, but I woyld use the 'createNativeQuery' method:
<?php
use Doctrine\ORM\Query\ResultSetMapping;
$rsm = new ResultSetMapping();
// build rsm here
$query = $entityManager->createNativeQuery("SELECT
u.user_id,
u.username,
u.create_date AS join_date,
u.last_login_date,
u.membership_level,
u.create_date,
avg(round((ug.toggle_count / ceil((g.ply_count + 1) / 2)) * 100, 1)) AS __avg_toggle_ratio,
count(g.game_id) AS __game_count,
ugse.rating AS __echess_rating,
ugse.total_win_count AS __echess_win_count,
ugse.total_loss_count AS __echess_loss_count,
ugse.total_draw_count AS __echess_draw_count,
(SELECT concat(ugsl.rating,'|',ugsl.total_win_count,'|',ugsl.total_loss_count,'|',ugsl.total_draw_count) FROM user_game_stats_live ugsl WHERE ugsl.user_id = u.user_id AND ugsl.game_time_class = 'lightning') AS __lightning_data,
(SELECT concat(ugsl.rating,'|',ugsl.total_win_count,'|',ugsl.total_loss_count,'|',ugsl.total_draw_count) FROM user_game_stats_live ugsl WHERE ugsl.user_id = u.user_id AND ugsl.game_time_class = 'blitz') AS __blitz_data,
(SELECT concat(ugsl.rating,'|',ugsl.total_win_count,'|',ugsl.total_loss_count,'|',ugsl.total_draw_count) FROM user_game_stats_live ugsl WHERE ugsl.user_id = u.user_id AND ugsl.game_time_class = 'standard') AS __standard_data,
(SELECT uts.rating FROM user_tactics_settings uts WHERE uts.user_id = u.user_id AND uts.attempt_count >= 10) AS __tactics_rating
FROM game g
JOIN user_game ug ON g.game_id = ug.game_id
JOIN user_game_stats_email ugse ON ug.user_id = ugse.user_id
JOIN user u ON ug.user_id = u.user_id
WHERE g.last_move_time >= DATE_SUB(NOW(), INTERVAL 5 DAY)
AND g.ply_count >= 20
AND u.is_enabled = 1
GROUP BY ug.user_id
HAVING __avg_toggle_ratio >= 90
AND __game_count >= 10
ORDER BY __avg_toggle_ratio DESC', $rsm);
$query->setParameter(1, 'romanb');
$data = $query->getResult();

Related

UNION ALL use with INNER JOIN

I am trying to join 3 tables with UNION ALL. I tried the following code. and giving this error of Invalid parameter number: number of bound variables does not match number of tokens.
$codeArray = explode(',', $code);
$inQuery = implode(',', array_fill(0, count($codeArray), '?'));
$full_dt = date('Y-m-d H:i:s');
$query = "SELECT * FROM
(
SELECT
a.*
FROM pat_info a
INNER JOIN
pat_medication b
ON a.id = b.pat_id
WHERE
a.status != 2 AND b.status != 2
AND '$full_dt' BETWEEN b.start_date AND b.end_date
AND a.location_code IN ($inQuery)
AND b.stock_status != '2'
AND (b.total_qty - (b.given + b.not_taken)) < 12
UNION ALL
SELECT
a.*
FROM pat_info a
INNER JOIN
prn_medication b
ON a.id = b.pat_id
WHERE
a.status != 2 AND b.status != 2
AND '$full_dt' BETWEEN b.start_date AND b.end_date
AND a.location_code IN ($inQuery)
AND b.stock_status != '2'
AND (b.total_qty - (b.given + b.not_taken)) < 12
) x
GROUP BY a.id ORDER BY a.id DESC";
$statement = $con->prepare($query);
$statement->execute($codeArray);
As you have the in clause twice in your code, you need to bind the values twice.
A simple way to do this would be to duplicate the data prior to the execute()...
$codeArray = array_merge($codeArray, $codeArray);
You also need to change
GROUP BY a.id ORDER BY a.id DESC
to
GROUP BY x.id ORDER BY x.id DESC
as the a alias is in the sub-select and not the overall SELECT.

Yii 1.16 ORM findAll()

How can I write this in a Yii ORM findAll using CDbCriteria to fin all Users model
SELECT DISTINCT u.id, u.slug, IFNULL(MIN(m.id), 0) FROM tbl_users u
INNER JOIN tbl_status s ON (s.users_id = u.id AND s.accept > 0)
INNER JOIN tbl_message m ON (m.owner_id = s.receiver AND m.users_id = s.users_id)
WHERE u.free = 0 AND u.es_index_time <> 0 AND
u.paid = 1 AND u.withdrawed = 0 AND (
NOT EXISTS (SELECT 1 FROM tbl_users_prepay up WHERE up.users_id = u.id) OR
EXISTS (SELECT 1 FROM tbl_users_prepay up WHERE up.user_redirect_id = u.id)
)
GROUP BY u.id
LIMIT 6;
/**
* Class User - for more details:
* #see https://www.yiiframework.com/doc/api/1.1/CDbCriteria
* or
* #see http://www.bsourcecode.com/2013/06/cdbcriteria-in-yii/
*/
class User extends CActiveRecord
{
// ... user model methods
public function myCustomMethod()
{
$criteria = new CDbCriteria();
$criteria->alias = 'u';
$criteria->distinct = true;
// INNER JOIN
$criteria->join = 'INNER JOIN tbl_status s ON (s.users_id = u.id AND s.accept > 0)';
$criteria->join = 'INNER JOIN tbl_message m ON (m.owner_id = s.receiver AND m.users_id = s.users_id)';
// condition
$criteria->condition = 'u.free = 0 AND u.es_index_time <> 0 AND
u.paid = 1 AND u.withdrawed = 0 AND (
NOT EXISTS (SELECT 1 FROM tbl_users_prepay up WHERE up.users_id = u.id) OR
EXISTS (SELECT 1 FROM tbl_users_prepay up WHERE up.user_redirect_id = u.id)
)
';
$criteria->group = 'u.id';
$criteria->limit = '6';
return self::model()->findAll($criteria);
}
}

Using My SQL joins

I am having trouble finishing my MySQL JOIN. I am unsure of the syntax for the last part of my query.
My Query:
$posts_query= "
SELECT *
FROM posts p
JOIN relations r ON p.user_id = r.recipient
WHERE (r.status = 1 OR r.status = 2)
AND (r.sender = '".$user_id."' OR p.user_id = '".$user_id."')
// How do I write this part?
AND skip where r.status = 1 and p.privacy = 2 where p.user_id != $user_id //
ORDER BY p.post_id DESC;
";
Instead of 'skip', just set it so that the value isn't true, using NOT:
SELECT *
FROM posts p
JOIN relations r ON p.user_id = r.recipient
WHERE (r.status = 1 OR r.status = 2)
AND (r.sender = '$user_id' OR p.user_id = '$user_id')
AND NOT (r.status = 1 AND p.privacy = 2 AND p.user_id != '$user_id')
ORDER BY p.post_id DESC;"
SELECT *
FROM posts p
JOIN relations r ON p.user_id = r.recipient
WHERE r.status in (1,2)
AND (r.sender = '$user_id' OR p.user_id = '$user_id')
AND NOT ( r.status = 1 and p.privacy = 2 AND p.user_id != '$user_id' )
ORDER BY p.post_id DESC;

MySQL Query Optimization - Sub Queries + Multiple Joins

How can I optimize this query? It takes 2-3 seconds to get 10 rows.
SELECT users.user_id, users.user_name, users.user_display_name,
(SELECT COUNT(tweet_id) FROM tweets WHERE tweet_user_id = users.user_id AND tweet_status = 1) AS user_tweets_count,
(SELECT COUNT(tweet_reply_id) FROM tweets_reply tr JOIN tweets t ON t.tweet_id = tr.tweet_reply_tweet_id WHERE tweet_reply_user_id = users.user_id AND t.tweet_status = 1 AND tr.tweet_reply_status = 1) AS user_replies_count
FROM users
JOIN tweets ON tweets.tweet_user_id = users.user_id
JOIN tweets_reply ON tweets_reply.tweet_reply_user_id = users.user_id
WHERE (tweets_reply.tweet_reply_status = 1 AND tweets.tweet_status = 1)
GROUP BY users.user_id
ORDER BY (user_tweets_count + user_replies_count) DESC
LIMIT 10
SELECT users.user_id, users.user_name, users.user_display_name,
COUNT(tweets.tweet_id) AS user_tweets_count,
COUNT(tweets_reply.tweet_reply_id) AS user_replies_count
FROM users
JOIN tweets ON tweets.tweet_user_id = users.user_id
JOIN tweets_reply ON tweets_reply.tweet_reply_user_id = users.user_id
WHERE (tweets_reply.tweet_reply_status = 1 AND tweets.tweet_status = 1)
GROUP BY users.user_id
ORDER BY (user_tweets_count + user_replies_count) DESC
LIMIT 10
Hope this helps.

How do i sort by users with profile pictures at the top?

So i'm filling in for our developer at the moment (be for-warned i'm a beginner) but I"m trying to simply sort my search results by profiles that have a profile picture included (i.e, i don't want blank profile pictures to show up at the top of the results...they should all be at the end of the results)...Note that there are a couple user types which is why there is so much code...
I'm pretty sure where i'm going wrong is the 2 lines...
ORDER BY $order u.picture ISNULL DESC"; (which relates to ordering by profile pictures). Would really appreciate any and all help...thx!
The code is as follows:
if ($user_type == 1) {
$sql = "SELECT a.*, u.*,
(SELECT COUNT(DISTINCT userId) FROM LF_usertype_A WHERE usertype_BId = u.userId AND status = 1) as i_cnt,
(SELECT COUNT(productId) FROM LF_products WHERE userId = u.userId AND status = 1) as product_cnt,
(SELECT COUNT(transactionId)
FROM LF_Transactions
WHERE usertypeBId = u.userId
AND (status = 1 OR status = 2)
AND type = 9
AND userId != usertypeBId
AND userId != usertypeAId) AS cnt
FROM LF_Users u
JOIN LF_products a ON a.userId = u.userId
LEFT JOIN LF_Transactions t ON t.productId = a.productId
WHERE a.status = 1
AND u.status = 1
AND u.userType = :ut $where
GROUP BY u.userID
ORDER BY $order u.name DESC LIMIT 200";
} elseif ($filter != "recent" && $user_type == 2) {
$sql = "SELECT u.*,
(SELECT COUNT(a.productId) FROM LF_usertypeA a INNER JOIN LF_products ON a.productId = m.productId INNER JOIN LF_Users uu ON uu.userId = a.usertypeAId WHERE a.userId = u.userId AND uu.status = 1 AND a.status = 1 AND m.status = 1) as product_cnt,
(SELECT COUNT(transactionId)
FROM LF_Transactions
WHERE usertypeBId = u.userId
AND (status = 1 OR status = 2)
AND type = 9
AND userId != usertypeAId
AND userId != usertypeBId) AS cnt
FROM LF_Users u
LEFT JOIN LF_Transactions t ON t.usertypeBId = u.userId
WHERE u.status = 1
AND u.userId != 1
AND u.userType = :ut $where
GROUP BY u.userID
ORDER BY $order u.name DESC LIMIT 200
ORDER BY $order u.picture ISNULL DESC";
} else {
$sql = "SELECT u.*,
(SELECT COUNT(a.productId) FROM LF_usertype_A a INNER JOIN LF_products m ON a.productId = m.productId INNER JOIN LF_Users uu ON uu.userId = a.usertypeAId WHERE a.userId = u.userId AND uu.status = 1 AND a.status = 1 AND m.status = 1) as product_cnt,
(SELECT COUNT(transactionId)
FROM LF_Transactions
WHERE usertypeBId = u.userId
AND (status = 1 OR status = 2)
AND type = 9
AND userId != usertypeAId
AND userId != usertypeBId) AS cnt
FROM LF_Users u
WHERE u.status = 1
AND u.userId != 1
AND u.userType = :ut $where
GROUP BY u.userID
ORDER BY $order u.name DESC LIMIT 200
ORDER BY $order u.picture ISNULL DESC";
}
You would have to put the isnull condition before your regular sort order if you want it to take precedence:
ORDER BY ISNULL(u.picture), $order

Categories