1

次のように、「性別」列を持つテーブルをクエリする必要があります。

| | ID | 性別 | 名前 |
-------------------------
| | 1 | み | マイケル |
-------------------------
| | 2 | ふ | ハンナ |
-------------------------
| | 3 | み | ルイ | ルイ |
-------------------------

そして、たとえば男性が 80%、女性が 20% の最初の N 個の結果を抽出する必要があります。したがって、1000 件の結果が必要な場合は、800 人の男性と 200 人の女性を取得する必要があります。

  1. 単一のクエリでそれを行うことは可能ですか? どのように?

  2. 十分な記録がない場合 (上記の例では男性が 700 人しかいないと想像してください)、700 / 300 を自動的に選択することはできますか?

4

3 に答える 3

2

基本的に、できるだけ多くの「M」を取得しますが、パーセンテージを超えないようにし、十分な「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

于 2013-08-20T04:55:05.583 に答える
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
于 2013-08-20T02:10:47.633 に答える
-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'

2番目のビットは、実際には非常に簡単です。基本的に、上位 % の男性を選択し、リストの残りの行を合計行数まで女性で埋めます。女性の数は実際には関係ありません。

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
于 2013-08-20T01:18:59.410 に答える