SQL для выбора средней трети всех значений в столбце в PostgreSQL - PullRequest
2 голосов
/ 21 мая 2009

Предположим, у меня есть столбец высот - как мне выбрать все и только те значения высоты, которые не находятся ни в верхних 30% значений, ни в нижних 30% значений.

UPDATE:

Мне бы хотелось получить ответ для PostgreSQL (или, в случае неудачи, MySQL - я использую Rails).

Ответы [ 5 ]

5 голосов
/ 21 мая 2009
WITH cte AS (
 SELECT *, NTILE(100) OVER (ORDER BY column) as rank
 FROM table)
SELECT * FROM cte WHERE rank BETWEEN 30 and 70
2 голосов
/ 21 мая 2009

для sql server 2005+ вы должны использовать для этого функцию NTILE () .

SELECT *
FROM   (
         SELECT ntile(3) over(order by AddressId) as Percentile, *
         FROM   (
                SELECT top 100 *
                FROM   Person.Address
           ) t
       ) t
where Percentile = 2
2 голосов
/ 21 мая 2009

для SQL Server 2005 +

SELECT
    *
FROM
    MyTable M
EXCEPT
SELECT
    *
FROM
    (SELECT TOP 30 PERCENT
        *
    FROM
        MyTable M
    ORDER BY
        Height
    UNION ALL
    SELECT TOP 30 PERCENT
        *
    FROM
        MyTable M
    ORDER BY
        Height DESC) foo
1 голос
/ 29 мая 2009

Postgres принимает константы только в предложении limit. Таким образом, решение выше не работает.

Ваш выбор выглядит примерно так:

SELECT *
  FROM (SELECT T.HEIGHT, 
               -- this tells us the "ranking" of each row 
               -- by counting all the heights that are small than 
               -- height in the that row
               (SELECT COUNT(*) + 1
                  FROM <table> T1 
                 WHERE T1.HEIGHT < T.HEIGHT
               ) AS RANK,
               -- this tells us the count of rows in the table
               (SELECT COUNT(*) 
                  FROM <table> T1
               ) AS REC_COUNT
          FROM <table> T
         ORDER BY T.HEIGHT
       ) T
 -- now just list rows wich ranking is between (not top30) and (not bottom30)
 WHERE T.RANK BETWEEN (T.REC_COUNT*0.30) AND (T.REC_COUNT*0.70)

Это сработает в любой базе данных, которая принимает подвыборы (подзапросы).

Это не относится к равенствам в "высотах", но это можно сделать с помощью первичного ключа

SELECT COUNT(*) + 1
  FROM <table> T1 
 WHERE (T1.HEIGHT < T.HEIGHT)
    OR (T1.HEIGHT = T.HEIGHT and T1.PK_FIELD < T.PK_FIELD)

Привет.

1 голос
/ 21 мая 2009

Вы запрашиваете PostgresSQL, и он не поддерживает NTITLE или TOP X PERCENT.

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

select *
from MyTable
where height not in (
    select Height from MyTable order by Height desc 
    limit ((select count(*) from MyTable)*0.3)
    union
    select Height from MyTable order by Height
    limit ((select count(*) from MyTable)*0.3)
)

Теперь я не уверен, поддерживает ли PostgresSQL лимит, рассчитанный в подзапросе, и у меня нет базы данных PostgresSQL, чтобы попробовать его.

...