I hate 4000+ adverts on a database. I use a FULLTEXT index on fields title, model and description.
In MySQL I change the value of ft_min_word_len from 4 to 3.
Actually, all the results are not matched.
Here is a simple request :
SELECT * ,
MATCH (
anno_modele, anno_titre, anno_desc
)
AGAINST (
"330"
) AS relevance
FROM (
`annonce`
JOIN possede
USING ( `anno_id` )
JOIN annonceur
USING ( `ann_id` )
JOIN cat_lang
USING ( `cat_id` )
JOIN lang_pays
USING ( `pays_id` )
JOIN marque
USING ( `mar_id` )
WHERE `mar_id` =867
AND MATCH (
anno_modele, anno_titre, anno_desc
)
AGAINST (
" 330"
)
AND `cat_id`
IN (
'3'
)
AND `anno_active` =1
AND `anno_mode` =1
AND `lang_pays`.`lang_id` = '3'
GROUP BY `anno_id`
ORDER BY `anno_prix` , `relevance` DESC
LIMIT 15
This matches me 3 results. 330 is just the field "anno_model".
If if do a like anno_modele LIKE '%330%', it matches me 9 results.
Here are the results matched by MATCH AGAINST :
Here are the results matched by LIKE
As you can see, when it exists a space ... the results are not matched by MACTH AGAINST
Is the problem on my request or it's something else ?
Help me please =)
Try using the * wildcard
...AGAINST ('*330*') ...
Related
I have the following code and I'm trying to group the messages
Here is a picture of database table and how the groups should be
and here is the SQL statement
SELECT a.* FROM `user_messages` `a`
JOIN (
SELECT `sender`, MAX(`id`) `last_id` FROM `user_messages` WHERE `receiver` = '1' GROUP BY `sender`
) `b`
ON `a`.`sender` = `b`.`sender` AND `a`.`id` = `b`.`last_id`
WHERE `a`.`receiver` = '1'
ORDER BY `id` DESC
OUTPUT:
I want to get somehow the last record where "receiver" is not my id, but "sender" is and name receiver column as "id" or something.
...so what i want is following result:
id | msg
13852 123
48 Hello!
17 321
Here is a fiddle: http://sqlfiddle.com/#!9/e06d57/3/0
To map my generic answer to your particular use case (using example 1):
SELECT receiver AS id, msg
FROM user_messages outerTable
WHERE NOT EXISTS
( SELECT *
FROM user_messages innerTable
WHERE innerTable.sender = outerTable.sender
AND innerTable.receiver = outerTable.receiver
AND innerTable.added > outerTable.added
)
AND sender = 1
This is a very common use case. There are several ways to write this code. Depending on the SQL engine used, they will be of different speeds.
I will use fairly generic column names. Tweak as needed.
SELECT common_id, msg
FROM myTable outerTable
WHERE NOT EXISTS
( SELECT *
FROM myTable innerTable
WHERE innerTable.common_id = outerTable.common_id
AND innerTable.time > outerTable.time
)
Please note that if there are two rows with identical common_id and time columns, then both will show up in the output. You can replace the > with >= to hide both of those rows.
The other common approach is kind of difficult to make sense of, but here goes. Notice the similarities to the NOT EXISTS approach.
SELECT outerTable.common_id, outerTable.msg
FROM myTable outerTable
LEFT JOIN myTable innerTable
ON innerTable.common_id = outerTable.common_id
AND innerTable.time > outerTable.time
WHERE innerTable.common_id IS NULL
According to your description, you seem to want something like this:
select um.receiver as id, um.msg
from user_messages um
where um.sender = 1 and
um.id = (select max(um2.id)
from user_messages um2
where um2.msg = um.msg and um2.receiver <> 1 and um.sender = 1
);
It doesn't produce the desired output, but that is because the output is inconsistent with the text description.
I'm using a query various IN() clauses to get the price of product combinations. I am actually correctly getting the prices, so thats OK. But I also need some other ID's to identify to which ID's the prices belong.
As you can see IN's, they all start with a different bundle_variant_id's but the rest of the bundle_variant_id's are the same. I want to return that first (or all) of those bundle_variant_id's in the result too, but using this query, i always get '1620' as bundle_variant_id. How can i get the first bundle_variant_id in those IN's (1616, 1655, 1677, etc) or ALL of the bundle_variant_id's?
It's not an option to remove the GROUP and the HAVING or any of the WHERE clauses.
SELECT `HardwareProductSubscriptionInstanceLink`.`subscription_instance_id`
,`BundleVariantLink`.`bundle_variant_id`
,`HardwareProductSubscriptionInstanceLink`.`price`
FROM `wax`.`prd_providers` AS `Provider`
INNER JOIN `wax`.`prd_subscription_types` AS `SubscriptionType` ON (`SubscriptionType`.`provider_id` = `Provider`.`id`)
INNER JOIN `wax`.`prd_subscriptions` AS `Subscription` ON (`Subscription`.`subscription_type_id` = `SubscriptionType`.`id`)
INNER JOIN `wax`.`prd_subscription_instances` AS `SubscriptionInstance` ON (`SubscriptionInstance`.`subscription_id` = `Subscription`.`id`)
INNER JOIN `wax`.`prd_bundle_variants_subscription_instances` AS `BundleVariantLink` ON (`BundleVariantLink`.`subscription_instance_id` = `SubscriptionInstance`.`id`)
INNER JOIN `wax`.`prd_hardware_products_subscription_instances` AS `HardwareProductSubscriptionInstanceLink` ON (
`HardwareProductSubscriptionInstanceLink`.`subscription_instance_id` = `SubscriptionInstance`.`id`
AND `HardwareProductSubscriptionInstanceLink`.`hardware_product_id` = 317
)
WHERE (
(
`BundleVariantLink`.`bundle_variant_id` IN (
'1616'
,'1618'
,'1600'
,'1620'
)
)
OR (
`BundleVariantLink`.`bundle_variant_id` IN (
'1655'
,'1618'
,'1600'
,'1620'
)
)
OR (
`BundleVariantLink`.`bundle_variant_id` IN (
'1677'
,'1618'
,'1600'
,'1620'
)
)
OR (
`BundleVariantLink`.`bundle_variant_id` IN (
'1691'
,'1618'
,'1600'
,'1620'
)
)
AND `SubscriptionInstance`.`number_of_bundle_variants` = 4
AND (
(`Provider`.`enabled` = '1')
AND (`Provider`.`visible` = '1')
)
GROUP BY `SubscriptionInstance`.`id`
HAVING count(`BundleVariantLink`.`bundle_variant_id`) = 4
Current results:
(column 1 = subscription_instance_id, 2=bundle_variant_id,3=price)
9213 1620 331.405
9214 1620 311.57
9215 1620 291.736
9219 1620 390.909
Required results:
9213 1616 331.405
9214 1655 311.57
9215 1677 291.736
9219 1691 390.909
Or alternate required results:
9213 1616,1618,1600,1620 331.405
9214 1655,1618,1600,1620 311.57
9215 1677,1618,1600,1620 291.736
9219 1691,1618,1600,1620 390.909
I am confused here This first sql-
I have one entry in my cnt_content table with content_pk=5419441 and title=test wls-2
Now when I am running this sql 1-
SELECT
title,
content_pk
FROM
cnt_content c
WHERE
c.type not in (
'AMT', 'LPA', 'QUE'
)
AND c.private_flag = 'N'
AND c.searchable_flag = 'Y'
AND c.status in (
'PUB', 'NAP'
)
AND (
trim(c.title) LIKE 'test wls-2'
OR trim(c.special_keyword) LIKE 'test wls-2'
)
and not exists (
SELECT
1
FROM
cmd_content_metadata cmd
WHERE
cmd.content_pk=5419441
AND cmd.for_others='Y'
)
ORDER BY
c.last_modified_date desc;
it is giving result-content_pk=5419441 and title=test wls-2
But when I am running this sql 2-
SELECT
title,
content_pk
FROM
cnt_content c
WHERE
c.type not in (
'AMT', 'LPA', 'QUE'
)
AND c.private_flag = 'N'
AND c.searchable_flag = 'Y'
AND c.status in (
'PUB', 'NAP'
)
AND (
trim(c.title) LIKE 'test wls-2'
OR trim(c.special_keyword) LIKE 'test wls-2'
)
and not exists (
SELECT
1
FROM
cmd_content_metadata cmd
WHERE
cmd.content_pk=c.content_pk
AND cmd.for_others='Y'
)
ORDER BY
c.last_modified_date desc;
It is not giving any result. Anyone please explain.
Because in one you just giving specific value for content_pk as 5419441, while other one uses corelated query which means for each and every value of content_pk selected in outer query, you are checking for equality in your sub select query.
I have 4 tables:
Table talks
table talks_fan
table talks_follow
table talks_comments
What I'm trying to achieve is counting all comments, fans, followers for every single talk.
I came up with this so far.
All tables have talk_id and only in talks table is a primary key
SELECT
g. *,
COUNT( m.talk_id ) AS num_of_comments,
COUNT( f.talk_id ) AS num_of_followers
FROM
talks AS g
LEFT JOIN talks_comments AS m
USING ( talk_id )
LEFT JOIN talks_follow AS f
USING ( talk_id )
WHERE g.privacy = 'public'
GROUP BY g.talk_id
ORDER BY g.created_date DESC
LIMIT 30;
I also tried using this method
SELECT
t.*,
COUNT(b.talk_id) AS comments,
COUNT(bt.talk_id) AS followers
FROM
talks t
LEFT JOIN talks_follow bt
ON bt.talk_id = t.talk_id
LEFT JOIN talks_comments b
ON b.talk_id = t.talk_id
GROUP BY t.talk_id;
Both give me the same results ....?!
Update: Create Statements
CREATE TABLE IF NOT EXISTS `talks` (
`talk_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` mediumint(9) NOT NULL,
`title` varchar(255) NOT NULL,
`content` text NOT NULL,
`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`privacy` enum('public','private') NOT NULL DEFAULT 'private',
PRIMARY KEY (`talk_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;
CREATE TABLE IF NOT EXISTS `talks_comments` (
`comment_id` bigint(20) NOT NULL AUTO_INCREMENT,
`talk_id` bigint(20) NOT NULL,
`user_id` mediumint(9) NOT NULL,
`comment` text NOT NULL,
`date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`status` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`comment_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=8 ;
CREATE TABLE IF NOT EXISTS `talks_fan` (
`fan_id` bigint(20) NOT NULL AUTO_INCREMENT,
`talk_id` bigint(20) NOT NULL,
`user_id` bigint(20) NOT NULL,
`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`status` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`fan_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;
CREATE TABLE IF NOT EXISTS `talks_follow` (
`follow_id` bigint(20) NOT NULL AUTO_INCREMENT,
`talk_id` bigint(20) NOT NULL,
`user_id` mediumint(9) NOT NULL,
`date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`follow_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
The final query that works
SELECT t.* , COUNT( DISTINCT b.comment_id ) AS comments,
COUNT( DISTINCT bt.follow_id ) AS followers,
COUNT( DISTINCT c.fan_id ) AS fans
FROM talks t
LEFT JOIN talks_follow bt ON bt.talk_id = t.talk_id
LEFT JOIN talks_comments b ON b.talk_id = t.talk_id
LEFT JOIN talks_fan c ON c.talk_id = t.talk_id
WHERE t.privacy = 'public'
GROUP BY t.talk_id
ORDER BY t.created_date DESC
LIMIT 30
EDIT: Final answer to the whole issue...
I have modified the Query and created some code in PHP (Codeigniter) to solve my issue apone the reccomendation of #Bill Karwin
$sql="
SELECT t.*,
COUNT( DISTINCT b.comment_id ) AS comments,
COUNT( DISTINCT bt.follow_id ) AS followers,
COUNT( DISTINCT c.fan_id ) AS fans,
GROUP_CONCAT( DISTINCT c.user_id ) AS list_of_fans
FROM talks t
LEFT JOIN talks_follow bt ON bt.talk_id = t.talk_id
LEFT JOIN talks_comments b ON b.talk_id = t.talk_id
LEFT JOIN talks_fan c ON c.talk_id = t.talk_id
WHERE t.privacy = 'public'
GROUP BY t.talk_id
ORDER BY t.created_date DESC
LIMIT 30
";
$query = $this->db->query($sql);
if($query->num_rows() > 0)
{
$results = array();
foreach($query->result_array() AS $talk){
$fan_user_id = explode(",", $talk['list_of_fans']);
foreach($fan_user_id AS $user){
if($user == 1 /* this supposed to be user id or session*/){
$talk['list_of_fans'] = 'yes';
}
}
$follower_user_id = explode(",", $talk['list_of_follower']);
foreach($follower_user_id AS $user){
if($user == 1 /* this supposed to be user id or session*/){
$talk['list_of_follower'] = 'yes';
}
}
$results[] = array(
'talk_id' => $talk['talk_id'],
'user_id' => $talk['user_id'],
'title' => $talk['title'],
'created_date' => $talk['created_date'],
'comments' => $talk['comments'],
'followers' => $talk['followers'],
'fans' => $talk['fans'],
'list_of_fans' => $talk['list_of_fans'],
'list_of_follower' => $talk['list_of_follower']
);
}
}
I STILL BELIEVE IT COULD BE OPTIMIZED IN THE DB AND JUST USE THE RESULT...
Im thinking if there are 1000 follower and 2000 fans of every single TALK then the result will take much longer to load.. HOW IF YOUT MULTIPLY THE NO WITH 10. Or im mistaking hear...
EDIT: adding benchmark for the query test...
I have used codeigniter profiler to know how long it take for the query to finish excuting.
that been said i also start adding data in the tables gratually
the result as follows.
Testing the DB after answerting data into it
Query Results time
table Talks
---------------
table data 50 rows.
Time: 0.0173 seconds
Table Rows: 644 rows
Time: 0.0535 seconds
Table Rows: 1250 rows
Time: 0.0856 seconds
Adding data to other tables
--------------------------
Talks = 1250 rows
talks_follow = 4115
talks_fan = 10 rows
Time: 2.656 seconds
Adding data to other tables
--------------------------
Talks = 1250 rows
talks_follow = 4115
talks_fan = 10 rows
talks_comments = 3650 rows
Time: 10.156 seconds
After replacing LEFT JOIN with STRAIGHT_JOIN
Time: 6.675 seconds
It seems that its extremely heavy on the DB.....
NOW Im Going to another dilemma on how to enhance its performance
Edited: using #leonardo_assumpcao suggestion
After rebuilding the DB using #leonardo_assumpcao suggestion
for indexing few fields..........
Adding data to other tables
--------------------------
Talks = 6000 Rows
talks_follow = 10000 Rows
talks_fan = 10000 Rows
talks_comments = 10000 Rows
Time: 17.940 second
Is this normal for heavy data DB......?
I can say this is (at least) one of the coolest select statements I improved today.
SELECT STRAIGHT_JOIN
t.* ,
COUNT( DISTINCT b.comment_id ) AS comments,
COUNT( DISTINCT bt.follow_id ) AS followers,
COUNT( DISTINCT c.fan_id ) AS fans
FROM
(
SELECT * FROM talks
WHERE privacy = 'public'
ORDER BY created_date DESC
LIMIT 0, 30
) AS t
LEFT JOIN talks_follow bt ON (bt.talk_id = t.talk_id)
LEFT JOIN talks_comments b ON (b.talk_id = t.talk_id)
LEFT JOIN talks_fan c ON (c.talk_id = t.talk_id)
GROUP BY t.talk_id ;
But it seems to me that your problem resides on your tables; A first step to obtain efficient queries is to index every field involved on your desired joins.
I've made some modifications on the tables you shown above; You can see its code here (updated).
Quite interesting, isn't it? Since we're here, take also your ERR model:
First try it using MySQL test database. Hopefully it will solve your performance troubles.
(Forgive my english, it's my second language)
You can force this into one query like so:
SELECT COUNT(*) num, 'talks' item FROM talks
UNION
SELECT COUNT(*) num, 'talks_fan' item FROM talks_fan
UNION
SELECT COUNT(*) num, 'talks_follow' item FROM talks_follow
UNION
SELECT COUNT(*) num, 'talks_comment' item FROM talks_comment
This will give you a five row resultset with one row per table. Each row is the count in a particular table.
If you must get it all into a single row you can do a pivot like so.
SELECT
SUM( CASE item WHEN 'talks' THEN num ELSE 0 END ) AS 'talks',
SUM( CASE item WHEN 'talks_fan' THEN num ELSE 0 END ) AS 'talks_fan',
SUM( CASE item WHEN 'talks_follow' THEN num ELSE 0 END ) AS 'talks_follow',
SUM( CASE item WHEN 'talks_comment' THEN num ELSE 0 END ) AS 'talks_comment'
FROM
( SELECT COUNT(*) num, 'talks' item FROM talks
UNION
SELECT COUNT(*) num, 'talks_fan' item FROM talks_fan
UNION
SELECT COUNT(*) num, 'talks_follow' item FROM talks_follow
UNION
SELECT COUNT(*) num, 'talks_comment' item FROM talks_comment
) counts
(This doesn't take into account your WHERE g.privacy = clause because I don't understand that. But you could add a WHERE clause to one one of the four queries in the UNION item to handle that.)
Notice that this truly is four queries on four separate tables coerced into a single query.
And, by the way, there is no difference in value between COUNT(*) and COUNT(id) when id is the primary key of the table. COUNT(id) doesn't count the rows for which the id is NULL, but if id is the primary key, then it is NOT NULL. But COUNT(*) is faster, so use it.
Edit if you need the number of fan, follow, and comment rows for each distinct talk, do this. It's the same idea of doing a union and a pivot, but with an extra parameter.
SELECT
talk_id,
SUM( CASE item WHEN 'talks_fan' THEN num ELSE 0 END ) AS 'talks_fan',
SUM( CASE item WHEN 'talks_follow' THEN num ELSE 0 END ) AS 'talks_follow',
SUM( CASE item WHEN 'talks_comment' THEN num ELSE 0 END ) AS 'talks_comment'
FROM
(
SELECT talk_id, COUNT(*) num, 'talks_fan' item
FROM talks_fan
GROUP BY talk_id
UNION
SELECT talk_id, COUNT(*) num, 'talks_follow' item
FROM talks_follow
GROUP BY talk_id
UNION
SELECT talk_id, COUNT(*) num, 'talks_comment' item
FROM talks_comment
GROUP BY talk_id
) counts
GROUP BY talk_id
After doing this for (too) many years, I've discovered that the best way to describe a query you need is to say to yourself "I need a result set with one row for each xxx, with columns for yyy, zzz, and qqq."
The reason the counts are the same is that it's counting rows after the joins have combined the tables. By joining to multiple tables, you're creating a Cartesian product.
Basically, you're counting not only how many comments per talk, but how many comments * followers per talk. Then you count the followers as how many followers * comments per talk. Thus the counts are the same, and they're all way too high.
Here's a simpler way to write a query to count each distinct comment, follower, etc. only once:
SELECT t.*,
COUNT(DISTINCT b.comment_id) AS comments,
COUNT(DISTINCT bt.follow_id) AS followers
FROM talks t
LEFT JOIN talks_follow bt ON bt.talk_id = t.talk_id
LEFT JOIN talks_comments b ON b.talk_id = t.talk_id
GROUP BY t.talk_id;
Re your comment: I wouldn't fetch all the followers in the same query. You could do it this way:
SELECT t.*,
COUNT(DISTINCT b.comment_id) AS comments,
COUNT(DISTINCT bt.follow_id) AS followers,
GROUP_CONCAT(DISTINCT bt.follower_name) AS list_of_followers
FROM talks t
LEFT JOIN talks_follow bt ON bt.talk_id = t.talk_id
LEFT JOIN talks_comments b ON b.talk_id = t.talk_id
GROUP BY t.talk_id;
But what you'd get back is a single string with the follower names separated by commas. Now you have to write application code to split the string on commas, you have to worry if some follower names actually contain commas already, and so on.
I'd do a second query, fetching the followers for a given talk. It's likely you want to display the followers only for a specific talk anyway.
SELECT follower_name
FROM talks_follow
WHERE talk_id = ?
Query :
(
SELECT
upd.uid,
upd.update_id,
upd.update,
upd.date,
upd.type,
upd.total_likes,
upd.total_comments,
upd.deleted,
usr.username AS `username`,
usr.profile_picture AS `profile_picture`
,(
SELECT
COUNT(lik.id)
FROM
likes as lik
WHERE
upd.update_id = lik.item_id
AND
lik.uid = 118697835834
AND lik.type=0
) as liked_update,
(
SELECT
COUNT(fav.id)
FROM
favorites as fav
WHERE
upd.update_id = fav.item_id
AND
fav.uid = 118697835834
AND fav.type=0
) as favorited_update
FROM
updates AS upd
LEFT JOIN
users AS usr
ON upd.uid = usr.uid
WHERE
upd.deleted=0
AND
(
upd.uid=118697835834
OR EXISTS
(
SELECT *
FROM
subscribers AS sub
WHERE
upd.uid = sub.suid
AND sub.uid = 118697835834
)
)
)
UNION
(
SELECT
topic.uid,
topic.tid,
topic.title,
topic.body,
topic.total_likes,
topic.total_replies,
topic.views,
topic.date,
usr.username AS `username`,
usr.profile_picture AS `profile_picture`
,(
SELECT
COUNT(lik.id)
FROM
likes as lik
WHERE
topic.update_id = lik.item_id
AND
lik.uid = 118697835834
AND lik.type=1
) as liked_update,
(
SELECT
COUNT(fav.id)
FROM
favorites as fav
WHERE
topic.update_id = fav.item_id
AND
fav.uid = 118697835834
AND fav.type=1
) as favorited_update
FROM
topics AS topic
LEFT JOIN
users AS usr
ON topic.uid = usr.uid
WHERE
topic.deleted=0
AND
(
topic.uid=118697835834
OR EXISTS
(
SELECT *
FROM
subscribers AS sub
WHERE
topic.uid = sub.suid
AND sub.uid = 118697835834
)
)
)
ORDER BY date DESC
I have added the UNION ( SELECT ) and the query takes forever to load and finally it stops returning a blank page...
removing UNION ( SELECT ) works fine...
OK after all the comments can you please say what changes you made to get the script working.
In light of your comment about the data from two tables being in the same columns that is because you have told the engine to do that by using UNION. If you want them in seperate columns you will need to place Nulls in between:
SELECT
upd.uid,
upd.update_id,
upd.update,
upd.date,
upd.type,
upd.total_likes,
upd.total_comments,
upd.deleted,
null AS `topicuid`,
null AS `topictid`,
null AS `topictitle`,
null AS `topicbody`,
null AS `topictotal_likes`,
null AS `topictotal_replies`,
null AS `topicviews`,
null AS `topicdate`,
usr.username AS `username`,
usr.profile_picture AS `profile_picture`,
(SELECT COUNT(lik.id) FROM likes as lik WHERE upd.update_id = lik.item_id AND lik.uid = 118697835834 AND lik.type=0) as liked_update,
(SELECT COUNT(fav.id) FROM favorites as fav WHERE upd.update_id = fav.item_id AND fav.uid = 118697835834 AND fav.type=0) as favorited_update
FROM
......
UNION ALL
SELECT
null AS `upd.uid`,
null AS `upd.update_id`,
null AS `upd.update`,
null AS `upd.date`,
null AS `upd.type`,
null AS `upd.total_likes`,
null AS `upd.total_comments`,
null AS `upd.deleted`,
topic.uid,
topic.tid,
topic.title,
topic.body,
topic.total_likes,
topic.total_replies,
topic.views,
topic.date,
usr.username AS `username`,
usr.profile_picture AS `profile_picture`,
(SELECT COUNT(lik.id) FROM likes as lik WHERE topic.update_id = lik.item_id AND lik.uid = 118697835834 AND lik.type=1) as liked_update,
(SELECT COUNT(fav.id) FROM favorites as fav WHERE topic.update_id = fav.item_id AND fav.uid = 118697835834 AND fav.type=1) as favorited_update
You might need to do a bit more work on the column names but you should get there. You should read up on what the UNION operator actually does to two or more queries.
When you use UNION you have to have exact same results "column format, names,..." so you have at top of query upd.total_comments as total_comments, and bottom you have topic.total_replies as total_replies those are different names. hope you understand what i try to explain, if not visit here where it explains better.