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。 (似乎是一个奇怪的结果。)
简短版,我有一个 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。 (似乎是一个奇怪的结果。)