2012-04-30 4 views
0

Предположим, у нас есть таблица со столбцом «A», которая имеет значения от 0 до N. И я хочу выбрать 30% каждой строки, которые имеют одинаковое значение для столбца «A», ,Выберите 30% каждого значения столбца

So if I have this: 
A| B 
------- 
0 hello 
0 test 
0 hi 
1 blah1 
1 blah2 
1 blah3 
1 blah4 
1 blah5 
1 blah6 

Result: 
A| B 
------- 
0 hello 
1 blah1 
1 blah4 

это может быть blah1 или любой другой мля, что не blah4 и blah4 может быть любой другой мля, что не blah1, в основном это может быть случайным или пропуск.

Кстати, фактический стол огромный, говорящий терабайт, поэтому подумайте о производительности.

+1

Не могли бы вы прояснить этот вопрос? Непонятно, что вы хотите выполнить. – mservidio

+2

Вы хотите, чтобы 30% строк? Например, если есть 100 строк, вам нужно 30 из них? Какой из 30? Или вы хотите сказать, что вам нужно 30% значения в столбце A, сгруппированном по столбцу B? Ваш вопрос непонятен – Matthew

+0

Вам нужно определить, какие 30%. «Первые» 30%? Хорошо ... тогда что определяет «первую» -сущность данной строки? У вас ** должны быть некоторые критерии. Таблица порядок? Такого нет ... это иллюзия. Случайные? Сервер Sql не делает случайным образом. SQL предназначен для того, чтобы точно указать, какие строки вы хотите. –

ответ

6

попробовать что-то вроде этого:

DECLARE @YourTable table (A int, b varchar(10)) 
INSERT @YourTable VALUES (0, 'hello') --OP's data 
INSERT @YourTable VALUES (0, 'test') 
INSERT @YourTable VALUES (0, 'hi') 
INSERT @YourTable VALUES (1, 'blah1') 
INSERT @YourTable VALUES (1, 'blah2') 
INSERT @YourTable VALUES (1, 'blah3') 
INSERT @YourTable VALUES (1, 'blah4') 
INSERT @YourTable VALUES (1, 'blah5') 
INSERT @YourTable VALUES (1, 'blah6') 

;WITH NumberedRows AS 
( SELECT 
     A,B,ROW_NUMBER() OVER (PARTITION BY A ORDER BY A,B) AS RowNumber 
     FROM @YourTable 
) 
, GroupCounts AS 
( SELECT 
     A,MAX(RowNumber) AS MaxA 
     FROM NumberedRows 
     GROUP BY A 
) 
SELECT 
    n.a,n.b 
    FROM NumberedRows   n 
     INNER JOIN GroupCounts c ON n.A=c.A 
    WHERE n.RowNUmber<=(c.MaxA+1)*0.3 

ВЫВОД:

a   b 
----------- ---------- 
0   hello 
1   blah1 
1   blah2 

(3 row(s) affected) 

EDIT на основе великой идеи в комментарий от Андрей М

;WITH NumberedRows AS 
( SELECT 
     A,B,ROW_NUMBER() OVER (PARTITION BY A ORDER BY A,B) AS RowNumber 
      ,COUNT(*) OVER (PARTITION BY A) AS TotalOf 
     FROM @YourTable 
) 
SELECT 
    n.a,n.b 
    FROM NumberedRows   n 
    WHERE n.RowNumber<=(n.TotalOf+1)*0.3 
    ORDER BY A 

OUTPUT:

a   b 
----------- ---------- 
0   hello 
1   blah1 
1   blah2 

(3 row(s) affected) 

EDIT здесь "случайных" строки, используя Андрей М идею:

DECLARE @YourTable table (A int, b varchar(10)) 
INSERT @YourTable VALUES (0, 'hello') --OP's data 
INSERT @YourTable VALUES (0, 'test') 
INSERT @YourTable VALUES (0, 'hi') 
INSERT @YourTable VALUES (1, 'blah1') 
INSERT @YourTable VALUES (1, 'blah2') 
INSERT @YourTable VALUES (1, 'blah3') 
INSERT @YourTable VALUES (1, 'blah4') 
INSERT @YourTable VALUES (1, 'blah5') 
INSERT @YourTable VALUES (1, 'blah6') 

;WITH NumberedRows AS 
( SELECT 
     A,B,ROW_NUMBER() OVER (PARTITION BY A ORDER BY newid()) AS RowNumber 
     FROM @YourTable 
) 
, GroupCounts AS (SELECT A,COUNT(A) AS MaxA FROM NumberedRows GROUP BY A) 
SELECT 
    n.A,n.B 
    FROM NumberedRows   n 
     INNER JOIN GroupCounts c ON n.A=c.A 
    WHERE n.RowNUmber<=(c.MaxA+1)*0.3 
    ORDER BY n.A 

ВЫВОД:

a   b 
----------- ---------- 
0   hi 
1   blah3 
1   blah6 

(3 row(s) affected) 
+0

Это, кажется, пропуская некоторые значения a, я сказал, что это очень большая таблица. Он начинался с 1 затем 3, затем 10, и должен быть 0, затем 1, затем 2 ... – luis

+0

Не нужно вычислять 'MAX (RowNumber)' отдельно, просто добавьте 'COUNT (*) OVER (PARTITION BY A)' to 'NumberedRows'. –

+0

Вам нужна фактическая случайность или круговой выбор? –

1

Это использует только один вложенный запрос, и, таким образом, за один проход через набор ,

SELECT a 
    , b 
FROM 
    (
     SELECT A 
      , b 
      , ROW_NUMBER() 
       OVER( PARTITION BY A 
         ORDER BY b 
        ) r 
      , COUNT(b) 
       OVER( PARTITION BY A 
        ) ct 
     FROM @YourTable 
    ) n 
WHERE n.r <= n.ct * 0.3 

Как это делает, хотя это всегда возвращает верхний 3, если есть меньше, чем 10 и «дополнительные услуги» публиковался в первые бункера .:

SELECT A 
    , b 
FROM 
    (
     SELECT A 
      , b 
      , NTILE(10) 
       OVER( PARTITION BY a 
         ORDER BY b 
        ) tens       
     FROM @YourTable 

    ) n 
WHERE tens <= 3; 
Смежные вопросы