我在一个sql语句之后(如果它存在)或如何使用几个sql语句设置一个方法来实现以下目的。
我有一个列表框和一个搜索文本框。
在搜索框中,用户可输入姓氏,例如史密斯。 然后我想查询数据库以进行搜索:
select * FROM customer where surname LIKE searchparam
这将为包含姓氏的客户提供所有结果:SMITH。简单,对吧?
我需要做的是限制返回的结果。如果搜索参数只是S,那么这个语句可以给我1000行。 我想要的是结果,仅限于前20场比赛和第1场比赛前的10行。
例如,SMI搜索:
Sives
Skimmings
Skinner
Skipper
Slater
Sloan
Slow
Small
Smallwood
Smetain
Smith ----------- This is the first match of my query. But i want the previous 10 and following 20.
Smith
Smith
Smith
Smith
Smoday
Smyth
Snedden
Snell
Snow
Sohn
Solis
Solomon
Solway
Sommer
Sommers
Soper
Sorace
Spears
Spedding
有没有这样做? 尽可能少的sql语句。
原因?我正在为网络连接速度慢的用户创建一个应用程序。
我正在使用POSTGRESQL v9
由于 安德鲁
答案 0 :(得分:2)
WITH ranked AS (
SELECT *, ROW_NUMBER() over (ORDER BY surname) AS rowNumber FROM customer
)
SELECT ranked.*
FROM ranked, (SELECT MIN(rowNumber) target FROM ranked WHERE surname LIKE searchparam) found
WHERE ranked.rowNumber BETWEEN found.target - 10 AND found.target + 20
ORDER BY ranked.rowNumber
SQL小提琴here。请注意,小提琴使用示例数据,我将范围修改为之前的3个条目和过去的6个条目。
答案 1 :(得分:0)
我假设您正在寻找通用算法......
听起来你正在寻找找到“大于或等于史密斯”和“不如史密斯”匹配的组合。
对于前者,您需要按姓氏排序并将结果限制为20,对于后者,您可以按姓氏降序排列并限制为10。
然后可以将两个结果集一起添加为数组并重新排序。
答案 2 :(得分:0)
我认为您需要使用ROW_NUMBER()
(see this link)。
WITH cust1 AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY surname) as numRow FROM customer
)
SELECT c1.surname, c1.numRow, x.flag
FROM cust1 c1, (SELECT *,
case when numRow = (SELECT MIN(numRow) FROM cust1 WHERE surname='Smith') then 1 else 0 end as flag
FROM cust1) x
WHERE x.flag = 1 and c1.numRow BETWEEN x.numRow - 1 AND x.numRow + 1
ORDER BY c1.numRow
SQLFiddle here。
这样做有效,但最后的标志不是必需的,而是PinnyM帖子之类的查询。
答案 3 :(得分:0)
WITH ranked AS (
SELECT
*,
ROW_NUMBER() over (ORDER BY surname) AS rowNumber
FROM customer
),
minrank AS (
SELECT
*,
MIN(CASE WHEN surname LIKE searchparam THEN rowNumber END) OVER () AS target
FROM ranked
)
SELECT
surname
FROM minrank
WHERE rowNumber BETWEEN target - 10 AND target + 20
;
而不是对ranked
CTE进行两次单独调用,一次是获取第一个匹配的行号而另一个是从中读取结果,而是引入另一个CTE来实现这两个目的。不能代表PostgreSQL,但在SQL Server中,这可能会为查询提供更好的执行计划,尽管在任何一种情况下仍需要通过适当的测试来验证真正的效率。