darwin
darwin

Reputation: 240

Select every other row as male/female from mysql table

I've got a table containing persons gender-coded as 0 and 1. I need to select every other row as male/female. I thought I could manage this somehow by using modulo and the gender-codes 0 and 1, but I haven't managed to figure it out yet...

The result I'm looking for would look like this:

+-----+--------+-------+
| row | gender | name  |
+-----+--------+-------+
|   1 | female | Lisa  |
|   2 | male   | Greg  |
|   3 | female | Mary  |
|   4 | male   | John  |
|   5 | female | Jenny |
+-----+--------+-------+

etc.

The alternative is to do it in PHP by merging 2 separate arrays, but I would really like it as a SQL query...

Any suggestions are appreciated!

Upvotes: 1

Views: 5600

Answers (5)

Pooja Sudhir Narang
Pooja Sudhir Narang

Reputation: 1

SELECT alias.*, ROW_NUMBER() OVER (PARTITION BY GENDER ORDER BY GENDER) rnk
FROM TABLE_NAME
ORDER BY rnk, GENDER DESC

Upvotes: -1

user1191247
user1191247

Reputation: 12973

Similar to Mikael's solution but without the need to order the resultset multiple times -

SELECT *
FROM (
    SELECT people.*,
        IF(gender=0, @mr:=@mr+1, @fr:=@fr+1) AS rank
    FROM people, (SELECT @mr:=0, @fr:=0) initvars
) tmp
ORDER BY rank ASC, gender ASC;

To avoid having to order both the inner and outer selects I have used separate counters (@mr - male rank, @fr - female rank) in the inner select.

Upvotes: 1

Mikael Eriksson
Mikael Eriksson

Reputation: 138980

Found Emulate Row_Number() and modified a bit for your case.

set @rownum := 0;
set @pg := -1;

select p.name, 
       p.gender
from
  (
    select name,
           gender,
           @rownum := if(@pg = gender, @rownum+1, 1) as rn, 
           @pg := gender as pg 
    from persons
    order by gender
  ) as p
order by p.rn, p.gender

Try on SQL Fiddle

Note: From 9.4. User-Defined Variables

As a general rule, you should never assign a value to a user variable and read the value within the same statement. You might get the results you expect, but this is not guaranteed.

I will leave it up to you do decide if you can use this. I don't use MySQL so I can't really tell you if you should be concerned or not.

Upvotes: 2

huhu78
huhu78

Reputation: 389

Do two subqueries to select male and female. Use ranking function to have them enumerated.

Males:
1 | Peter
2 | John
3 | Chris

Females:
1 | Marry
2 | Christina
3 | Kate

Then multiplay ranking result by x10 and add 5 for females. So you have this:

Males:
10 | Peter
20 | John
30 | Chris

Females:
15 | Marry
25 | Christina
35 | Kate

Then do the UNION ALL and sort by new sort order/new ID.

Together it should like this (pseudo code)

SELECT
Name
FROM
(subquery for Males: RANK() AS sortOrd, Name)
UNION ALL
(subquery for Females: RANK()+1 AS SortOrd, Name)
ORDER BY SortOrd

Result should be like this:

Males and Females:
10 | Peter
15 | Marry
20 | John
25 | Christina
30 | Chris
35 | Kate  

Upvotes: 2

meriton
meriton

Reputation: 70574

I've got a table containing persons gender-coded as 0 and 1

Then why would you make assumptions on the order of rows in the result set? Seems to me transforming the 0/1 into 'male'/'female' is far more robust:

select name, case gender when 0 then 'male' else 'female' end
from Person

Upvotes: 0

Related Questions