抓取每一行的数据并将其设置为变量-TSQL

时间:2019-03-27 17:25:46

标签: sql-server tsql

我正在尝试创建一个循环,该循环将拉出一行的一个值并将其存储到变量(@nameString)中。我需要在行数未知的情况下发生这种情况。当我需要此循环来循环遍历所有行并在每次循环使用下一行值时更新变量时,我应该指的是什么。

我已经尝试了一些计数器循环,但是它们并没有遍历它们一直命中同一行的行。

-- Code for parsing a name with multiple parts

DECLARE     @nameString as varchar(max),
            @firstSpaceLoc as smallint,
            @secondSpaceLoc as smallint,
            @thirdSpaceLoc as smallint,
            @firstString as varchar(max),
            @secondString as varchar(max),
            @thirdString as varchar(max) 

-- I'm expecting the loop to be below here!
SET @nameString = 'Robert Dobson, Jr.'
--SET @nameString = 'Robert William Dobson, Sr.'

-- How many strings are in the name?
-- Is there one space in the name
SET @firstSpaceLoc = CHARINDEX(' ',@namestring,1)

-- Is there second space in the name
SET @secondSpaceLoc = CHARINDEX(' ', @namestring, CHARINDEX('     ',@nameString,1)+1)

-- Is there a third space in the name
SET @thirdSpaceLoc = 
CASE
      WHEN CHARINDEX(' ', @namestring, 
           CHARINDEX(' ',@nameString,1)+1) = 0 THEN 0
      WHEN CHARINDEX(' ', @namestring, 
           CHARINDEX(' ',@nameString,1)+1) > 0 THEN
           CHARINDEX(' ', @namestring, 
           CHARINDEX(' ', @namestring, 
           CHARINDEX(' ',@nameString,1)+1)+1)
END

SELECT
            @nameString sourceString,
            CASE 
                        WHEN @firstSpaceLoc > 0 THEN 'There is one space'
                        ELSE 'There is not one space'
            END [Is there one space],
            CASE 
                        WHEN @secondSpaceLoc > 0 THEN 'There is a second     space'
                        ELSE 'There is not a second space'
            END [Is there a second space],
            CASE 
                        WHEN @thirdSpaceLoc > 0 THEN 'There is a third space'
                        ELSE 'There is not a third space'
            END [Is there a third space]


-- extract and save strings
SELECT

@firstString = 
       CASE
            WHEN @firstSpaceLoc > 0 THEN LEFT(@nameString,CHARINDEX('     ',@namestring,1)-1)
            ELSE @nameString
       END,
       @secondString =   
       CASE
            WHEN @firstSpaceLoc = 0 THEN ''
            WHEN @secondSpaceLoc = 0 THEN 
                        RIGHT(@namestring, LEN(@namestring)- CHARINDEX('     ',@namestring,1))
            WHEN @secondSpaceLoc > 0 THEN
                        REPLACE     (
                        SUBSTRING   (
                                       @nameString, 
                                       CHARINDEX(' ',@namestring,1)+1, 
                                       CHARINDEX(' ', @namestring, 
                                       CHARINDEX(' ',@nameString,1)+1) 
                                             - CHARINDEX(' ',@namestring,1)
                                     ),
                                     ',',
                                     ''
                                     )
            ELSE ''
      END,
      @thirdString =
      CASE
            WHEN @firstSpaceLoc = 0 OR @secondSpaceLoc = 0  THEN ''
            WHEN @secondSpaceLoc > 0 
                        AND @thirdSpaceLoc = 0 THEN
                        SUBSTRING   (
                                       @nameString,
                                       CHARINDEX(' ', @namestring, 
                                       CHARINDEX(' ',@nameString,1)+1)+1,
                                       LEN(@nameString)
                                     )     
            ELSE RIGHT(@namestring,LEN(@namestring) - @secondSpaceLoc)              
      END


-- Report names
SELECT
            @nameString sourceString,
            @firstString [First string],
            @secondString [Second string],
            @thirdString [Third string]

SELECT
        CASE
                  WHEN @thirdSpaceLoc > 0 THEN 
                                    @thirdString + ', '  + @firstString + ' '     + @secondString
                  WHEN @secondSpaceLoc > 0 AND @thirdSpaceLoc = 0 THEN 
                                    @secondString + ' '  + @thirdString + ',     ' + @firstString
                  WHEN @firstSpaceLoc > 0 THEN 
                                    @secondString + ', '  + @firstString 
                  WHEN @firstSpaceLoc = 0 THEN 
                                    @firstString
            END [Reported Name]

期望的结果是,这会遍历并将具有多个空格的列中的每一行分隔为一长串的名称,这些名称被分隔开。该列表但是更长。enter image description here

3 个答案:

答案 0 :(得分:0)

您可以这样尝试吗:

DECLARE     @nameString AS VARCHAR(MAX),                
            @firstString AS VARCHAR(MAX),
            @secondString AS VARCHAR(MAX),
            @thirdString AS VARCHAR(MAX) 

SET @nameString = 'Robert Dobson, Jr.'

DECLARE @tbl TABLE
(
    Id INT IDENTITY(1,1),
    Name VARCHAR(MAX)
)

INSERT INTO @tbl(Name)
SELECT value FROM STRING_SPLIT(@nameString, ' ');


SELECT @firstString = Name FROM @tbl WHERE Id = 1
SELECT @secondString = Name FROM @tbl WHERE Id = 2
SELECT @thirdString = Name FROM @tbl WHERE Id = 3


SELECT
@nameString sourceString,
CASE WHEN LEN(@firstString) > 0 THEN 'There is one space'
            ELSE 'There is not one space'
END [Is there one space],
CASE WHEN LEN(@secondString)> 0 THEN 'There is a second     space'
            ELSE 'There is not a second space'
END [Is there a second space],
CASE WHEN LEN(@thirdString)> 0 THEN 'There is a third space'
            ELSE 'There is not a third space'
END [Is there a third space]

SELECT @nameString SourceString, @firstString [First string], @secondString [Second string] , @thirdString [Third string]

SELECT
    CASE
        WHEN LEN(@thirdString) > 0 THEN 
                        @thirdString + ', '  + @firstString + ' '     + @secondString
        WHEN LEN(@secondString) > 0 AND LEN(@thirdString) = 0 THEN 
                        @secondString + ' '  + @thirdString + ',     ' + @firstString
        WHEN LEN(@firstString) > 0 THEN 
                        @secondString + ', '  + @firstString 
        WHEN LEN(@firstString) = 0 THEN 
                        @firstString
        END [Reported Name]

答案 1 :(得分:0)

很抱歉,如果代码中存在某些错误,我已经无法直接访问MS-SQL,因此我尝试直接在此处进行编码。 您的请求是非常不寻常的(我同意罗伯特的评论),但是像这样的简单代码将起作用。

DECLARE    @nameString as varchar(max),
           @firstString as varchar(max),
           @secondString as varchar(max),
           @thirdString as varchar(max)

SET @nameString = 'Robert Dobson, Jr.'

SET @thirdString = REPLACE(@nameString, ',', '')
SET @firstString = LTRIM(SUBSTRING(@thirdString, 1, CHARINDEX(' ', @thirdString)))
SET @thirdString = LTRIM(REPLACE(@thirdString, @firstString, ‘’))
SET @secondString = LTRIM(SUBSTRING(@thirdString, 1, CHARINDEX(' ', @thirdString)))
SET @thirdString = LTRIM(REPLACE(@thirdString, @secondString, ‘’))

SELECT
            @nameString sourceString,
            @firstString [First string],
            @secondString [Second string],
            @thirdString [Third string]

答案 2 :(得分:0)

我假设您需要它来基于nameString中发现的空格数返回动态的列数。我在系统上使用了一些您需要的东西才能使它正常工作。

首先是理货单。我将一个放在我的系统上作为视图。这是我用于此的代码。理货表是帮助我们避免使用循环的好工具。您可以阅读有关here的更多信息。

create View [dbo].[cteTally] as

WITH
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
    cteTally(N) AS 
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
    )
select N from cteTally

我们接下来需要的是一个字符串拆分器。其中有很多,甚至在最新版本的sql server中都内置了一个。然而,即使是MS,也错过了每个元素序数位置的关键元素。幸运的是,杰夫·摩登(Jeff Moden)有一个基于设置的闪电般快速,并返回每个元素的位置编号。

您可以找到DelimitedSplit8K here的代码。

现在,我们面临着返回动态列数的挑战。为此,您可以使用动态枢轴。那会很好。对我来说,我发现将数据透视表的语法变得非常钝,并且更喜欢使用条件聚合或交叉表。在这种情况下,它必须是动态的。

我在示例中创建了一个临时表来代表您的表。我在列表中添加了一些其他名称,其中一些具有3个以上的字符串。

if OBJECT_ID('tempdb..#Something') is not null
    drop table #Something

create table #Something --this represents your current table
(
    nameString varchar(100)
)

insert #Something values
('Robert Dobson, Jr.')
, ('NeoAer')
, ('Ryan Wilson')
, ('Somebody with four names')
, ('another with yet more names')

declare @StaticPortion nvarchar(2000) = 
    'with OrderedResults as
    (
        select nameString
            , stringValue = replace(x.Item, '','', '''')
            , x.ItemNumber
        from #Something s
        cross apply dbo.DelimitedSplit8K(s.nameString, '' '') x
    )
    select nameString';

declare @DynamicPortion nvarchar(max) = '';
declare @FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by nameString order by nameString';

select @DynamicPortion = @DynamicPortion + 
    ', MAX(Case when ItemNumber = ' + CAST(N as varchar(6)) + ' then stringValue end) as string' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <= 
(
    select top 1 Count(*)
    from #Something s
    cross apply dbo.DelimitedSplit8K(s.nameString, ' ') x
    group by nameString
    order by COUNT(*) desc
)

select @StaticPortion + @DynamicPortion + @FinalStaticPortion

--once you are satisfied that the dynamic sql is correct uncomment the next two lines to execute it.
--declare @SqlToExecute nvarchar(max) = @StaticPortion + @DynamicPortion + @FinalStaticPortion;
--exec sp_executesql @SqlToExecute

如果您不这样做就返回动态的列数,我们可以采用类似的查询类型,但是要简单得多。