mysqldatabasemariadbvbulletin

Use MySQL variable only for counting without returning to client in SELECT part


TL;DR

I use a MySQL variable that got incremented conditionally per row. This variable is only required for the HAVING clause, but by force also selected for incrementation.

Is it possible to increment the variable for each row without selecting it value back to the client?

Context with explanation and examples

The VBulletin forum software stores thread replys in a post table with a column visible. 0 means waiting for unlock, 1 visible and 2 soft deleted. I'm working on a MySQL query that fetches the posts of a page (typical 10). Users should only see posts with visible = 1 but moderators also the others.

First I want to filter based on usergroup. But this would make up my paging chaotic since a post could be on e.g. page 2 for guests, where it is on page 3 for moderators since deleted/not approved posts exists before this page.

For this reason, my concept is to select all post ids and limit only the ones to 10 per page where visible = 1. If the first page contains 10 visible posts and 2 deleted posts, then mods would get 12 posts and regular users only 10. But paging is the same for both, since deleted posts doesn't change it.

Inspirated from this question I build the following query:

SET @visible_sum = 0;

SELECT postid, visible, @visible_sum := @visible_sum + IF(visible = 1, 1, 0)
FROM post
WHERE threadid = 38325
GROUP BY postid
HAVING @visible_sum < 10
ORDER BY dateline;

enter image description here

As you can see, I get 10 non deleted posts and additionally 4 deleted ones (highlighted). With less modifications, this query can be re-used for non moderative users:

SELECT postid, visible, @visible_sum := @visible_sum + 1
...
HAVING @visible_sum < 10 AND visible = 1

enter image description here

So this generally works as required. But I don't like the fact that I always get the counter. Only post ids are used in my application, which means SELECT postid FROM posts ... would be enough. I don't know a way how it's possible to calculate the variable without using the SELECT part, which automatically results in a field of the returned rows to the client. I'm using MySQL, currently on MariaDB 10.1.


Solution

  • Move your query into a subquery.

    SELECT postid, visible
    FROM (
        SELECT postid, visible, @visible_sum := @visible_sum + IF(visible = 1, 1, 0)
        FROM post
        CROSS JOIN (SELECT @visible_sum := 0) AS vars
        WHERE threadid = 38325
        HAVING @visible_sum < 10
        ORDER BY dateline
    ) AS x
    

    You also shouldn't have GROUP BY postid when you don't have any aggregation functions.