How to write a SQL request in less code? - mysql

I have a code like this:
SELECT
`cabinet`.`name_test`,
`answers`.`answer_id`,
(
SELECT `answer_id`
FROM `answers`
WHERE `user_id` = '353281' AND `answers`.`test_id` = `cabinet`.`test_id`
) as answer_2
FROM `cabinet`
INNER JOIN `answers`
WHERE
`user_id` = '184918649'
AND `friend_id` = '353281'
AND `answers`.`test_id` = `cabinet`.`test_id`
How not to write twice: answers.test_id = cabinet.test_id?

It is not really less code, but you can also do this by joining on the answers table twice:
SELECT
c.`name_test`,
a1.`answer_id` answer_1,
a2.`answer_id` answer_2
FROM `cabinet` c
INNER JOIN `answers` a1
ON c.`test_id` = a1.`test_id`
AND a1.`user_id` = '184918649'
AND `friend_id` = '353281'
INNER JOIN `answers` a2
ON c.`test_id` = a2.`test_id`
AND a2.`user_id` = '353281'
Or you can use subqueries:
SELECT
c.`name_test`,
a1.`answer_id` answer_1,
a2.`answer_id` answer_2
FROM `cabinet` c
INNER JOIN
(
select `answer_id`
from `answers`
where `user_id` = '184918649'
AND `friend_id` = '353281'
) a1
ON c.`test_id` = a1.`test_id`
INNER JOIN
(
select `answer_id`
from `answers`
where `user_id` = '353281'
) a2
ON c.`test_id` = a2.`test_id`;

you are missing ON clause in your sql
try this
SELECT
`cabinet`.`name_test`,
`answers`.`answer_id`,
(
SELECT `answer_id`
FROM `answers`
WHERE `user_id` = '353281' AND `answers`.`test_id` = `cabinet`.`test_id`
) as answer_2
FROM `cabinet`
INNER JOIN `answers` on `answers`.`test_id` = `cabinet`.`test_id`
WHERE
`user_id` = '184918649'
AND `friend_id` = '353281'
removed the last line which is double

Related

How to optimize subquery in select clause in mysql?

I have a subquery in select clause, like this
SELECT
`s`.`id` AS `id`,
`s`.`unit_id` AS `unit_id`,
`m`.`description` AS `description`,
`s`.`lot_no` AS `lot_no`,
(
(
(
SELECT COALESCE(SUM(`payment_amt`),0) AS `jmlh`
FROM `sb_ar_bill_sch`
WHERE `unit_id` = `s`.`unit_id` AND `lot_no` = `s`.`lot_no` AND `project_no` = `s`.`project_no` AND `debtor_acct` = `s`.`debtor_acct`
AND `bill_type` = 'S'
)
/
`s`.`sell_price`
)
*
100
) AS `persen_paid`
FROM `p_sis_rl_sales` `s`
JOIN `p_sis_pl_project` `p` ON `s`.`unit_id` = `p`.`unit_id` AND `s`.`project_no` = `p`.`project_no`
JOIN `p_sis_pm_lot` `l` ON `s`.`unit_id` = `l`.`unit_id` AND `s`.`project_no` = `l`.`project_no` AND `s`.`lot_no` = `l`.`lot_no`
JOIN `p_common_businessunit` `m` ON `s`.`unit_id` = `m`.`unit_id`
JOIN `v_la_lastowner` `o` ON `s`.`unit_id` = `o`.`unit_id` AND `s`.`project_no` = `o`.`project_no` AND `s`.`lot_no` = `o`.`lot_no`
WHERE
(
`s`.`contract_no` IS NOT NULL
AND
(
(
(
SELECT COALESCE(SUM(`payment_amt`),0) AS `jmlh`
FROM `sb_ar_bill_sch`
WHERE `unit_id` = `s`.`unit_id` AND `lot_no` = `s`.`lot_no` AND `project_no` = `s`.`project_no` AND `debtor_acct` = `s`.`debtor_acct`
AND `bill_type` = 'S'
)
/ `s`.`sell_price`
)
*
100
)
>=
100
)
ORDER BY `s`.`sales_date` DESC
I already indexed the table that I used.
Do I need to process hundreds of thousands of rows in one table?
The Query above takes a long time. How can the query above be optimized?

MySQL Invalid Use of Group Function

I'm getting Error Code: 1111. Invalid use of group function when trying to build a query in MySQL. Apparently MySQL doesn't support WITH, which is what I'm more comfortable using.
SELECT DISTINCT `UserID`
FROM `user`
INNER JOIN `message`
ON `user`.`Message` = `message`.`Recipient`
WHERE MAX(`TotalSize`) IN (
SELECT SUM(`message`.`Size`) as `TotalSize`
FROM `message`
INNER JOIN `category`
ON `message`.`CatID` = `category`.`CatID`
WHERE `category`.`CatName` = 'Inbox'
GROUP BY `Recipient`);
SELECT `UserID`, MAX(SUM(message.Size)) as TotalSize
FROM `user`
INNER JOIN `message`
ON `user`.`Message` = `message`.`Recipient`
INNER JOIN category
ON message.CatID = category.CatID
WHERE category.CatName = 'Inbox'
GROUP BY UserID
You need to use HAVING clause instead of WHERE MAX(TotalSize)
SELECT DISTINCT `UserID`
FROM `user`
INNER JOIN `message`
ON `user`.`Message` = `message`.`Recipient`
GROUP BY `UserID`
HAVING MAX(`message`.`Size`) IN (
SELECT SUM(`message`.`Size`) as `TotalSize`
FROM `message`
INNER JOIN `category`
ON `message`.`CatID` = `category`.`CatID`
WHERE `category`.`CatName` = 'Inbox'
GROUP BY `Recipient`);
Group functions are not accessible in WHERE clause , HAVING can filter on aggregates.

how to build nested select on zend db

Hi i have trouble with this query
SELECT * FROM(
SELECT `b`.*,`owner`.firstname,`owner`.lastname,`owner`.email,
(
SELECT COUNT(`ps`.profile_id) FROM `profile` AS `ps`
LEFT JOIN `xref_store_profile_brand` AS `xbp` ON `xbp`.profile_id = `ps`.profile_id
WHERE `xbp`.brand_id = b.brand_id AND ps.role = 'salesrep' AND `xbp`.store_id IS NULL
) AS `salesrepTotal`,
(
SELECT GROUP_CONCAT(`ms`.firstname) FROM `profile` AS `ps`
LEFT JOIN `xref_store_profile_brand` AS `xbp` ON `xbp`.profile_id = `ps`.profile_id
LEFT JOIN `member` AS `ms`ON `ms`.member_id = `ps`.member_id
WHERE `xbp`.brand_id = `b`.brand_id AND ps.role = 'salesrep' AND `xbp`.store_id IS NULL
) AS `salesrep`,
(
SELECT COUNT(`s`.store_id) FROM `store` AS `s`
LEFT JOIN `xref_store_profile_brand` AS `xbs` ON `xbs`.store_id = `s`.store_id
WHERE `xbs`.brand_id = `b`.brand_id AND `xbs`.brand_id IS NOT NULL
) AS `storeTotal`,
(
SELECT GROUP_CONCAT(`s`.name) FROM `store` AS `s`
LEFT JOIN `xref_store_profile_brand` AS `xbs` ON `xbs`.store_id = `s`.store_id
WHERE `xbs`.brand_id = `b`.brand_id AND `xbs`.brand_id IS NOT NULL
) AS `store`
FROM `brand` AS `b`
LEFT JOIN
(
SELECT `m`.firstname,`m`.lastname,`m`.email,`xspb`.brand_id FROM `member` AS `m`
LEFT JOIN `profile` as `p` ON `p`.member_id = `m`.member_id AND `p`.role = 'designer' AND `p`.isPrimary = 1
LEFT JOIN `xref_store_profile_brand` AS `xspb` ON `xspb`.profile_id = `p`.profile_id AND `xspb`.store_id IS NULL
) AS `owner` ON `owner`.brand_id =`b`.brand_id
GROUP BY `b`.brand_id
) AS `final`
how can i convert this in to Zend_Db_Select object?
Th main problem is
this part
SELECT `b`.*,`owner`.firstname,`owner`.lastname,`owner`.email,
(
SELECT COUNT(`ps`.profile_id) FROM `profile` AS `ps`
LEFT JOIN `xref_store_profile_brand` AS `xbp` ON `xbp`.profile_id = `ps`.profile_id
WHERE `xbp`.brand_id = b.brand_id AND ps.role = 'salesrep' AND `xbp`.store_id IS NULL
) AS `salesrepTotal`,
You need to use Zend_Db_Expr objects in your query and array structures for select AS.
below is the solution you are looking for:
<?php
$db = Zend_Db_Table::getDefaultAdapter();
// inner query
$sqlSalesRepTotal = $db->select()
->from(array('ps' => 'profile'))
->joinLeft(array('xbp' => 'xref_store_profile_brand'), 'xbp.profile_id = ps.profile_id')
->where('xbp.brand_id = b.brand_id')
->where('ps.role = ?', 'salesrep')
->where('xbp.store_id IS NULL');
// main query
$sql = $db->select()
->from(array('b' => 'brand'), array(
// NOTE: have to add parentesis around the expression
'salesrepTotal' => new Zend_Db_Expr("($sqlSalesRepTotal)")
))
->where('....')
->group('brand_id');
// debug
var_dump($db->fetchAll($sql));

left join makes 0 results instead of empty rows

Here is big sql query and it works
select * from (SELECT DISTINCT `t`.*
FROM `wp_pods_bars` AS `t` LEFT JOIN `wp_podsrel` AS `rel_city`
ON ( `rel_city`.`field_id` = 13918 AND `rel_city`.`item_id` = `t`.`id` )
LEFT JOIN `wp_pods_city` AS `city`
ON ( `rel_city`.`field_id` = 13918 AND `city`.`id` = `rel_city`.`related_item_id` )
LEFT JOIN `wp_podsrel` AS `rel_goodfor_what`
ON ( `rel_goodfor_what`.`field_id` = 13912 AND `rel_goodfor_what`.`item_id` = `t`.`id` )
LEFT JOIN `wp_pods_goodfor` AS `goodfor_what`
ON ( `rel_goodfor_what`.`field_id` = 13912 AND `goodfor_what`.`id` = `rel_goodfor_what`.`related_item_id` )
LEFT JOIN `wp_podsrel` AS `rel_goodfor_who`
ON `rel_goodfor_who`.`field_id` = 13911 AND `rel_goodfor_who`.`item_id` = `t`.`id`
LEFT JOIN `wp_pods_goodfor_who` AS `goodfor_who`
ON `rel_goodfor_who`.`field_id` = 13911 AND `goodfor_who`.`id` = `rel_goodfor_who`.`related_item_id`
LEFT JOIN `wp_podsrel` AS `rel_goodfor_when`
ON `rel_goodfor_when`.`field_id` = 13913 AND `rel_goodfor_when`.`item_id` = `t`.`id`
LEFT JOIN `wp_pods_goodfor_when` AS `goodfor_when` ON `rel_goodfor_when`.`field_id` = 13913
AND `goodfor_when`.`id` = `rel_goodfor_when`.`related_item_id`
WHERE hide=0 AND opening_soon=0 AND ( `city`.`name` = "London" ) AND `goodfor_when`.`name` IN ('Late') GROUP BY name HAVING COUNT(DISTINCT `goodfor_when`.`name`) = 1
ORDER BY `t`.`name`, `t`.`id`
) as foo
LEFT JOIN `wp_podsrel` AS `pr`
ON `field_id` = 13905 AND `item_id` = foo.id
and returns 144 results. Now I add one more left join and no results (See in the bottom)
select * from (SELECT DISTINCT `t`.*
FROM `wp_pods_bars` AS `t` LEFT JOIN `wp_podsrel` AS `rel_city`
ON ( `rel_city`.`field_id` = 13918 AND `rel_city`.`item_id` = `t`.`id` )
LEFT JOIN `wp_pods_city` AS `city`
ON ( `rel_city`.`field_id` = 13918 AND `city`.`id` = `rel_city`.`related_item_id` )
LEFT JOIN `wp_podsrel` AS `rel_goodfor_what`
ON ( `rel_goodfor_what`.`field_id` = 13912 AND `rel_goodfor_what`.`item_id` = `t`.`id` )
LEFT JOIN `wp_pods_goodfor` AS `goodfor_what`
ON ( `rel_goodfor_what`.`field_id` = 13912 AND `goodfor_what`.`id` = `rel_goodfor_what`.`related_item_id` )
LEFT JOIN `wp_podsrel` AS `rel_goodfor_who`
ON `rel_goodfor_who`.`field_id` = 13911 AND `rel_goodfor_who`.`item_id` = `t`.`id`
LEFT JOIN `wp_pods_goodfor_who` AS `goodfor_who`
ON `rel_goodfor_who`.`field_id` = 13911 AND `goodfor_who`.`id` = `rel_goodfor_who`.`related_item_id`
LEFT JOIN `wp_podsrel` AS `rel_goodfor_when`
ON `rel_goodfor_when`.`field_id` = 13913 AND `rel_goodfor_when`.`item_id` = `t`.`id`
LEFT JOIN `wp_pods_goodfor_when` AS `goodfor_when` ON `rel_goodfor_when`.`field_id` = 13913
AND `goodfor_when`.`id` = `rel_goodfor_when`.`related_item_id`
WHERE hide=0 AND opening_soon=0 AND ( `city`.`name` = "London" ) AND `goodfor_when`.`name` IN ('Late') GROUP BY name HAVING COUNT(DISTINCT `goodfor_when`.`name`) = 1
ORDER BY `t`.`name`, `t`.`id`
) as foo
LEFT JOIN `wp_podsrel` AS `pr`
ON `field_id` = 13905 AND `item_id` = foo.id
LEFT JOIN `wp_posts`
ON `pr`.related_item_id = `wp_posts`.`ID`
So now this query returns 0 results. I suppose it should add just empty rows if no match found? Here is wp_podsrel structure
`wp_podsrel` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`pod_id` int(10) unsigned DEFAULT NULL,
`field_id` int(10) unsigned DEFAULT NULL,
`item_id` bigint(20) unsigned DEFAULT NULL,
`related_pod_id` int(10) unsigned DEFAULT NULL,
`related_field_id` int(10) unsigned DEFAULT NULL,
`related_item_id` bigint(20) unsigned DEFAULT NULL,
`weight` smallint(5) unsigned DEFAULT '0',
PRIMARY KEY (`id`),
KEY `field_item_idx` (`field_id`,`item_id`),
KEY `rel_field_rel_item_idx` (`related_field_id`,`related_item_id`),
KEY `field_rel_item_idx` (`field_id`,`related_item_id`),
KEY `rel_field_item_idx` (`related_field_id`,`item_id`)
)

Combining multiple queries in MySQL

This is a bit of a long-winded question, and I apologize for that. My SQL skills are severely lacking (something I'd like to redress ASAP). As a result, I really cannot fathom how I can tackle this problem that I have run into.
Basically, our project is storing user notifications in a single table notifications. The table structure looks like this:
+-----------+-----------+----------------+------------+
| user_id | subject | action | date |
+-----------+-----------+----------------+------------+
| 1 | 2 | started_follow | 1371034287 |
| 1 | 2 | stopped_follow | 1371034287 |
| 2 | 5 | added_item | 1371034287 |
+-----------+-----------+----------------+------------+
user_id always contains the ID of the user that performed the action, and date is obviously the date that the notification was registered. The tricky part is that subject is a reference to an ID of another table, and that table is largely dependent upon the value of the action column.
So for example, in the first two records of the sample data, subject is a reference to an ID in the users table (i.e. the user who was followed, and then unfollowed). In the third record, subject is a reference to an ID in the items table.
We also need to perform several JOIN statements, depending upon the condition of action. So, if it's added_item for example, we need to JOIN several other tables (to check for settings and other requirements).
I came across a legacy function in the code which essentially checks to see how many notifications exist in the table for a given user since a specified date. The previous developer has simply used a series of queries, and then returned the total number of several SELECT COUNT(*) statements as follows (please note, this is all inside the PHP User class):
// Get the number of notifications since the specified time (or of all time):
public function countNotifications($since = '')
{
$sinceString = ($since == '') ? '' : "AND `date` > '$since'";
// Notifications when someone follows $this:
$started_following = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
WHERE `action` = 'started_following'
AND `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when someone stops following $this:
$stopped_following = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
WHERE `action` = 'stopped_following'
AND `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when someone sends $this a message:
$sent_message = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
WHERE `action` = 'sent_message'
AND `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when someone favorites $this' items:
$favorited_item = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
WHERE `notifications`.`action` = 'favorited_item'
AND `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when someone adds a comment to $this' items:
$comments = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
WHERE `notifications`.`action` = 'added_comment'
AND `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when a follower of $this adds a new item:
$new_items = $this->_database->query("SELECT COUNT(*) AS `total`
FROM `notifications`
INNER JOIN `categories` ON `notifications`.`subject` = `categories`.`id`
INNER JOIN (SELECT `followee` FROM `user_followers` WHERE `follower` = '{$this->id}') `followers`
WHERE `notifications`.`action` = 'added_item'
AND `followee` = `user_id`
$sinceString
AND `user_id` != '{$this->id}'")->fetchObject();
// Notifications when a follower of $this adds a new collection:
$new_collections = $this->_database->query("SELECT COUNT(*) AS `total`
FROM `notifications`
INNER JOIN `categories` ON `notifications`.`subject` = `categories`.`id`
INNER JOIN (SELECT `followee` FROM `user_followers` WHERE `follower` = '{$this->id}') `followers`
WHERE `notifications`.`action` = 'added-collection'
AND `followee` = `user_id`
$sinceString
AND `user_id` != '{$this->id}'")->fetchObject();
// Notifications when a follower of $this adds a new category:
$new_categories = $this->_database->query("SELECT COUNT(*) AS `total`
FROM `notifications`
INNER JOIN `categories` ON `notifications`.`subject` = `categories`.`id`
INNER JOIN (SELECT `followee` FROM `user_followers` WHERE `follower` = '{$this->id}') `followers`
WHERE `notifications`.`action` = 'added-category'
AND `followee` = `user_id`
$sinceString
AND `user_id` != '{$this->id}'")->fetchObject();
// Selling Notifications:
// Notifications when someone makes an offer for an item $this is selling:
$offers = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
WHERE `notifications`.`action` = 'made_offer'
AND `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when someone purchases an item $this is selling:
$purchases = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
INNER JOIN (SELECT COUNT(*) AS `count`, `item_id`
FROM `user_favorite_items`
WHERE `user_id` = '{$this->id}') `following` ON `items`.`id` = `following`.`item_id`
WHERE `notifications`.`action` = 'bought_item'
AND `following`.`count` = 1
AND `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when an item that $this favorited is listed for sale:
$item_sales = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN (SELECT COUNT(*) AS `count`, `item_id`
FROM `user_favorite_items`
WHERE `user_id` = '{$this->id}'
) `following` ON `items`.`id` = `following`.`item_id`
WHERE `notifications`.`action` = 'selling_item'
AND `following`.`count` = 1
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Return the counts:
return ($started_following->count +
$stopped_following->count +
$sent_message->count +
$favorited_item->count +
$comments->count +
$new_items->count +
$new_collections->count +
$new_categories->count +
$offers->count +
$purchases->count +
$item_sales->count);
}
While this does the job perfectly well, it makes it extremely difficult to fetch all records from a specified date, for example, or all records that relate to a specific User ID.
I suppose my question really is what is the best way to combine the numerous SQL statements provided? I have experimented with LEFT JOIN, but as you can see we need to join the table to a different column, depending upon the value of notifications.action. While I can do this using table aliases, it does tend to return a lot of redundant data.
Essentially, I'd like to combine the COUNT(*) queries given above so that we can simply return all notifications.* for a given User ID and / or time period.
I'd also like to avoid using UNION if at all possible (for obvious reasons).
Sorry for the lengthy question, but I've tried to make everything as clear as possible. Before anyone asks, I'm unable to change the structure of the data or the DB schema, as this is for an existing site.
I have put together an SQLFiddle to make things a little more clear.
Those queries vary in complexity and what they are doing.
The first 3 could be combined into a single query returning (up to) 3 rows:-
SELECT action, COUNT(*) AS `count`
FROM `notifications`
WHERE `action` IN ( 'started_following', 'stopped_following', 'sent_message')
AND `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'
GROUP BY action
To force that to return 3 rows you could possibly do something like this:-
SELECT WantedActions.WantedAction, COUNT(*) AS `count`
FROM (SELECT 'started_following' AS WantedAction UNION SELECT 'stopped_following' UNION SELECT 'sent_message') AS WantedActions
LEFT OUTER JOIN `notifications`
ON WantedActions.WantedAction = notifications.action
WHERE `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'
GROUP BY WantedActions.WantedAction
You can probably do similar things for others
EDIT
SELECT started_following, stopped_following, sent_message, favorited_item, comments, new_items, new_collections, new_categories, offers, purchases, item_sales
FROM (SELECT SUM(IF(`action` = 'started_following', 1, 0) AS started_following,
SUM(IF(`action` = 'stopped_following', 1, 0) AS stopped_following,
SUM(IF(`action` = 'sent_message', 1, 0) AS sent_message
FROM `notifications`
WHERE `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}') Sub1
CROSS JOIN (SELECT SUM(IF(`action` = 'favorited_item', 1, 0) AS favorited_item,
SUM(IF(`action` = 'added_comment', 1, 0) AS comments,
SUM(IF(`action` = 'made_offer', 1, 0) AS offers
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
WHERE `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}') Sub2
CROSS JOIN (SELECT SUM(IF(`action` = 'added_item', 1, 0) AS new_items,
SUM(IF(`action` = 'added-collection', 1, 0) AS new_collections,
SUM(IF(`action` = 'added-category', 1, 0) AS new_categories
FROM `notifications`
INNER JOIN `categories` ON `notifications`.`subject` = `categories`.`id`
INNER JOIN (SELECT `followee` FROM `user_followers` WHERE `follower` = '{$this->id}') `followers`
WHERE `followee` = `user_id`
$sinceString
AND `user_id` != '{$this->id}') Sub3
CROSS JOIN (SELECT COUNT(*) AS purchases
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
INNER JOIN (SELECT COUNT(*) AS `count`, `item_id`
FROM `user_favorite_items`
WHERE `user_id` = '{$this->id}'
) `following` ON `items`.`id` = `following`.`item_id`
WHERE `notifications`.`action` = 'bought_item'
AND `following`.`count` = 1
AND `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}') Sub4
CROSS JOIN (SELECT COUNT(*) AS item_sales
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN (SELECT COUNT(*) AS `count`, `item_id`
FROM `user_favorite_items`
WHERE `user_id` = '{$this->id}'
) `following` ON `items`.`id` = `following`.`item_id`
WHERE `notifications`.`action` = 'selling_item'
AND `following`.`count` = 1
$sinceString
AND `notifications`.`user_id` != '{$this->id}') Sub5
EDIT - Using a union
SELECT action, COUNT(*) AS action_count
FROM `notifications`
WHERE `subject` = '{$this->id}'
AND action IN ('started_following', 'stopped_following', 'sent_message')
$sinceString
AND `notifications`.`user_id` != '{$this->id}'
GROUP BY action
UNION
SELECT action, COUNT(*) AS action_count
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
WHERE `categories`.`owner` = '{$this->id}'
AND action IN ('favorited_item', 'added_comment', 'made_offer')
$sinceString
AND `notifications`.`user_id` != '{$this->id}'
GROUP BY action
UNION
SELECT action, COUNT(*) AS action_count
FROM `notifications`
INNER JOIN `categories` ON `notifications`.`subject` = `categories`.`id`
INNER JOIN (SELECT `followee` FROM `user_followers` WHERE `follower` = '{$this->id}') `followers`
WHERE `followee` = `user_id`
AND action IN ('added_item', 'added-collection', 'added-category')
$sinceString
AND `user_id` != '{$this->id}'
GROUP BY action
UNION
SELECT 'purchases' AS action, COUNT(*) AS action_count
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
INNER JOIN (SELECT user_id, COUNT(*) AS `count`, `item_id`
FROM `user_favorite_items`
GROUP BY `user_id`, item_id
) `following` ON `items`.`id` = `following`.`item_id` AND `notifications`.`user_id` = `following`.`user_id`
WHERE `notifications`.`action` = 'bought_item'
AND `following`.`count` = 1
AND `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'
UNION
SELECT 'item_sales' AS action, COUNT(*) AS action_count
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN (SELECT user_id, COUNT(*) AS `count`, `item_id`
FROM `user_favorite_items`
GROUP BY `user_id`, item_id
) `following` ON `items`.`id` = `following`.`item_id` AND `notifications`.`user_id` = `following`.`user_id`
WHERE `notifications`.`action` = 'selling_item'
AND `following`.`count` = 1
$sinceString
AND `notifications`.`user_id` != '{$this->id}'