web-dev-qa-db-fra.com

Comment convertir NVARCHAR séparé par des virgules en enregistrements de table dans SQL Server 2005?

J'ai une liste d'identifiants séparés par des virgules comme:

 1,17,25,44,46,67,88

Je veux les convertir en enregistrements de table (en table temporaire) comme

#tempTable

number_
--------
1
17
25
44
46
67
88

C’est possible avec une fonction, une table?

Pourquoi je veux ça? Je souhaite utiliser la clause INNER JOIN (dans la procédure stockée) avec une ou plusieurs autres tables, par exemple:

SELECT a,b,c FROM T1
INNER JOIN functionNameWhichReturnsTable 
ON functionNameWhichReturnsTable.number_ = T1.a

Je ne peux pas utiliser IN car je vais utiliser une procédure stockée qui accepte un paramètre de type NVARCHAR. Ce paramètre fournira la liste des identifiants.

Je vous remercie

12
Snake Eyes

Doublage possible de séparer les valeurs séparées par des virgules et stocker dans une table dans le serveur SQL

Veuillez essayer une valeur précise de Valeur délimitée par des virgules dans le tableau :

CREATE FUNCTION [dbo].[ufn_CSVToTable] ( @StringInput VARCHAR(8000), @Delimiter nvarchar(1))
RETURNS @OutputTable TABLE ( [String] VARCHAR(10) )
AS
BEGIN

    DECLARE @String    VARCHAR(10)

    WHILE LEN(@StringInput) > 0
    BEGIN
        SET @String      = LEFT(@StringInput, 
                                ISNULL(NULLIF(CHARINDEX(@Delimiter, @StringInput) - 1, -1),
                                LEN(@StringInput)))
        SET @StringInput = SUBSTRING(@StringInput,
                                     ISNULL(NULLIF(CHARINDEX(@Delimiter, @StringInput), 0),
                                     LEN(@StringInput)) + 1, LEN(@StringInput))

        INSERT INTO @OutputTable ( [String] )
        VALUES ( @String )
    END

    RETURN
END
GO

Vérifiez l'exigence d'une autre manière en utilisant XML:

DECLARE @param NVARCHAR(MAX)
SET @param = '1:0,2:1,3:1,4:0'

SELECT 
     Split.a.value('.', 'VARCHAR(100)') AS CVS  
FROM  
(
    SELECT CAST ('<M>' + REPLACE(@param, ',', '</M><M>') + '</M>' AS XML) AS CVS 
) AS A CROSS APPLY CVS.nodes ('/M') AS Split(a)
23
TechDo

La méthode que j'ai trouvée ne nécessite aucune fonction ni astuce XML.

En gros, vous transformez la chaîne en une seule instruction d'insertion pour la table temporaire.
.__ qui peut ensuite être utilisé pour un traitement ultérieur.

IF OBJECT_ID('tempdb..#tempTable') IS NOT NULL DROP TABLE #tempTable;
CREATE TABLE #tempTable (number int);

DECLARE @TEXT varchar(max) = '1,17,25,44,46,67,88';

DECLARE @InsertStatement varchar(max) = 'insert into #tempTable values ('+REPLACE(@TEXT,',','),(')+');';
EXEC (@InsertStatement);

SELECT * FROM #tempTable;

Cette méthode est utilisable pour 1000 valeurs maximum.
Parce que 1000 est la limite maximale d'une expression de valeur de ligne.
Ou jusqu'à ce que la limite de varchar pour le @InsertStatement soit atteinte.

En outre, comme l'a souligné Stuart Ainsworth.
Comme cette méthode utilise EXEC, méfiez-vous de l’injection de code et ne l’utilisez pas pour les chaînes basées sur une entrée utilisateur non vérifiée.

2
LukStorms

Essayez ce code 

 SELECT RTRIM(part) as part
    INTO Table_Name
        FROM dbo.splitstring(@Your_Comma_string,',')

la fonction splitstring est la suivante

CREATE FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) )
RETURNS
 @returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN

 DECLARE @name NVARCHAR(255)
 DECLARE @pos INT

 WHILE CHARINDEX(',', @stringToSplit) > 0
 BEGIN
  SELECT @pos  = CHARINDEX(',', @stringToSplit)  
  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
 END

 INSERT INTO @returnList
 SELECT @stringToSplit

 RETURN
END
0
Akshay Mishra

En complétant les réponses, vous pouvez également utiliser la chaîne CSV pour stocker plusieurs valeurs dans plusieurs colonnes:

 --input sql text 
declare @text_IN varchar(max) ='text1, text1.2, text1.3, 1, 2010-01-01\r\n text2, text2.2, text2.3, 2, 2016-01-01'

Divisez le fichier csv en lignes:

declare @temptable table (csvRow varchar(max))    
declare @DelimiterInit varchar(4) = '\r\n'
declare @Delimiter varchar(1) = '|'
declare @idx int       
declare @slice varchar(max)    

set @text_IN = REPLACE(@text_IN,@DelimiterInit,@Delimiter)


select @idx = 1       
    if len(@text_IN)<1 or @text_IN is null  return       

while @idx!= 0       
begin       
    set @idx = charindex(@Delimiter,@text_IN)       
    if @idx!=0       
        set @slice = left(@text_IN,@idx - 1)       
    else       
        set @slice = @text_IN 

    if(len(@slice)>0)  
        insert into @temptable(csvRow) values(@slice)       

    set @text_IN = right(@text_IN,len(@text_IN) - @idx)       
    if len(@text_IN) = 0 break       
end   

Fractionner les lignes en colonnes:

;WITH XMLTable (xmlTag)
AS
(
    SELECT CONVERT(XML,'<CSV><champ>' + REPLACE(csvRow,',', '</champ><champ>') + '</champ></CSV>') AS xmlTag
    FROM @temptable
)

 SELECT RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[1]','varchar(max)'))) AS Column1,    
        RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[2]','varchar(max)'))) AS Column2,
        RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[3]','varchar(max)'))) AS Column3,    
        RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[4]','int'))) AS Column4,
        RTRIM(LTRIM(xmlTag.value('/CSV[1]/champ[5]','datetime'))) AS Column5
 FROM XMLTable
0
Candous

Les oeuvres suivantes: 

declare @parStoreNo As varchar(8000) = '1,2,3,4'        
CREATE TABLE #parStoreNo (StoreNo INT)-- drop #parStoreNo
declare @temptable VARCHAR(1000) = @parStoreNo
declare @SQL VARCHAR(1000) 
SELECT @SQL = CONVERT(VARCHAR(1000),' select ' + REPLACE(ISNULL(@temptable,' NULL '),',', ' AS Col UNION ALL SELECT ')) 
INSERT #parStoreNo (StoreNo)
EXEC (@SQL)
0
Petrus Norlin