【问题标题】:How to select strings in UUID format + case sensitive wildcards如何选择 UUID 格式的字符串 + 区分大小写的通配符
【发布时间】:2022-01-22 11:07:10
【问题描述】:

如何仅选择格式为 XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 的字符串,其中 X 是任意数字或任意大写(不是小写)字符?

示例数据集:

ed54cb09-b402-4551-912d-b8e0fec69d9e --I do not want to select this one
00029B19-80CC-4FF8-BE11-BDB55FC7FC2A --I do want to select this one

有些是全大写,有些不是,这是一个 varchar 字段。我只想选择这些全大写 UUID,不包括其余的。

目前我正在使用 _ 通配符来查找基本的 UUID 格式,但看起来 UPPER 不适用于 _ 通配符。例如:

SELECT mycolumn
FROM mytable t
WHERE  t.mycolumn like UPPER('________-____-____-____-____________') COLLATE SQL_Latin1_General_Cp1_CS_AS

【问题讨论】:

  • 您可以尝试将其转换为 uniqueidentifier 并从尝试的转换中筛选出值为 NULL 的行。
  • 如果MyColumn = Upper( MyColumn ) 那么你不应该对小写字符有任何问题。 Try_Convert 可以处理其余的验证。您将Upperlike 一起使用没有意义。将所有小写下划线更改为大写不会有太大作用。
  • 我错过了这个奇怪的要求,@DaleK。似乎也需要COLLATE。也许需求是 XY 问题的一部分。例如,为什么 OP 首先不使用uniqueidentifier
  • 旁白:来自RFC4122:“每个字段都被视为一个整数,并将其值打印为一个以零填充的十六进制数字字符串,最高有效位在前。十六进制值“a”到"f" 输出为小写字符,输入时不区分大小写。"
  • @David 你知道该怎么做when someone answers吗?

标签: sql sql-server tsql


【解决方案1】:

如前所述,您可以首先使用区分大小写的排序规则将您的值的 upper 与其自身进行比较,以检查其全部大写。然后使用您的通配符模式(或更精确的模式,如下所示)来确认格式是否正确。

select
    -- Precise check on allowed characters
    case when upper(X.Test) = X.Test collate Latin1_General_CS_AI
        and X.Test like '[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]-[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]-[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]-[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]-[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]' then 1 else 0 end
    -- Loose check on allowed character, but definitely upper case
    , case when upper(X.Test) = X.Test collate Latin1_General_CS_AI
        and X.Test like '________-____-____-____-____________' then 1 else 0 end     
    -- Not sure why HAGO deleted their answer, but the following works also
    , case when upper(X.Test) = X.Test collate Latin1_General_CS_AI
        and try_convert(uniqueidentifier,X.Test) is not null then 1 else 0 end
    -- And combining Shmiel's and Charleface's suggestions gives
    , case when X.Test like replicate('[A-F0-9]', 8) + '-' + replicate('[A-F0-9]', 4) + '-' + replicate('[A-F0-9]', 4) + '-' + replicate('[A-F0-9]', 4) + '-' + replicate('[A-F0-9]', 12) collate Latin1_General_100_BIN2 then 1 else 0 end

from (
    values ('ed54cb09-b402-4551-912d-b8e0fec69d9e'), ('00029B19-80CC-4FF8-BE11-BDB55FC7FC2A')
) X (Test);

我必须在此附和 Larnu 的评论,这似乎是一个很奇怪的要求,通过其他地方的系统更改可能会更好地解决。

【讨论】:

  • 您可以使用REPLICATE(num_of_times,'[A-Z0-9]') 而不是键入它。
  • Latin1_General_100_BIN2 会更高效,UUID 是十六进制的,只使用[A-F0-9],那么就不需要三个不同的检查,就是完全匹配格式。跨度>
  • @Charlieface 有趣地使用Latin1_General_CS_AILIKE 不起作用,但使用Latin1_General_100_BIN2 可以。你能解释一下为什么它表现更好吗?
  • 二进制排序规则将总是比任何其他排序规则执行得更好:它不做任何排序规则,它只是一个字节比较,所以它是一个非常快的REPZ CMPSB on x86 处理器。为什么Latin1_General_CS_AI 不起作用我不知道,它似乎对我有用?不相信REPLICATE 可能会在每一行上计算它的速度很慢(尽管它是确定性的,所以编译器可能足够聪明地将它提升出来)而且它实际上并没有更短
  • @Charlieface 哦,当然 :) 自从我考虑二进制方面以来已经有一段时间了。嗯,看到这个dbfiddle 第一个比较不区分大小写。
猜你喜欢
  • 2013-05-03
  • 2014-09-07
  • 2022-11-22
  • 1970-01-01
  • 1970-01-01
  • 2014-10-26
  • 2017-12-09
  • 2018-04-28
  • 1970-01-01
相关资源
最近更新 更多