在T-SQL中打印给定字符串中逗号的位置

时间:2017-03-24 20:58:09

标签: sql-server tsql while-loop

我想在给定的逗号分隔字符串中打印逗号的位置,但我只是只得到零。

这是我写的代码:

declare @begin int=0
declare @temp int=1
declare @count int=0
declare @Name nvarchar(MAX)='siva,lahsh,dsjhdsd,hjdhjds,ddjhds,yrehrf'
declare @max nvarchar(20)
set @max=len(@Name)-len(replace(@Name,',',''))

create table #table(delimiter int)

while @count>=@max
begin
set @temp=CHARINDEX(',',@Name,@begin)
set @begin=@temp+1
insert into #table(delimiter) values(@temp)
set @count+=1
end
select  delimiter from #table

任何帮助?

3 个答案:

答案 0 :(得分:1)

嗯,你的逻辑在几个地方都错了......这是一个有效的固定版本:

declare @begin int=0
declare @temp int=1
declare @count int=0
declare @Name nvarchar(MAX)='siva,lahsh,dsjhdsd,hjdhjds,ddjhds,yrehrf'
declare @max nvarchar(20)
set @max=len(@Name)

IF OBJECT_ID('tempdb..#table') IS NOT NULL DROP TABLE #table 
create table #table(delimiter int)

while CHARINDEX(',',@Name,@begin) > 0
begin
set @temp=CHARINDEX(',',@Name,@begin)
set @begin=@temp+1
insert into #table(delimiter) values(@temp)
set @count+=1
end
select  delimiter from #table

基本上,你的循环控制完全关闭,你的@max初始化也是如此。你甚至不需要" max",但我只是对你的代码进行了调整,这样你就可以看到改变了什么。我会把它留作练习来进一步优化它。

当然,我不确定你为什么要这样做......对于我能想到的任何合理问题,似乎没有任何合理的解决办法。也许你可以提供更多关于你真正想要做什么的细节......

答案 1 :(得分:1)

使用Jeff Moden和var selections = $("#primaryModal").find("select").not(".hidden"); for(var i = 0; i < selections.length; i++){ console.log(selections.length); console.log("select"); for(var j = 0; j < $(selections)[i].options.length; j++){ console.log("option"); } } 的CSV Splitter表值函数来求解解析值+1的长度以报告分隔符位置:

sum() over()

rextester 演示http://rextester.com/BXD20065

返回:

declare @Name nvarchar(MAX)='siva,lahsh,dsjhdsd,hjdhjds,ddjhds,yrehrf';

select s.*
  , Delimiter = sum(len(Item)+1) over (order by ItemNumber)
from dbo.delimitedsplitN4K(@Name,',') s

拆分字符串参考:

+------------+---------+-----------+
| ItemNumber |  Item   | Delimiter |
+------------+---------+-----------+
|          1 | siva    |         5 |
|          2 | lahsh   |        11 |
|          3 | dsjhdsd |        19 |
|          4 | hjdhjds |        27 |
|          5 | ddjhds  |        34 |
|          6 | yrehrf  |        41 | <-- 41 is not a comma, but it is the end of the string+1
+------------+---------+-----------+

答案 2 :(得分:0)

要考虑的一些事项......

首先 - 如果您不需要@name为nvarchar(max),则应将其更改为nvarchar(4000)。 nvarchar(max)会杀死性能(Jeff实际上在其函数的注释部分中包含了这个)。如果你有超过4000的字符串 - 那么解决方案SqlZim发布将是错误的。

虽然我喜欢Jeff Moden的分裂器,但它不适合这项工作。 SqlZim的解决方案将是非常低效的,正如他所指出的,返回一个坏行(没有廉价的解决方法的问题。)使用循环和放大器来解决这个问题。临时表更糟糕。

我有一个专门为这类事物设计的功能。我今晚刚刚为这个问题创建了一个nvarchar(4000)版本。你可以在这里读更多关于它的内容。 Nasty Fast N-Grams (Part 1): Character-Level Unigrams

这是我刚刚完成开发的nvarchar(4000)版本:

CREATE FUNCTION dbo.NGramsN4K
(
  @string nvarchar(4000), -- Input string
  @N      int             -- requested token size
)
/****************************************************************************************
Purpose:
 A character-level N-Grams function that outputs a contiguous stream of @N-sized tokens 
 based on an input string (@string). Accepts strings up to 4000 nvarchar characters long.
 For more information about N-Grams see: http://en.wikipedia.org/wiki/N-gram. 

Compatibility: 
 SQL Server 2008+, Azure SQL Database

Syntax:
--===== Autonomous
 SELECT position, token FROM dbo.NGramsN4K(@string,@N);

--===== Against a table using APPLY
 SELECT s.SomeID, ng.position, ng.token
 FROM dbo.SomeTable s
 CROSS APPLY dbo.NGramsN4K(s.SomeValue,@N) ng;

Parameters:
 @string  = The input string to split into tokens.
 @N       = The size of each token returned.

Returns:
 Position = bigint; the position of the token in the input string
 token    = nvarchar(4000); a @N-sized character-level N-Gram token

Developer Notes:  
 1. NGramsN4K is not case sensitive

 2. Many functions that use NGramsN4K will see a huge performance gain when the optimizer
    creates a parallel execution plan. One way to get a parallel query plan (if the 
    optimizer does not chose one) is to use make_parallel by Adam Machanic which can be 
    found here:
 sqlblog.com/blogs/adam_machanic/archive/2013/07/11/next-level-parallel-plan-porcing.aspx

 3. When @N is less than 1 or greater than the datalength of the input string then no 
    tokens (rows) are returned. If either @string or @N are NULL no rows are returned.
    This is a debatable topic but the thinking behind this decision is that: because you
    can't split 'xxx' into 4-grams, you can't split a NULL value into unigrams and you 
    can't turn anything into NULL-grams, no rows should be returned.

    For people who would prefer that a NULL input forces the function to return a single
    NULL output you could add this code to the end of the function:

    UNION ALL 
    SELECT 1, NULL
    WHERE NOT(@N > 0 AND @N <= DATALENGTH(@string)) OR (@N IS NULL OR @string IS NULL);

 4. NGramsN4K is deterministic. For more about deterministic functions see:
    https://msdn.microsoft.com/en-us/library/ms178091.aspx

Usage Examples:
--===== Turn the string, 'abcd' into unigrams, bigrams and trigrams
 SELECT position, token FROM dbo.NGramsN4K('abcd',1); -- unigrams (@N=1)
 SELECT position, token FROM dbo.NGramsN4K('abcd',2); -- bigrams  (@N=2)
 SELECT position, token FROM dbo.NGramsN4K('abcd',3); -- trigrams (@N=3)

--===== How many times the substring "AB" appears in each record
 DECLARE @table TABLE(stringID int identity primary key, string nvarchar(100));
 INSERT @table(string) VALUES ('AB123AB'),('123ABABAB'),('!AB!AB!'),('AB-AB-AB-AB-AB');

 SELECT string, occurances = COUNT(*) 
 FROM @table t
 CROSS APPLY dbo.NGramsN4K(t.string,2) ng
 WHERE ng.token = 'AB'
 GROUP BY string;

----------------------------------------------------------------------------------------
Revision History:
 Rev 00 - 20170324 - Initial Development - Alan Burstein
****************************************************************************************/
RETURNS TABLE WITH SCHEMABINDING AS RETURN
WITH
L1(N) AS
(
  SELECT 1 FROM (VALUES -- 64 dummy values to CROSS join for 4096 rows
        ($),($),($),($),($),($),($),($),($),($),($),($),($),($),($),($),
        ($),($),($),($),($),($),($),($),($),($),($),($),($),($),($),($),
        ($),($),($),($),($),($),($),($),($),($),($),($),($),($),($),($),
        ($),($),($),($),($),($),($),($),($),($),($),($),($),($),($),($)) t(N)
),
iTally(N) AS 
(
  SELECT 
  TOP (ABS(CONVERT(BIGINT,((DATALENGTH(ISNULL(@string,''))/2)-(ISNULL(@N,1)-1)),0)))
    ROW_NUMBER() OVER (ORDER BY (SELECT NULL))    -- Order by a constant to avoid a sort
  FROM L1 a CROSS JOIN L1 b                       -- cartesian product for 4096 rows (16^2)
)
SELECT
  position = N,                                   -- position of the token in the string(s)
  token    = SUBSTRING(@string,CAST(N AS int),@N) -- the @N-Sized token
FROM iTally
WHERE @N > 0 AND @N <= (DATALENGTH(@string)/2);       -- Protection against bad parameter values
GO

...现在进行快速的1行测试(打开实际执行计划):

SET NOCOUNT ON;

declare @Name nvarchar(MAX)='siva,lahsh,dsjhdsd,hjdhjds,ddjhds,yrehrf';

-- comparing IO:
SET STATISTICS IO ON;

  --NGramsN4K
  PRINT 'NGramsN4K:'+char(13)+char(10)+replicate('-',50)+char(13)+char(10)+char(13)+char(10);
  SELECT position 
  FROM dbo.NGramsN4K(@name,1)
  WHERE token = ',';

  --delimitedsplitN4K
  PRINT 'delimitedsplitN4K-based solution'+char(13)+char(10)+replicate('-',50);
  select Delimiter = sum(len(Item)+1) over (order by ItemNumber)
from dbo.delimitedsplitN4K(@Name,',') s;
SET STATISTICS IO OFF;

结果:

position
--------------------
5
11
19
27
34


Delimiter
-----------
5
11
19
27
34
41

计划: enter image description here

...和IO统计数据:

NGramsN4K:
--------------------------------------------------

delimitedsplitN4K-based solution
--------------------------------------------------
Table 'Worktable'. Scan count 7, logical reads 37, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

一行37次读取非常糟糕。