限制百分比而不是没有子查询的行数

时间:2015-12-23 19:26:17

标签: postgresql

我想选择前1%的行;但是,我不能使用子查询来做到这一点。即,这不会起作用:

SELECT * FROM mytbl
WHERE var='value'
ORDER BY id,random()
LIMIT(SELECT (COUNT(*) * 0.01)::integer FROM mytbl)

如果不使用带有限制的子查询,我将如何完成相同的输出?

4 个答案:

答案 0 :(得分:1)

您可以使用PERCENT_RANK

WITH cte(ID, var, pc) AS
(
  SELECT ID, var, PERCENT_RANK() OVER (ORDER BY random()) AS pc
  FROM mytbl
  WHERE var = 'value'
)
SELECT *
FROM cte
WHERE pc <= 0.01
ORDER BY id;

SqlFiddleDemo

答案 1 :(得分:0)

我使用psycopg2包解决了它:

    cur.execute("SELECT ROUND(COUNT(id)*0.01,0)
                 FROM mytbl")
    nrows = str([int(d[0]) for d in cur.fetchall()][0])
    cur.execute("SELECT * 
                 FROM mytbl
                 WHERE var='value'
                 ORDER BY id, random() LIMIT (%s)",nrows)

也许有一个更优雅的解决方案只使用SQL,或者更有效的解决方案,但这正是我正在寻找的。

答案 2 :(得分:0)

如果我做对了,你需要:

  1. 所有行的随机1%样本,
  2. 如果样本中有一些id,则所有具有相同id的行也必须在那里。
  3. 以下的sql应该可以解决这个问题:

    with ids as (
        select   id,
                 total,
                 sum(cnt) over (order by max(rnd)) running_total
        from     (
                   select id,
                          count(*) over (partition by id) cnt,
                          count(*) over () total,
                          row_number() over(order by random()) rnd
                   from   mytbl
                 ) q
        group by id,
                 cnt,
                 total
    )
    select   mytbl.*
    from     mytbl,
             ids
    where    mytbl.id = ids.id
    and      ids.running_total <= ids.total * 0.01
    order by mytbl.id;
    

答案 3 :(得分:0)

我当然没有您的数据,但是在LIMIT子句中使用子查询没有问题。

但是,子查询仅包含count(*)部分,然后我将结果乘以0.01

SELECT * FROM mytbl
WHERE var='value'
ORDER BY id,random()
LIMIT(SELECT count(*) FROM mytbl)*0.01;