How to join multiple count(*) queries? - mysql

Is there a way to join multiple count(*) queries to a single one? I know that i don't need to prepare the last two queries two times but that's not what the question is about. I have no idea how to do this in a correct way.
$sth = $this->_db->prepare('SELECT count(*) FROM posts WHERE topicid = ?');
$sth->execute( array( $this->_id ) );
$numPosts = $sth->fetch(\PDO::FETCH_ASSOC);
$sth = $this->_db->prepare('SELECT count(*) FROM topic_activity WHERE topicid = ?');
$sth->execute( array( $this->_id ) );
$numViews = $sth->fetch(\PDO::FETCH_ASSOC);
$sth = $this->_db->prepare('SELECT count(*) FROM topic_activity WHERE topicid = ? AND likes = 1');
$sth->execute( array( $this->_id ) );
$numLikes = $sth->fetch(\PDO::FETCH_ASSOC);
$sth = $this->_db->prepare('SELECT count(*) FROM topic_activity WHERE topicid = ? AND likes = -1');
$sth->execute( array( $this->_id ) );
$numDislikes = $sth->fetch(\PDO::FETCH_ASSOC);

SELECT count_post, topic_activity
FROM(
SELECT count(*) AS count_post, NULL AS topic_activity FROM posts WHERE topicid = ?
UNION
SELECT NULL AS count_post, count(*) AS topic_activity FROM topic_activity WHERE topicic =?
) T
GROUP by count_post, topic_activity
let me know if it works

Although the answer of user3106988 'works', I would have gone for a more 'vertical' approach (and also store the id in a variable so you only need to pass it once, could be this doesn't work in your environment though, so could be you'll need to replace the #id's with 4 question marks, but hopefully not) :
SET #id = ?;
SELECT info = 'Posts', count(*) FROM posts WHERE topicid = #id
UNION ALL
SELECT info = 'Views', count(*) FROM topic_activity WHERE topicid = #id
UNION ALL
SELECT info = 'Likes', count(*) FROM topic_activity WHERE topicid = #id AND likes = 1
UNION ALL
SELECT info = 'DisLikes', count(*) FROM topic_activity WHERE topicid = #id AND likes = -1
But that returns 4 records where you'll then need to extract the data out by means of the info field. So, building on the idea of user3106988's answer to return just 1 record with all the info in different fields you could actually go for the likes & disklikes in as little effort as below. Should be quite fast.
SET #id = ?;
SELECT SUM(count_posts) as count_posts,
SUM(views) as views,
SUM(likes) as likes,
SUM(dislikes) as dislikes
FROM(
SELECT COUNT(*) as count_posts,
0 as views,
0 as likes,
0 as dislikes
FROM posts
WHERE topicid = #id
UNION ALL
SELECT 0 as count_posts,
COUNT(*) as views,
SUM(Case WHEN likes = 1 THEN 1 ELSE 0 END) as likes,
SUM(Case WHEN likes = -1 THEN 1 ELSE 0 END) as dislikes
FROM topic_activity
WHERE topicid = #id
) T;

Related

how write sub-query with having clause in cakephp 3

How to write following query in CakePHP 3. It has "having" clause in sub-query
the following query is working but what is the way to write CakePHP query for following complex query.
$query = "SELECT users.name, users.Id ,users.primary_image ,genders.name as genderName, FLOOR(DATEDIFF(CURDATE(),users.DOB) / 365) AS age, countries.Name as countryName, states.Name as stateName,
user_log.online_status
FROM users_address, genders , countries, states, user_log , users
WHERE gender_id = " . $looksFor->gender_id ."
AND Users_address.user_id = users.Id
AND genders.Id = users.gender_id
AND Users_address.country_id = countries.Id
AND Users_address.state_id = states.Id
AND user_log.user_id = users.Id
AND users.Id IN (
SELECT users_responses.user_id
FROM users_responses
WHERE". $conditions_list ."
GROUP BY user_id
HAVING COUNT(DISTINCT question_id, response_id) > ".$thirty_percent." );
ORDER BY RAND()
LIMIT 15 ";
}
$thirty_percent and $conditions_list have the following data which is used in sub-query to find out the results.
$thirty_percent = (int)($conditions_count/3.3 );
$conditions_list = (question_id = 3 AND response_id = 6)OR
(question_id = 5 AND response_id = 8)OR
(question_id = 12 AND response_id = 33)OR
(question_id = 6 AND response_id = 17)OR
(question_id = 9 AND response_id = 26)OR
(question_id = 7 AND response_id = 18)OR
(question_id = 1 AND response_id = 5)OR
(question_id = 8 AND response_id = 22)OR
(question_id = 2 AND response_id = 3)
EDIT:
I learnt first write sub query and then put that query in main query
Main Query: $this->Users->find('all',[
'contain'=>['Genders','Images','Users_Address', 'Countries','States'],
'conditions'=>[ 'user_id IN' => $Subquery ]
]);
Sub Query :
$Subquery = $UsersResponses->find('all',[
'conotain'=>[],
]])->where([$conditions_list, **here problem 1** ])->group('user_id')->having COUNT("(DISTINCT question_id, response_id)=>" = ".$thirty_percent." )here problem 2 ;
SQL sub-Query
SELECT users_responses.user_id
FROM users_responses
WHERE". $conditions_list ."
GROUP BY user_id
HAVING COUNT(DISTINCT question_id, response_id) > ".$thirty_percent." );
ORDER BY RAND()
LIMIT 15 ";
As you see in sub-query I need to put $conditions_list which have arrays of conditions and how we can put here in CAKEPHP.
problem 2 :need to use
GROUP BY user_id
HAVING COUNT(DISTINCT question_id, response_id) > ".$thirty_percent." );
ORDER BY RAND()
LIMIT 15 "; in sub-query but there is no clue how to do it.

Long tail where clause at CodeIgniter or Ignited Datatables

I am trying to write a long tail where statement which containing another select query and how I can do it. Currently, I am using Ignited Datatables Library with my CodeIgniter 3 installation.
SELECT ContactId,
ReceiverId,
SenderId,
IF(ReceiverId = 1,
(SELECT first_name
FROM users
WHERE users.id = contacts_connectivity.SenderId),
(SELECT first_name
FROM users
WHERE users.id = contacts_connectivity.ReceiverId)) AS FirstName,
IF(ReceiverId = 1,
(SELECT email
FROM users
WHERE users.id = contacts_connectivity.SenderId),
(SELECT email
FROM users
WHERE users.id = contacts_connectivity.ReceiverId)) AS SenderEmail,
IF(ReceiverId = 1,
(SELECT phone
FROM users
WHERE users.id = contacts_connectivity.SenderId),
(SELECT phone
FROM users
WHERE users.id = contacts_connectivity.ReceiverId)) AS SenderPhone,
IF(ReceiverId = 1,
(SELECT company
FROM users
WHERE users.id = contacts_connectivity.SenderId),
(SELECT company
FROM users
WHERE users.id = contacts_connectivity.ReceiverId)) AS SenderCompany,
ModulesId,
(SELECT ModuleName
FROM modules
WHERE ModuleId = contacts_connectivity.ModulesId) AS ModuledName,
FROM_UNIXTIME(AddedDate, "%m/%d/%Y") AddedDate
FROM contacts_connectivity
WHERE (ReceiverId = 1
OR SenderId = 1)
AND (ReceiverId
OR SenderId NOT IN
(SELECT (ReceiverId
OR SenderId)
FROM contacts_connectivity
WHERE (ReceiverId
OR SenderId) = 1))
I noticed that My query doesn't return any array at all. I already tried to write the where statement like this-
$this->datatables->where("(ReceiverId = ' . $id . ' OR SenderId = ' . $id . ')");
$this->datatables->where(" AND (ReceiverId OR SenderId NOT IN (SELECT (ReceiverId OR SenderId) FROM contacts_connectivity WHERE (ReceiverId OR SenderId) = ' . $id . '");
What am I doing wrong?
You invalid use parameters. Try something like this:
$this->datatables->where("(ReceiverId=$id OR SenderId=$id )");
Second string should be fixed too the same way. Also check that your $id param properly escaped.

Which table does the row come from?

Here is my query:
SELECT *
FROM messages
WHERE status = 1
AND (
poster IN (SELECT thing FROM follows WHERE follower = :uid AND type = 3)
OR
topic_id IN (SELECT thing FROM follows WHERE follower = :uid AND type = 1)
)
ORDER BY post_date DESC LIMIT 0, 20
I want to know which clause the rows come from. From the poster IN (...) part or the topic_id IN (...) part? How can I do that?
A straightforward way:
SELECT *
, CASE WHEN poster IN (SELECT thing FROM follows WHERE follower = :uid AND type = 3) THEN 'poster'
ELSE 'topic_id' END AS from_clause
FROM messages <..>
Another way :
SELECT m.*
, CASE WHEN t1.thing IS NULL THEN 'topic_id' ELSE `poster` END AS from_clause
FROM messages m
LEFT JOIN (SELECT thing FROM follows WHERE follower = :uid AND type = 3) t1 ON m.poster = t1.thing
LEFT JOIN (SELECT thing FROM follows WHERE follower = :uid AND type = 1) t2 ON m.topic_id = t2.thing
WHERE m.status = 1 AND (t1.thing IS NOT NULL OR t2.thing IS NOT NULL)

I want to combine multiple tables result count in one result using MySQl

I want to combine multiple tables result count in one result with column wise using MySql (see the result required) but i am confuse about this if you have any query or optimize way regarding this please answer me or helps are definitely appreciated also i was tried myself this Query with Union but seriously not success (see the Query Example)
Result required
post post_comment_likes post_comments post_likes
2 0 3 0
Query
SELECT COUNT(*) AS `post` FROM post WHERE user_id = "123456" UNION
SELECT COUNT(*) AS `post_comment_likes` FROM post_comment_likes WHERE user_id = "123456" UNION
SELECT COUNT(*) AS `post_comments` FROM post_comments WHERE user_id = "123456" UNION
SELECT COUNT(*) AS `post_likes` FROM post_likes WHERE user_id = "123456"
set #post = 0;
set #post_comment_likes = 0;
set #post_comments = 0;
Set #post_likes = 0;
select count(*) into #post from .......;
select count(*) into #post_comment_likes from ......;
select count(*) into #post_comments from ......;
select count(*) into #post_likes from ......;
select (#post + #post_comment_likes + #post_comments + #post_likes) ;
In the above code #post , #post_comment_likes , #post_comments , #post_likes are session variables , you prefix them with '#' character
Using the above code you have access to count of each table.
SELECT (SELECT COUNT(*)
FROM post
WHERE user_id = "123456") AS `post`
,(SELECT COUNT(*)
FROM post_comment_likes
WHERE user_id = "123456") AS `post_comment_likes`
,(SELECT COUNT(*)
FROM post_comments
WHERE user_id = "123456") AS `post_comments`
,(SELECT COUNT(*)
FROM post_likes
WHERE user_id = "123456") AS `post_likes`
You should replace COUNT(*) with COUNT(<some fieldname>) and could use a variable for the user id.
Please try the mysql query given below
SELECT
(SELECT COUNT(*) AS `post` FROM post WHERE user_id = "123456" ) AS post ,
(SELECT COUNT(*) AS `post_comment_likes` FROM post_comment_likes WHERE user_id ="123456") AS post_comment_likes,
(SELECT COUNT(*) AS `post_comments` FROM post_comments WHERE user_id = "123456") AS post_comments ,
(SELECT COUNT(*) AS `post_likes` FROM post_likes WHERE user_id = "123456" ) AS post_likes
thanks

MySQL Select by Count + Sum of values

I have the following query (Wordpress DB).
This will return data for the comment that has the most combined "up" and "down" ratings:
$comment_query = $wpdb->get_results("
SELECT wp_comments.*, wp_comment_rating.*, (wp_comment_rating.ck_rating_up+wp_comment_rating.ck_rating_down) AS pop_comment
FROM wp_comments, wp_comment_rating
WHERE wp_comments.comment_post_ID = $post->ID
AND wp_comments.comment_ID = wp_comment_rating.ck_comment_id
AND wp_comments.comment_approved = 1
ORDER BY pop_comment
DESC
LIMIT 1");
However, I'd also like to factor in comments that have the most replies by counting the number of matched "comment_parent" per comment, then adding that total to the "pop_comment" value I'm ordering by.
Essentially, I want to get the data for a comment with the most combined replies and up/down ratings.
Hope that makes sense...
You could subquery to get the counts by comment_parent
$comment_query = $wpdb->get_results("
SELECT wp_comments.*, wp_comment_rating.*, (wp_comment_rating.ck_rating_up+wp_comment_rating.ck_rating_down + (
select count(*) from wp_comments c2 where c2.comment_parent=wp_comments.comment_ID
)) AS pop_comment
FROM wp_comments, wp_comment_rating
WHERE wp_comments.comment_post_ID = $post->ID
AND wp_comments.comment_ID = wp_comment_rating.ck_comment_id
AND wp_comments.comment_approved = 1
ORDER BY pop_comment
DESC
LIMIT 1");
This should work
Essentially its just a sub query to get the total comments for the comment_parent and then joins that as SubQ / SubCount to the field
comment_query = $wpdb->get_results("
SELECT wp_comments.*, wp_comment_rating.*, (SubCount + pop_comment) AS total_rank, (wp_comment_rating.ck_rating_up+wp_comment_rating.ck_rating_down) AS pop_comment
JOIN (SELECT COUNT(*) as SubCount, comment_parent as Sub_ID FROM wp_comments GROUP BY comment_parent) as SubQ
ON wp_comments.comment_ID = SubQ.Sub_ID
FROM wp_comments, wp_comment_rating
WHERE wp_comments.comment_post_ID = $post->ID
AND wp_comments.comment_ID = wp_comment_rating.ck_comment_id
AND wp_comments.comment_approved = 1 ORDER BY total_rank DESC LIMIT 1");