SQL:如果行太多,给出 up/return 不同的结果

SQL: Give up/return different result if too many rows

简短版,我有一个 SQL 语句,我只想要结果 if 行数 returned 小于某个值(说 1000),否则我想要一个不同的结果集。当我打算将它们扔掉时,最好的方法是什么而不会产生 returning 1000 行的开销(如果我使用 limit 会发生这种情况)?

例如,我想要return

的结果
SELECT * 
FROM T 
WHERE updated_at > timestamp 
  AND name <= 'Michael' 
ORDER BY name ASC

前提是最多有 1000 个条目,但如果超过 1000 个条目,我想 return

SELECT * 
FROM T 
ORDER BY name ASC 
LIMIT 25

两次查询还不错,但我绝对不想从第一次查询中取回1000条记录只是为了扔掉它们。

(也很高兴使用 Postgres 扩展,但更喜欢 SQL)

--

解释一下,我正在批量刷新客户请求的数据,有时客户需要知道他们已经收到的部分是否有任何更改。不过,如果改动太多,我就放弃了,重新从头开始发记录。

WITH max1000 AS (
   SELECT the_row, count(*) OVER () AS total
   FROM  (
      SELECT the_row  -- named row type
      FROM   T AS the_row
      WHERE  updated_at > timestamp
      AND    name <= 'Michael'
      ORDER  BY name
      LIMIT  1001
      ) sub
   )
SELECT (the_row).*  -- parentheses required
FROM   max1000 m
WHERE  total < 1001

UNION ALL
(  -- parentheses required
SELECT * 
FROM   T 
WHERE (SELECT total > 1000 FROM max1000 LIMIT 1)
ORDER  BY name
LIMIT  25
)

CTE max1000 中的子查询 sub 获取第一个查询的完整排序结果 - 包装为行类型,​​并使用 LIMIT 1001 以避免多余的工作。

外层的 SELECT 添加了总行数。参见:

外部 UNION 查询的第一个 SELECT returns 分解行作为结果 - 如果它们少于 1001。

第二个 SELECT 外部 UNION 查询 returns 备用结果 - 如果超过 1000。需要括号 - 参见:

或:

WITH max1000 AS (
   SELECT *
   FROM   T
   WHERE  updated_at > timestamp
   AND    name <= 'Michael'
   ORDER  BY name
   LIMIT  1001
   )
, ct(ok) AS (SELECT count(*) < 1001 FROM max1000)   

SELECT *
FROM   max1000 m
WHERE (SELECT ok FROM ct)

UNION ALL
(  -- parentheses required
SELECT * 
FROM   T 
WHERE (SELECT NOT ok FROM ct)
ORDER  BY name
LIMIT  25
);

我觉得我更喜欢第二个。不确定哪个更快。

要么优化大多数调用中少于 1001 行的性能。如果那是例外,我会先 运行 便宜一些。也很大程度上取决于可用索引...

如果第一个查询没有找到任何行,您会得到 no row。 (似乎是一个奇怪的结果。)