【问题标题】:Implementing and applying a string split in T-SQL在 T-SQL 中实现和应用字符串拆分
【发布时间】:2009-04-15 20:33:40
【问题描述】:

我在 T-SQL 中有这个语句。

SELECT Bay From TABLE where uid in (
    select B_Numbers from Info_Step WHERE uid = 'number'
)

我从TABLE 中选择“多个”BAYs,其中他们的uid 等于这样的一串数字:

B_Numbers = 1:45:34:98

因此,我应该从 TABLE 中选择 4 个不同的 BAYs。我基本上需要将字符串 1:45:34:98 拆分为 4 个不同的数字。

我认为 Split() 会起作用,但它不起作用,我得到一个语法错误。 T-SQL 大神们的任何想法都会很棒!

【问题讨论】:

    标签: tsql select split


    【解决方案1】:

    这是一个拆分函数的实现,它以表格形式返回数字列表:

    http://rbgupta.blogspot.com/2007/03/split-function-tsql.html

    看起来这会让你上路……

    【讨论】:

      【解决方案2】:

      这是一种使用辅助数字表来解析输入字符串的方法。可以轻松地将逻辑添加到返回表的函数中。然后可以连接该表以查找正确的行。

      第 1 步:创建数字表

      SET NOCOUNT ON
      GO
      
      IF EXISTS
      (
          SELECT  1
          FROM    INFORMATION_SCHEMA.TABLES
          WHERE       TABLE_NAME  = 'Numbers'
                  AND     TABLE_SCHEMA    = 'dbo'
                  AND     TABLE_TYPE  = 'BASE TABLE'
      )
      BEGIN
          DROP TABLE dbo.Numbers
      END
      GO
      
      CREATE TABLE dbo.Numbers
      (
          Number smallint  IDENTITY(1, 1) PRIMARY KEY
      )
      GO
      
      WHILE 1 = 1
      BEGIN
          INSERT INTO dbo.Numbers DEFAULT VALUES
      
          IF SCOPE_IDENTITY() = 32767 
          BEGIN
              BREAK
          END
      END
      GO
      

      第 2 步:解析输入字符串

      CREATE FUNCTION dbo.ParseString(@input_string varchar(8000), @delim varchar(8000) = " ")
      RETURNS TABLE
      AS RETURN
      (
          SELECT Number 
          FROM dbo.Numbers
          WHERE CHARINDEX 
          ( 
              @delim + CONVERT(VARCHAR(12),Number) + @delim, 
              @delim + @input_string + @delim 
          ) > 0 
      )
      GO
      
      **EXAMPLE**
      SELECT * FROM dbo.ParseString('1:45:34:98',':')
      

      第 3 步:使用您想要/需要的结果

      Number
      ------
      1
      34
      45
      98
      

      端到端示例

      创建返回适当 BNumber 的函数(当然更改它以使用注释掉的 SQL)

      SET ANSI_NULLS ON
      GO
      SET QUOTED_IDENTIFIER ON
      GO
      CREATE FUNCTION dbo.GetBNumber (@uid int)
      RETURNS VARCHAR(8000) 
      AS
      BEGIN
          RETURN '1:45:34:98'
          --select B_Numbers from Info_Step WHERE uid = @uid
      END
      GO
      

      使用使用函数返回想要的结果

      -- Using Test Data
      SELECT N.Number FROM Numbers N
      JOIN dbo.ParseString(dbo.GetBNumber(12345),':') Q ON Q.Number = N.Number
      
      -- Using Your Data (Untested but should work.)
      SELECT N.Bay
      FROM TABLE N
      JOIN dbo.ParseString(dbo.GetBNumber(ENTER YOU NUMBER HERE),':') Q ON Q.Number = N.uid
      

      结果

      Number
      ------
      1
      34
      45
      98
      

      【讨论】:

        【解决方案3】:

        您应该将数组保留为行,但如果我理解您的问题,我认为这会起作用。

        SELECT 
            Bay 
        
        From 
            TABLE
            join  Info_Step 
            on B_Numbers like '%'+ uid  +'%'
        
        where 
            Info_Step.uid = 'number'
        

        由于 like 运算符,此查询将执行全表扫描。

        【讨论】:

        • 这不起作用,因为输入字符串需要分成标记(4 个不同的行),然后将表连接在一起。您的方法将尝试找到像“.....1:45:34:98.....”这样的 UID,但事实并非如此,因为 UID 可能是一个整数。
        【解决方案4】:

        您可以做的是遍历B_Numbers 条目并在: 上进行自己的拆分将这些条目插入到临时表中,然后执行您的查询。

        DECLARE @i             int
        DECLARE @start         int
        DECLARE @B_Numbers     nvarchar(20)
        DECLARE @temp          table (
            number nvarchar(10)
        )
        
        -- SELECT B_Numbers FROM Info_Step WHERE uid = 'number'
        SELECT @B_Numbers = '1:45:34:98'
        
        SET @i = 0
        SET @start = 0
        
        -- Parse out characters delimited by ":";  
        -- Would make a nice user defined function.
        WHILE @i < len(@B_Numbers)
        BEGIN
            IF substring(@B_Numbers, @i, 1) = ':'
            BEGIN
                INSERT INTO @temp
                VALUES (substring(@B_Numbers, @start, @i - @start))
                SET @start = @i + 1
            END
        
            SET @i = @i + 1
        END
        
        -- Insert last item
        INSERT INTO @temp
        VALUES (substring(@B_Numbers, @start, @i - @start + 1))
        
        -- Do query with parsed values
        SELECT Bay FROM TABLE WHERE uid in (SELECT * FROM @temp)
        

        【讨论】:

          【解决方案5】:

          你甚至可以试试这个

          declare @str varchar(50)
          set @str = '1:45:34:98'
          
          ;with numcte as(
          select 1 as rn union all select rn+1 from numcte where rn<LEN(@str)),
          getchars as(select 
          ROW_NUMBER() over(order by rn) slno,
          rn,chars from numcte 
          cross apply(select SUBSTRING(@str,rn,1) chars)X where chars = ':') 
          
          select top 1 
              Bay1 = SUBSTRING(@str,0,(select rn from getchars where slno = 1)) 
              ,Bay2 = SUBSTRING(@str,
                      (select rn from getchars where slno = 1) + 1,
                      (((select rn from getchars where slno = 2)-
                      (select rn from getchars where slno = 1)
                      )-1))
              ,Bay3 = SUBSTRING(@str,
                      (select rn from getchars where slno = 2) + 1,
                      (((select rn from getchars where slno = 3)-
                      (select rn from getchars where slno = 2)
                      )-1))
              ,Bay4 = SUBSTRING(@str,
                      (select rn from getchars where slno = 3)+1,
                      LEN(@str))
              from getchars 
          

          输出:

          Bay1    Bay2    Bay3    Bay4
          1   45  34  98
          

          【讨论】:

            猜你喜欢
            • 2021-06-23
            • 1970-01-01
            • 2014-03-13
            • 1970-01-01
            • 2011-07-03
            • 1970-01-01
            • 1970-01-01
            • 2015-03-11
            • 2021-08-26
            相关资源
            最近更新 更多