mysql order by from a different table breaks ranking

mysql order by from a different table breaks ranking



I have a query that grabs tags for a list of articles and limits it to under 5 tags per article. This works pretty well.



Here's the query:


SET @rank=null, @val=null;
SELECT * FROM (
SELECT r.article_id, c.`category_name`, c.`category_id`,
@rank := IF( @val = r.article_id, @rank +1, 1 ) AS rank,
@val := r.article_id
FROM `article_category_reference` r
INNER JOIN `articles_categorys` c ON c.category_id = r.category_id
WHERE r.article_id
IN ( 1,2 )
ORDER BY r.`article_id` ASC
) AS a
WHERE rank < 5



However, I have specific tags I want to show up first which have a column of "show_first" 0/1 and I want them included first and be counted.



I've tried doing:


ORDER BY CASE WHEN (c.`show_first` = 1) THEN 0 ELSE 1 END, r.`article_id` ASC



Which breaks the rank counting, so all tags end up showing.



Any pointers would be appreciated.



The tables:


CREATE TABLE `article_category_reference` (
`ref_id` int(11) NOT NULL,
`article_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Indexes for table `article_category_reference`
--
ALTER TABLE `article_category_reference`
ADD PRIMARY KEY (`ref_id`),
ADD KEY `category_id` (`category_id`),
ADD KEY `article_id` (`article_id`);

CREATE TABLE `articles_categorys` (
`category_id` int(11) NOT NULL,
`category_name` varchar(32) CHARACTER SET utf8 NOT NULL,
`quick_nav` tinyint(1) NOT NULL DEFAULT '0',
`is_genre` tinyint(1) NOT NULL DEFAULT '0',
`show_first` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

--
-- Indexes for table `articles_categorys`
--
ALTER TABLE `articles_categorys`
ADD PRIMARY KEY (`category_id`);

-- And some data:

INSERT INTO `articles_categorys` (`category_id`, `category_name`, `quick_nav`, `is_genre`, `show_first`) VALUES
(1, 'one', 1, 0, 0),
(2, 'two', 1, 0, 0),
(3, 'three', 1, 0, 0),
(4, 'four', 0, 0, 0),
(5, 'five', 0, 0, 0),
(6, 'six', 0, 0, 0),
(7, 'seven', 0, 0, 1),
(8, 'eight', 0, 0, 1);

INSERT INTO `article_category_reference` (`ref_id`, `article_id`, `category_id`) VALUES
(1, 1, 1),
(2, 1, 2),
(3, 1, 3),
(4, 1, 4),
(5, 1, 5),
(6, 1, 6),
(7, 1, 7),
(8, 1, 8),
(9, 2, 1),
(10, 2, 2),
(11, 2, 3),
(12, 2, 4),
(13, 2, 5),
(14, 2, 6),
(15, 2, 7),
(16, 2, 8);



Fiddle of how it works: http://sqlfiddle.com/#!9/1de99/1/0



Fiddle of it not working with me wanting some to always show first: http://sqlfiddle.com/#!9/0d36b7/1 (adding in a second group seems to break the ranking system)





Could you provide some sample data and expect result?
– D-Shih
Aug 30 at 22:54





See meta.stackoverflow.com/questions/333952/…
– Strawberry
Aug 30 at 22:56





Added tables + a fiddle to show the working version that doesn't deal with tags i want to show first. Still fiddling to show the non-working example where I want "show_first" to be included...
– NaughtySquid
Aug 30 at 23:23





Added example data, added link to show how it breaks ranking system.
– NaughtySquid
Aug 30 at 23:30





No his comment doesn't solve it. The whole point is to pull more than one group, will see about a better fiddle.
– NaughtySquid
Aug 31 at 7:20





1 Answer
1



Your issue is not in the where condition, it's about the ranking that you are creating.



As you will see in my answer, I have created one inner query which will get that record in specific order and apply accurate ranking.



If you check your inner query, it's shows that all rows have the same rank and that is due to that ordering issue.



So I have added the ORDER BY clause in innermost query, and then filtered out records which have rank1 less than 5.


ORDER BY


rank1


5


SET @rank1=null, @val=null;

SELECT * FROM (
SELECT a.article_id, a.`category_name`, a.`category_id`,
@rank1 := IF( @val = a.article_id, @rank1 +1, 1 ) AS rank1,
@val := a.article_id
FROM (
SELECT r.article_id, c.`category_name`, c.`category_id`
FROM `article_category_reference` r
INNER JOIN `articles_categorys` c ON c.category_id = r.category_id
GROUP BY r.article_id, c.`category_name`, c.`category_id`
ORDER BY r.`article_id`,CASE WHEN (c.`show_first` = 1) THEN 0 ELSE 1 END ASC
) AS a
) Z
WHERE Z.rank1 < 5;



You can check here.





Try This answer are low-value on StackOverflow because they do very little to educate the OP and thousands of potential researchers. Every time you post an answer, always include how your solution works and why it is advisable.
– mickmackusa
Aug 31 at 7:47





Nope. Did you test it? Shows all of them, no limit placed as expected.
– NaughtySquid
Aug 31 at 7:48





@mickmackusa You can check my answer. I am waiting for his answer that ,if it get resolve his problem or not.Once get confirmation then i can explain my logic to him.
– Sagar Gangwal
Aug 31 at 8:28





While that works, you're now selecting all possible article id's, as my example shows I want to pick specific id's using IN.
– NaughtySquid
Aug 31 at 8:29





Yes, that you can filter out.
– Sagar Gangwal
Aug 31 at 8:30



Required, but never shown



Required, but never shown






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)