2013-08-20 5 views
1

мне нужно запросить таблицу, в которой есть столбец «гендер», например, так:Как выбрать различные проценты данных на основе значения столбца?

 
| id | gender | name | 
------------------------- 
| 1 | M  | Michael | 
------------------------- 
| 2 | F  | Hanna | 
------------------------- 
| 3 | M  | Louie | 
------------------------- 

И мне нужно, чтобы извлечь первые результаты N, которые имеют, например, 80% мужчин и 20% женщин. Итак, если бы мне понадобилось 1000 результатов, я бы хотел получить 800 мужчин и 200 женщин.

  1. Возможно ли это сделать в одном запросе? Как?

  2. Если у меня недостаточно записей (представьте, что у меня всего 700 мужчин на примере выше), можно ли автоматически выбрать 700/300?

+0

Для сценария 2, что должно произойти? –

+0

Я отредактировал свой ответ, чтобы лучше объяснить себя. –

+0

К сожалению, я не знаю достаточно SQL, чтобы дать ответ в терминах кода, но я могу дать логику: Я бы предложил SP и имел значение N (номер, который вы выбираете) и принимаете n * .8 и выберите, где пол - M, подсчитайте свои строки, возвращаемые как numResultsMale, и выберите N- (numResultsMale), где пол: F –

ответ

2

в принципе, вы хотите, чтобы получить как можно больше «М», как вы можете, но не больше, чем ваш процент, а затем получить достаточно «F», так у вас есть общие 1000 строк:

with cte_m as (
    select * from Table1 where gender = 'M' limit (1000 * 0.8) 
), cte as (
    select *, 0 as ord from cte_m 
    union all 
    select *, 1 as ord from Table1 where gender = 'F' 
    order by ord 
    limit 1000 
) 
select id, gender, name 
from cte 

sql fiddle demo

+0

Это замечательно! Благодаря! –

-1

У меня нет PostgreSQL со мной, но первый сценарий довольно легко с профсоюзом в MS SQL 2012. Я предполагаю, что вы можете сделать это так же в Postgre:

declare @MaxRows   INT 
     ,@PercentageMale INT 
     ,@PercentageFemale INT 

select  @MaxRows = 1000 
      ,@PercentageMale = 80 
      ,@PercentageFemale = 20 

select top (@MaxRows*@PercentageMale/100) * 
FROM  someTable 
WHERE  Gender = 'M' 
UNION 
select top (@MaxRows*@PercentageFemale/100) * 
FROM  someTable 
WHERE  Gender = 'F' 

Второй бит на самом деле довольно просто. В основном вы хотите выбрать верхний% мужчин, а затем заполнить остальную часть списка самками, вплоть до общего количества строк. Число женщин на самом деле не relavent:

declare @MaxRows   INT 
     ,@PercentageMale INT 

select  @MaxRows = 1000 
      ,@PercentageMale = 80 

SELECT TOP @MaxRows * 
FROM 
(
    select top (@MaxRows*@PercentageMale/100) * 
    FROM  someTable 
    WHERE  Gender = 'M' 
    UNION 
    select top (@MaxRows) * --we never want more than @MaxRows 
           --so no need to check for a %, 
           --just fill in the rest of the data set 
    FROM  someTable 
    WHERE  Gender = 'F' 
) a 
+1

-1 Вопрос не в Sql Server. –

0

Как о следующем, предполагающем вы поставляете количество строк («LMT»), и поплавки для распределения M/F:

create table gen (
id  integer, 
gender text, 
name text 
); 

-- inserts 75% males and 25% females into the source table ("gen") 
insert into gen select n, case when mod(n,5) = 0 then 'F' else 'M' end, (case when mod(n,5) = 0 then 'F' else 'M' end)||'_'||n::text 
from generate_series(1,20000) n 


-- extract 80/20 M vs F 
with conf as (select 1000 as lmt, .80::FLOAT as mpct, .20::FLOAT as fpct), 
    g as (select id,gender,name,row_number() over (partition by gender order by gender) rn from gen) 
select * 
from g 
where (gender = 'M' and rn <= (select lmt*mpct from conf)) 
or (gender = 'F' and rn <= (select lmt*fpct from conf)); 


-- Same query, to show the percent M vs F: 
with conf as (select 1000 as lmt, .80::FLOAT as mpct, .20::FLOAT as fpct), 
    g as (select id,gender,name,row_number() over (partition by gender order by gender) rn from gen) 
select gender,count(*) 
from (
    select * 
    from g 
    where (gender = 'M' and rn <= (select lmt*mpct from conf)) 
    or (gender = 'F' and rn <= (select lmt*fpct from conf)) 
    ) y 
group by gender