简体   繁体   中英

How to select row pairs that match certain criteria in mysql

I have a table of things. Here is a simplified structure:

CREATE TABLE `things` (
  `thing_id` int(11) NOT NULL AUTO_INCREMENT,
  `thing_group` int(11) NOT NULL,
  `thing_status` int(1) NOT NULL DEFAULT '0'
);

There are 2 types of things. Primary, which would have thing_id = thing_group and secondary, which would having a unqiue thing_id but the same thing_group as the primary item.

INSERT INTO `things` (`thing_id`, `thing_group`, `thing_status`) VALUES
(1, 1, 0),
(2, 1, 1),
(3, 3, 1),
(4, 3, 0),
(5, 5, 1),
(6, 5, 1),
(7, 7, 0),
(8, 7, 0),
(9, 9, 1),
(10, 9, 1),

I have thousands of these pairs.

thing_status can be 0 for either the primary or the secondary (or both), but I want to select ONLY a pair (at random) that has thing_status = 1 both for primary and secondary thing.

So from the sample data I provided, it should only return pairs which are either thing_id 5 and 6, or 9 and 10 (at random)

Hard part: Some things can just have the primary thing only, and no secondary. The query should still return those and treat them equally to things that come in pairs.

Am i better off doing 2 queries or a convoluted single query?

My intuition says that you should use 2 queries with a UNION ALL . But... with MySQL it's not always clear what works and what doesn't.

I believe that this query does what you want though:

SELECT t1.thing_id, t1.group_id
FROM things t1
LEFT JOIN things t2
    ON t2.thing_id = t2.thing_group
    AND t1.thing_id != t2.thing_id
WHERE (
    t1.thing_id = t1.thing_group
    AND t2.thing_id IS NULL
) OR (
    t1.thing_group = t2.thing_id
    AND t1.thing_id != t1.thing_group
)
GROUP BY t1.thing_id, t1.group_id

Group your rows by thing_group and select those where the number of rows is the same as the sum of thing_status . Join the resulting set back to the original table on thing_group to obtain the actual rows corresponding to the groups. So:

SELECT
  t.thing_id,
  t.thing_group
FROM things t
INNER JOIN (
  SELECT thing_group
  FROM things
  GROUP BY thing_group
  HAVING COUNT(*) = SUM(thing_status)
  ORDER BY RAND()
  LIMIT 1
) g ON t.thing_group = g.thing_group

Not so hard, maybe the random part is a bit more tricky:

select * 
from things 
where 
  thing_group = (select thing_group
                 from things 
                 where thing_status = 1 
                 group by thing_group
                 having count(thing_id) = 2
                 limit 1)
limit 1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM