【问题标题】:sql query to return results which match a search key but also retrieves records which are alphabetically after the search keysql查询返回与搜索键匹配的结果,但也检索在搜索键之后按字母顺序排列的记录
【发布时间】:2016-02-20 13:01:39
【问题描述】:

标题很拗口,但我觉得很难解释。

我以前有一个允许用户输入搜索键的网络服务,例如4,这将返回以该搜索键开头的记录 例如4、4a、4b。

现在我被要求实现一个解决方案,如果用户键入 4,它将返回结果:

4
4a
4aa
4b
5
5a
5b
5c
5Z
6
52.
etc.. 

50 条记录。

我不确定从哪里开始更改查询...正在搜索的 col 是字母数字,这是令人困惑的部分。

查询本身超过 20 行,但将结果链接到搜索键的部分只是;

(col LIKE @searchKey + '[a-zA-Z.]%' OR col = @searchKey OR col >= @searchKey)

根据要求,顺序是:

ORDER BY   
        CASE WHEN col LIKE '[a-zA-Z]%' Then 1 ELSE 0 END,

                 CAST(SUBSTRING(col, 0, 

                  CASE WHEN patindex('%[a-zA-Z.]%', col) = 0

                  THEN len(col)+1

                  ELSE patindex('%[a-zA-Z.]%', col)

                  END) 

                 as INT),

    CASE WHEN col LIKE '[a-zA-Z]%' THEN SUBSTRING(col, 1,1) END,

    CASE WHEN col LIKE '[a-zA-Z]%' AND len(col) = 1 THEN 0 ELSE 1 END,

    CASE WHEN col LIKE '[a-zA-Z]%' AND len(col) = 2 THEN 0 ELSE 1 END,

    CASE WHEN col LIKE '[a-zA-Z]%' AND len(col) = 3 THEN 0 ELSE 1 END,

    col;

例如,现在如果我传入 82,我会得到结果:

8
8A
8B
8E
8H
9
9A
9C
9D
9E
82
82A
82B
82C
.
.
.
.
99R

但是我需要的是,如果用户输入 82,他们不会收到 8、8x、9、9x 等结果。

【问题讨论】:

  • 所以该字段显然是一个字符串字段。它曾经达到2位数吗?如果是这样,您需要从字符中解析出数字。
  • @Rabbit 它可以达到两位数是的。我不确定如何解析出不定字符串长度的数量
  • 您需要使用 PATINDEX 函数和 SUBSTRING 将字段分成您需要的两部分。字符串的 alpha 部分呢?有没有过 2 个字符?
  • @Rabbit 嗨,是的,字符串的字母部分确实可以是数字,甚至在某些情况下还有 .作为第一个字符。我明天将有测试数据可供使用,然后会报告。
  • 测试数据需要代表你所拥有的。我们还需要知道您期望从所述测试数据中得到什么排序。即使字符串看起来像数字,字符串比较也不同于数字。

标签: sql sql-server sql-server-2008 substring patindex


【解决方案1】:

您需要从 alpha 部分中分离出数字部分,然后将它们重新组合成一个可以排序和过滤的新数字值。您需要对用户输入执行相同的操作。

请注意,这不涉及您在帖子中提到的时间段,因为您没有告诉我们应该如何处理它。如果它无关紧要,则使用替换功能摆脱它。此外,这不处理字符串的 alpha 部分长于一个字符的情况。

我假设用户可以在输入数字后输入一个字符。如果不是这种情况,则可以通过不必转换用户输入并且不必将数字部分乘以大数来简化此操作。

100000 应该大于字符串数字部分中可能存在的最大数字。根据需要添加额外的零。

SQL Fiddle

declare @t table (col varchar(4))
declare @userinput varchar(4)

set @userinput = '9C'

insert into @t values ('8')
insert into @t values ('8A')
insert into @t values ('8B')
insert into @t values ('8E')
insert into @t values ('8H')
insert into @t values ('9')
insert into @t values ('9A')
insert into @t values ('9C')
insert into @t values ('9D')
insert into @t values ('9E')
insert into @t values ('82')
insert into @t values ('82A')
insert into @t values ('82B')
insert into @t values ('82C')
insert into @t values ('99R')

;with cte as (
    select 
        col,
        CONVERT(int,
            case when PATINDEX('%[a-z]%', col) = 0 
                then col
                else LEFT(col, PATINDEX('%[a-z]%', col) - 1)
            end
        ) * 100000
        +
        ascii(case when PATINDEX('%[a-z]%', col) = 0
            then ' '
            else SUBSTRING(col, PATINDEX('%[a-z]%', col), len(col))
        end) newcol

    from @t
)

select *
from cte
where 
    newcol >= (
        CONVERT(int,
            case when PATINDEX('%[a-z]%', @userinput) = 0 
                then @userinput
                else LEFT(@userinput, PATINDEX('%[a-z]%', @userinput) - 1)
            end
        ) * 100000
        +
        ascii(case when PATINDEX('%[a-z]%', @userinput) = 0
            then ' '
            else SUBSTRING(@userinput, PATINDEX('%[a-z]%', @userinput), len(@userinput))
        end)
    )
order by newcol

【讨论】:

  • 我对 cte 没有经验。我只是在使用 mssql。带点的条目应该放在最后
  • 谢谢,我搞定了,不需要其他解决方案
  • 很高兴你成功了,如果你想让我在某个时候发布更简单的解决方案,请告诉我,我会写出来
【解决方案2】:

如果你想在搜索键后面按字母顺序,那么使用>=:

where col >= @searchKey

【讨论】:

  • 真的吗? >= 运算符是否适用于字母数字字符串?
  • 可以,但对于字符串,'2' > '10' 因为它逐个字符比较。
  • @Rabbit 。 . .那里没有“但是”。 '2' > '10'2 > 10 不同。第一个比较字符串并且为真。第二个比较数字并且是假的。
  • 我了解运算符如何处理字符串和数字之间的区别。我的评论是指出该解决方案不起作用,因为字符串的数字部分达到 2+ 位。
  • @Rabbit 。 . .我在问题中看不到任何暗示排序是 not 字母的。我还可以看到一个合理的解释,即初始数字应该被视为一个数字。 OP应该澄清。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多