【问题标题】:Parsing / Indexing a Binary String in SQL Server在 SQL Server 中解析/索引二进制字符串
【发布时间】:2015-01-02 07:01:00
【问题描述】:

我已经广泛搜索了相关答案,但没有一个完全满足我需要做的事情。

出于我们的目的,我有一列包含 50 个字符的二进制字符串。在我们的数据库中,它实际上有数百个字符长。

我们数据库中的每个唯一项目 ID 都有一个字符串。每个“1”的位置标记一个特定的标准为真,一个“0”为假,因此 1 和 0 的索引位置非常重要。大多数情况下,我关心 1 的位置。

我没有更新任何数据库,所以我首先决定尝试创建一个循环来查看每个字符串并创建 1 的位置列表。

declare @binarystring varchar(50) = '10000010000110000001000000000000000000000000000001'
declare @position int = 0
declare @list varchar(200) = ''

while (@position <= len(@binarystring))
begin   

set @position = charindex('1', @binarystring, @position)
set @list = @list + ', ' + convert(varchar(10),@position)
set @position = charindex('1', @binarystring, @position)+1

end 
select right(@list, len(@list)-2)

这将创建以下列表:

1, 7, 12, 13, 20, 50

但是,如果字符串末尾没有“1”,则循环将爆炸,因为我是通过出现 1 而不是一次一个字符来搜索字符串。我不确定当循环通常会到达字符串末尾时如何满足中断条件,而没有 1。

我的循环轰炸是否有一个简单的解决方案,我什至应该首先循环吗?

我尝试过其他的解析、联合连接、索引等方法,但鉴于这种非常特殊的情况,我找不到任何可以完全满足我需要的组合。上面的代码是我迄今为止最好的。

我并不特别需要以逗号分隔的列表作为输出,但我需要知道字符串中所有 1 的位置。 1 的数量不同,但字符串大小始终相同。

这是我第一次在 stackoverflow 上发帖,但我已经多次使用答案。我试图用相关信息提出一个明确的问题。如果有什么我能帮忙的,我会尽力满足任何要求。

【问题讨论】:

    标签: sql sql-server arrays loops binary


    【解决方案1】:

    while 条件改为这个怎么样?

    while (charindex('1', @binarystring, @position) > 0)
    

    【讨论】:

    • 这对于解决字符串末尾没有 1 的问题非常有效,但如果字符串中没有 1 则会爆炸。这有什么好的吗?也许是案例陈述?
    • @Muffin_Cup 。 . .在那种情况下,这个“炸弹”会如何?如果发生这种情况,那么@list 将是空的。
    【解决方案2】:
     while (@position <= len(@binarystring))
     begin   
          set @position = charindex('1', @binarystring, @position)
          if @position != 0 
          begin
               set @list = @list + ', ' + convert(varchar(10),@position)
               set @position = charindex('1', @binarystring, @position)+1
          end
          else
          begin
               break
          end;
     end
    

    【讨论】:

    • 当没有找到最后一个 1 时,break 会让你跳出循环,并阻止它从字符串的 from 重新开始。
    • 这个循环也可以,但是如果在字符串中没有找到 1(全为零)它会爆炸 - 有没有好的解决方案?
    • 在循环之前简单检查是否存在任何 1 if (charindex('1', @binarystring, @position) > 0 -- 然后放入 while 循环
    【解决方案3】:

    拥有大量连续整数的源通常很有用。我有一个表 dbo.range 有一个单列 id 包含从 -500,000 到 +500,000 的所有连续整数。该列是一个聚集的主键,因此查找速度很快。有了这样的表,解决你的问题就简单了。

    假设您的表具有类似的架构

    create table dbo.some_table_with_flags
    (
      id    int           not null primary key ,
      flags varchar(1000) not null ,
    )
    

    下面的查询应该可以做到:

    select row_id        = t.id ,
           flag_position = r.id
    from dbo.some_table t
    join dbo.range      r on r.id between 1 and len(t.flags)
                         and substring(t.flags,r.id,1) = '1'
    

    对于flags 列中的每个1 值,您将获得一行,其中包含源表的ID 列中的ID,以及在flags 中找到1 的位置。

    有许多技术可用于生成此类序列。这个链接显示了几个:

    http://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1

    例如,您可以使用公用表表达式 (CTE) 来生成序列,如下所示:

    WITH
    s1(n) AS -- 10 (10^1)
      (           SELECT 1
        UNION ALL SELECT 1
        UNION ALL SELECT 1
        UNION ALL SELECT 1
        UNION ALL SELECT 1
        UNION ALL SELECT 1
        UNION ALL SELECT 1
        UNION ALL SELECT 1
        UNION ALL SELECT 1
        UNION ALL SELECT 1
      ) ,
    s2(n)  as ( select 1 from s1 a cross join s1 b ) , -- 10^2       100
    s3(n)  as ( select 1 FROM s1 a cross join s2 b ) , -- 10^3     1,000
    s4(n)  as ( select 1 from s1 a cross join s3 b ) , -- 10^4    10,000
    s5(n)  as ( select 1 from s1 a cross join s4 b ) , -- 10^5   100,000
    s6(n)  as ( select 1 from s1 a cross join s5 b ) , -- 10^6 1,000,000
    seq(n) as ( select row_number() over ( order by n ) from s6 )
    select *
    from dbo.some_table t
    join seq            s on s.n between 1 and len(t.flags)
                         and substring(t.flags,s.n,1) = '1'
    

    【讨论】:

      猜你喜欢
      • 2021-02-18
      • 2023-04-04
      • 2021-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-27
      相关资源
      最近更新 更多