9
votes

Créez une table des colonnes CSV dans SQL Server sans utiliser de curseur

Compte tenu d'une table:

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Split]') and xtype in (N'FN', N'IF', N'TF')) drop function [dbo].Split
go
CREATE FUNCTION dbo.Split (@sep char(1), @s varchar(512))
RETURNS table
AS
RETURN (
    WITH Pieces(pn, start, stop) AS (
      SELECT 1, 1, CHARINDEX(@sep, @s)
      UNION ALL
      SELECT pn + 1, stop + 1, CHARINDEX(@sep, @s, stop + 1)
      FROM Pieces
      WHERE stop > 0
    )
    SELECT pn,
      SUBSTRING(@s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
    FROM Pieces
  )


go

declare @inputtable table (
    name varchar(200) not null,
    hobbies varchar(200) not null
)

declare @outputtable table (
    name varchar(200) not null,
    hobby varchar(200) not null
)

insert into @inputtable values('Joe', 'Eating,Running,Golf')
insert into @inputtable values('Dafydd', 'Swimming,Coding,Gaming')

select * from @inputtable

declare inputcursor cursor for
select name, hobbies
from @inputtable

open inputcursor

declare @name varchar(255), @hobbiescsv varchar(255)
fetch next from inputcursor into @name, @hobbiescsv
while(@@FETCH_STATUS <> -1) begin

    insert into @outputtable
    select @name, splithobbies.s
    from dbo.split(',', @hobbiescsv) splithobbies

    fetch next from inputcursor into @name, @hobbiescsv 
end
close inputcursor
deallocate inputcursor

select * from @outputtable


2 commentaires

Même si dans votre exemple, chaque personne a exactement trois hobbies, je suppose que chaque personne peut réellement avoir 1 hobbies ou plus?


@LittlebbobbobbobbobbobbobbobbobbobbyTables Oui, j'aurais dû mentionner la liste des passe-temps peut être de longueur arbitraire


4 Réponses :


9
votes

Utilisez une fonction d'analyse de chaîne comme celle trouvée ici . La clé est d'utiliser Cross Appliquer pour exécuter la fonction pour chaque ligne de votre table de base .

CREATE FUNCTION [dbo].[fnParseStringTSQL] (@string NVARCHAR(MAX),@separator NCHAR(1))
RETURNS @parsedString TABLE (string NVARCHAR(MAX))
AS 
BEGIN
   DECLARE @position int
   SET @position = 1
   SET @string = @string + @separator
   WHILE charindex(@separator,@string,@position) <> 0
      BEGIN
         INSERT into @parsedString
         SELECT substring(@string, @position, charindex(@separator,@string,@position) - @position)
         SET @position = charindex(@separator,@string,@position) + 1
      END
     RETURN
END
go

declare @MyTable table (
    Name char(10),
    Hobbies varchar(100)
)

insert into @MyTable
    (Name, Hobbies)
    select 'Joe', 'Eating,Running,Golf'
    union all
    select 'Dafydd', 'Swimming,Coding,Gaming'

select t.Name, p.String
    from @mytable t
        cross apply dbo.fnParseStringTSQL(t.Hobbies, ',') p

DROP FUNCTION [dbo].[fnParseStringTSQL]


0 commentaires

4
votes

Créez cette fonction dans votre DB:

Select t.Name, 
       s.items as 'Hobby'
from dbo.MyTable as t
Cross Apply dbo.Split(t.Hobbies,',') as s 


3 commentaires

Nopers. Vous devez être applicable ou externe appliquer un TVF.


@Denis - Merci Denis. J'ai oublié que je traitais avec la table de table là-bas. Mise à jour ma réponse maintenant.


Merci, cross s'appliquer est ce que j'étais après! Fera encore une lecture sur cela maintenant



4
votes

Faites simplement ce qui suit:

select *
from @inputtable
outer apply dbo.split(',', hobbies) splithobbies


4 commentaires

Il n'y a pas de fonction native "Split" dans SQL Server (qui aspire).


@Philip La réponse est donnée dans le contexte de la question. Avez-vous vu qu'il y a déjà une fonction de scission mise en œuvre au tout début de la question? Donc, ça va.


est correct, l'application extérieure est la partie dont je devais savoir afin que cette réponse soit parfaitement valide.


Assez juste. Je viens de lire l'intro impliquant qu'il s'agissait d'une solution de boucle à base de curseur typique, a vu les fonctions de scission postées par tous les autres, et supposait que c'était comme toutes les autres questions d'analyse de la chaîne publiées. Hélas, les votes (bas ou autrement) ne peuvent pas être inversés à moins que la réponse originale soit modifiée; Si vous (ajoutez un espace, changez de ponctuation), je vais l'inverser.



0
votes

Je préfère généralement utiliser xml pour scinder la liste CSV sur le format de la valorisation de la table. Vous pouvez vérifier cette fonction: xxx

et le suivant article pour plus de techniques montrant comment faire cela. Ensuite, il vous suffit d'utiliser la clause appliquer pour appliquer la fonction.


0 commentaires