我正在尝试创建一个循环,该循环将拉出一行的一个值并将其存储到变量(@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]
答案 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
如果您不这样做就返回动态的列数,我们可以采用类似的查询类型,但是要简单得多。