仅选择部分结果,但获取总行数

时间:2013-07-18 21:47:38

标签: sql postgresql count pattern-matching window-functions

我陷入了SQL子查询选择。现在,我有一个表产品:

 id | name  |     description      
----+-------+----------------------
  6 | 123   | this is a           +
    |       | girl.
  7 | 124   | this is a           +
    |       | girl.
  8 | 125   | this is a           +
    |       | girl.
  9 | 126   | this is a           +
    |       | girl.
 10 | 127   | this is a           +
    |       | girl.
 11 | 127   | this is a           +
    |       | girl. Isn't this?
 12 | 345   | this is a cute slair
 13 | ggg   | this is a           +
    |       | girl
 14 | shout | this is a monster
 15 | haha  | they are cute
 16 | 123   | this is cute

我想要做的是找到( 记录总数 前5条记录 '1''this'列中包含namedescription

我能弄清楚的是如此丑陋:

SELECT *, (select count(id)
           from (SELECT * from products
                 where description like any (array['%1%','%this%'])
                           or name like any (array['%1%','%this%'])
                ) as foo
          ) as total
from (SELECT * from products
      where description like any (array['%1%','%this%'])
                or name like any (array['%1%','%this%']))
     ) as fooo
limit 5;

2 个答案:

答案 0 :(得分:1)

假设您使用的是postgresql 9.0+,可以使用CTE来实现此目的。 例如

WITH p AS (
        SELECT *
        FROM products
        WHERE description LIKE ANY (ARRAY['%1%','%this%']) OR name LIKE ANY (ARRAY['%1%','%this%'])
        )
SELECT  *,
        (select count(*) from p) as total
FROM p
ORDER BY id LIMIT 5;

答案 1 :(得分:1)

您可以使用聚合函数count()作为窗口函数来计算同一查询级别的总计数:

SELECT id, name, description, count(*) OVER () AS total
FROM   products p
WHERE  description LIKE ANY ('{%1%,%this%}'::text[])
           OR name LIKE ANY ('{%1%,%this%}'::text[])
ORDER  BY id
LIMIT  5;

引用manual on window functions

  

除了这些函数之外,任何内置或用户定义的聚合函数都可以用作窗口函数

这很有效,因为在窗口函数之后应用了LIMIT

我还使用了数组文字的替代语法。一个和另一个一样好。对于较长的阵列,这个较短。有时候需要一个明确的类型转换。我在这里假设text

在我的测试中,它比具有CTE的版本更简单,更快。

顺便说一下,这个带有正则表达式的WHERE子句更短 - 但更慢:

WHERE  description ~ '(1|this)'
           OR name ~ '(1|this)'

丑陋,但很快

还有一个测试:我发现原始版本(类似于你已经的版本)甚至 更快

SELECT id, name, description
    , (SELECT count(*)
       FROM   products p
       WHERE  description LIKE ANY ('{%1%,%this%}'::text[])
                  OR name LIKE ANY ('{%1%,%this%}'::text[])
      ) AS total
FROM   products p
WHERE  description LIKE ANY ('{%1%,%this%}'::text[])
           OR name LIKE ANY ('{%1%,%this%}'::text[])
ORDER  BY id
LIMIT  5;