Reputation: 79
I have a table storing the usage count of topics used, for each subsequent request increases the usage count. I have added a query to return the least used topic.
SELECT b.body, n.nid
FROM node n
LEFT JOIN body b ON n.nid = b.entity_id
LEFT JOIN topic_usage u ON n.nid = u.entity_id
LEFT JOIN reference r ON n.nid = r.entity_id
AND (
r.entity_type = 'node'
AND
r.deleted = '0'
)
WHERE n.type = :type
AND n.status = 1
AND r.target_id= :id
ORDER BY u.field_topic_usage_value ASC LIMIT 0,1
Example table
nid | Usage Count
-----------------
1 | 0
2 | 0
3 | 0
4 | 1
The above query works fine to return the lowest used topic. But the requirement is to apply RAND()
on the lowest usage.
As per the above example table, the query should do a rand()
where usage count is 0.
I can write 2 queries, first one gets the lowest count and second query does the rand()
on that count but can that be combined into 1 ?
Thank you.
Solution 1 @fancypants
SELECT b.body, node.nid
FROM node
LEFT JOIN body ON n.nid = body.entity_id
LEFT JOIN topic_usage ON n.nid = u.entity_id
LEFT JOIN field_data_field_issue_reference r ON node.nid = f.entity_id ,
( select @min := (
SELECT min(f.usage_value) from node n
LEFT JOIN field_data_field_topic_usage ON n.nid = f.entity_id
)
) var_init_subquery
AND node.status = 1
AND f.field_issue_reference_target_id = 708
order by f.usage_value, if(f.usage_value=@min, rand(), node.nid)
LIMIT 0,1
Solution 2 @Hitesh
SELECT b.body, node.nid
FROM node
LEFT JOIN body ON node.nid = b.entity_id
LEFT JOIN topic_usage ON node.nid = f.entity_id
LEFT JOIN issue_reference f ON node.nid = f.entity_id
AND (
f.entity_type = 'node'
AND
f.deleted = '0'
)
WHERE node.type = 'issue_paragraphs'
AND node.status = 1
AND f.field_issue_reference_target_id = 708
GROUP BY node.nid having f.usage_value=min(f.usage_value)
ORDER BY rand() LIMIT 0,1
Upvotes: 1
Views: 67
Reputation: 51868
Sample data:
CREATE TABLE t
(`a` int, `b` int)
;
INSERT INTO t
(`a`, `b`)
VALUES
(1, 1),
(2, 1),
(3, 0),
(4, 0),
(5, 1),
(6, 0)
;
Query:
select
*
from
t
order by b, if(b=0, rand(), a)
Every time you execute it, a
column is ordered random for entries where b
is 0
and ordered by a
where b
is not 0
.
To have it working for your minimum, you could simply use variables:
select
a, b
from
t
, (select @min := (select min(b) from t)) var_init_subquery
order by b, if(b=@min, rand(), a)
Upvotes: 2
Reputation: 1588
I think you need to use Group by and having clause for selections and then use order by rand(). For example i am writing you query as following. My query may be wrong on based on column selections but i am tring to focus on approch.
SELECT b.body, n.nid
FROM node n
LEFT JOIN body b ON n.nid = b.entity_id
LEFT JOIN topic_usage u ON n.nid = u.entity_id
LEFT JOIN reference r ON n.nid = r.entity_id
AND (
r.entity_type = 'node'
AND
r.deleted = '0'
)
WHERE n.type = :type
AND n.status = 1
AND r.target_id= :id
GROUP BY n.nid having u.field_topic_usage_value=min(u.field_topic_usage_value)
ORDER BY rand()
Upvotes: 1
Reputation: 6421
As far as I know, this cannot be done with one query if you want to apply the RAND()
ordering only for topics with 0 usage count. A possible workaround would be changing the ORDER BY
clause like this:
ORDER BY u.field_topic_usage_value ASC, RAND()
This will apply random sorting to all topics with the same usage count as a possible workaround, while maintaining the ordering by usage count itself.
Upvotes: 0