1

I have a string like

Declare @Str varchar (15) = '0123456789' 

and I have a table

CREATE TABLE TableNum(Nums Varchar(1));

How can I insert each number to a separate row?

My output should be

Nums
0
1
2
3
4
.
.
  • 3
    Possible duplicate of [T-SQL Split Word into characters](http://stackoverflow.com/questions/8517816/t-sql-split-word-into-characters) – Fred Apr 27 '17 at 09:52
  • @Fred - The duplicate you refer to is marked as a duplicate of [Split function equivalent in T-SQL?](http://stackoverflow.com/questions/697519/split-function-equivalent-in-t-sql) – Tony Apr 27 '17 at 10:08

6 Answers6

1

Using a numbers table is probably the best and simplest way to do it. If you don't alrady have a numbers table, you can create one:

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Tally
    FROM sys.objects s1
    CROSS JOIN sys.objects s2
ALTER TABLE Tally ADD CONSTRAINT PK_Tally PRIMARY KEY CLUSTERED (Number)

Then all you have to do is simply this:

INSERT INTO TableNum(Nums)
SELECT SUBSTRING(@Str, Number, 1)
FROM Tally
WHERE Number <= LEN(@Str)

For more information on why you want a numbers (or tally) table, read this article by Jeff Moden.

BTW, using varchar(1) makes no sense - use char(1) instead.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
1

Try this : Using CTE you can achieve this, No need to use any joins with existing system tables

;WITH CTE AS(
     SELECT CAST('' AS NVARCHAR(1)) AS CH, 1 AS CNT
     UNION ALL
     SELECT CAST(SUBSTRING(@Str,CNT,1)AS NVARCHAR(1)) AS CH , CNT+1
     FROM CTE 
     WHERE CNT<=LEN(@Str)
)
INSERT INTO TableNum(Nums) 
SELECT CH FROM CTE WHERE CH <> ''
Jaydip Jadhav
  • 12,179
  • 6
  • 24
  • 40
1

If you can't add a tally table (which the way to go as illustrated by Zohar Peled), you can use an ad-hoc tallty table

Declare @Str varchar (15) = '0123456789' 

Select Num=substring(@Str,N,1)
 From (Select Top (Len(@Str)) N=Row_Number() Over (Order By (Select null)) From master..spt_values ) N

Returns

Num
0
1
2
3
4
5
6
7
8
9

Another option is to create a TVF

Declare @Str varchar (15) = '0123456789' 

Select * from [dbo].[udf-Str-Parse-Char](@Str) 

The UDF

CREATE FUNCTION [dbo].[udf-Str-Parse-Char] (@String varchar(max))
Returns Table
As
Return (
    with   cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
           cte2(N) As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From cte1 a,cte1 b,cte1 c,cte1 d,cte1 e,cte1 f)

    Select RetSeq=N
          ,RetVal=Substring(@String,N,1) 
     From  cte2
) 
--Max 1 Million Observations
--Select * from [dbo].[udf-Str-Parse-Char]('this is a string') 
John Cappelletti
  • 79,615
  • 7
  • 44
  • 66
  • 1
    I don't understand people. How come your answer, where you state (in bold font, no less) that mine is better, got an upvote while mine didnt? Don't get me wrong, I think your answer is good, but I can't help but wondering... Well, there. I'm done ranting about it. – Zohar Peled Apr 27 '17 at 10:30
  • @ZoharPeled I actually meant to upvote your answer because I do support the tally table approach. I only offered an altenative if OP can't create a table. That said, some folks never see the true or future value of one approach over another. You can lead a horse to water ... – John Cappelletti Apr 27 '17 at 10:37
  • @ZoharPeled If it makes you feel better http://stackoverflow.com/questions/43654697/check-existence-of-each-character-in-a-string-with-another-string-in-sql/43654762?noredirect=1#comment74357695_43654762 – John Cappelletti Apr 27 '17 at 10:40
1

Try this

DECLARE @Str varchar(10) = '0123456789'
DECLARE @Count INT=1

WHILE @Count <= LEN(@Str)
BEGIN
    INSERT INTO TableNum
    SELECT substring(@Str, @count, 1)  
    SET @Count = @Count + 1
END

and then

SELECT * FROM TabNum
Noor A Shuvo
  • 2,639
  • 3
  • 23
  • 48
1
Declare @Str varchar (15) = '0123456789' 
        ,@pos INT, 
         @result VARCHAR(100); 

   SET @result = @Str; 
   SET @pos = 2 -- location where we want first space 
   WHILE @pos < LEN(@result)+1 
   BEGIN 
       SET @result = STUFF(@result, @pos, 0, SPACE(1)); 
       SET @pos = @pos+2; 

  END
  SELECT @result=REPLACE( @result,' ',',')
  --Print @result
  SELECT   Split.a.value('.', 'VARCHAR(100)') AS Num  
        FROM  
        (
            SELECT   
                 CAST ('<M>' + REPLACE(@result, ',', '</M><M>') + '</M>' AS XML) AS Num  

        ) AS A CROSS APPLY Num.nodes ('/M') AS Split(a)

OutPut

Num
0
1
2
3
4
5
6
7
8
9
1

Try this.

CREATE TABLE TableNum(Nums Varchar(1));
TRUNCATE TABLE TableNum;

Declare @Str varchar (15) = '0123456789';

DECLARE @nLIMIT AS INT = LEN(@Str);
DECLARE @nCounter AS INT = 1;

WHILE @nCounter <= @nLIMIT
BEGIN  

   INSERT INTO TableNum VALUES(SUBSTRING (@Str,@nCounter,1));

   SET @nCounter = @nCounter + 1;
   IF @nCounter > @nLIMIT
         BREAK  
   ELSE  
      CONTINUE  
 END;

SELECT * FROM TableNum;
Ikyong
  • 123
  • 7