web-dev-qa-db-fra.com

SQL Server convertir sélectionnez une colonne et convertissez-la en chaîne

Est-il possible d'écrire une instruction qui sélectionne une colonne d'une table et convertit les résultats en une chaîne?

Idéalement, je voudrais avoir des valeurs séparées par des virgules.

Par exemple, supposons que l'instruction SELECT ressemble à quelque chose

SELECT column
FROM table
WHERE column<10

et le résultat est une colonne avec des valeurs

|column|
--------
|  1   |
|  3   |
|  5   |
|  9   |

Je veux par conséquent la chaîne "1, 3, 5, 9"

20
eddy ed

Vous pouvez le faire comme ceci:

Démo Fiddle

declare @results varchar(500)

select @results = coalesce(@results + ',', '') +  convert(varchar(12),col)
from t
order by col

select @results as results

| RESULTS |
-----------
| 1,3,5,9 |
51
Kaf
select  stuff(list,1,1,'')
from    (
        select  ',' + cast(col1 as varchar(16)) as [text()]
        from    YourTable
        for     xml path('')
        ) as Sub(list)

Exemple avec SQL Fiddle.

10
Andomar

Il existe une nouvelle méthode dans SQL Server 2017:

SELECT STRING_AGG (column, ',') AS column FROM Table;

qui produira 1,3,5,9 pour toi

6
jkalamarz
SELECT  CAST(<COLUMN Name> AS VARCHAR(3)) + ','
FROM    <TABLE Name>
FOR     XML PATH('')
1
Mohammad Foolady

La réponse actuellement acceptée ne fonctionne pas pour plusieurs regroupements.
Essayez ceci lorsque vous devez opérer sur des catégories de valeurs de ligne de colonne.

Supposons que j'ai les données suivantes:

+---------+-----------+
| column1 |  column2  |
+---------+-----------+
| cat     | Felon     |
| cat     | Purz      |
| dog     | Fido      |
| dog     | Beethoven |
| dog     | Buddy     |
| bird    | Tweety    |
+---------+-----------+

Et je veux cela comme sortie:

+------+----------------------+
| type |        names         |
+------+----------------------+
| cat  | Felon,Purz           |
| dog  | Fido,Beethoven,Buddy |
| bird | Tweety               |
+------+----------------------+

(Si vous suivez:

create table #column_to_list (column1 varchar(30), column2 varchar(30))
insert into #column_to_list
values 
('cat','Felon'),
('cat','Purz'),
('dog','Fido'),
('dog','Beethoven'),
('dog','Buddy'),
('bird','Tweety')

)

Maintenant - je ne veux pas entrer dans toute la syntaxe, mais comme vous pouvez le voir, cela fait l'astuce initiale pour nous:

select ',' + cast(column2 as varchar(255)) as [text()]  
from #column_to_list sub
where column1 = 'dog'
for xml path('')
--Using "as [text()]" here is specific to the “for XML” line after our where clause and we can’t give a name to our selection, hence the weird column_name

sortie:

+------------------------------------------+
| XML_F52E2B61-18A1-11d1-B105-00805F49916B |
+------------------------------------------+
| ,Fido,Beethoven,Buddy                    |
+------------------------------------------+

Vous pouvez voir qu'il est limité dans la mesure où il ne concernait qu'un seul groupe (où column1 = "chien") et qu'il a laissé une virgule à l'avant, et en plus il est nommé bizarre.

Donc, commençons par gérer la virgule principale en utilisant la fonction 'stuff' et nommons notre colonne stuff_list:

select stuff([list],1,1,'') as stuff_list
from (select ',' + cast(column2 as varchar(255)) as [text()]
         from #column_to_list sub
         where column1 = 'dog'
         for xml path('')
         ) sub_query([list]) 
--"sub_query([list])" just names our column as '[list]' so we can refer to it in the stuff function.  

Sortie:

+----------------------+
|      stuff_list      |
+----------------------+
| Fido,Beethoven,Buddy |
+----------------------+

Enfin, nous allons simplement en faire une instruction select, en notant la référence à l'alias top_query définissant la colonne1 que nous voulons (sur la 5e ligne ici):

select top_query.column1, 
          (select stuff([list],1,1,'') as stuff_list
         from (select ',' + cast(column2 as varchar(255)) as [text()]
                  from #column_to_list sub
                  where sub.column1 = top_query.column1
                  for xml path('')
                  ) sub_query([list])
              ) as pet_list
from  #column_to_list top_query
group by column1
order by column1

sortie:

+---------+----------------------+
| column1 |       pet_list       |
+---------+----------------------+
| bird    | Tweety               |
| cat     | Felon,Purz           |
| dog     | Fido,Beethoven,Buddy |
+---------+----------------------+

Et nous avons terminé.

Vous pouvez lire plus ici:

1
ColinMac

C'est une tentative de créer une colonne réutilisable pour une chaîne séparée par des virgules. Dans ce cas, je n'ai qu'une seule chaîne qui a des valeurs et je ne veux pas de chaînes vides ou nulles.

Je crée d'abord un type défini par l'utilisateur qui est une table à une colonne.

-- ================================
-- Create User-defined Table Type
-- ================================
USE [RSINET.MVC]
GO

-- Create the data type
CREATE TYPE [dbo].[SingleVarcharColumn] AS TABLE 
(
    data NVARCHAR(max)
)
GO

Le véritable objectif du type est de simplifier la création d'une fonction scalaire pour placer la colonne dans des valeurs séparées par des virgules.

-- ================================================
-- Template generated from Template Explorer using:
-- Create Scalar Function (New Menu).SQL
--
-- Use the Specify Values for Template Parameters 
-- command (Ctrl-Shift-M) to fill in the parameter 
-- values below.
--
-- This block of comments will not be included in
-- the definition of the function.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:  Rob Peterson        
-- Create date: 8-26-2015
-- Description: This will take a single varchar column and convert it to
-- comma separated values.
-- =============================================
CREATE FUNCTION fnGetCommaSeparatedString 
(
    -- Add the parameters for the function here
    @column AS [dbo].[SingleVarcharColumn] READONLY
)
RETURNS VARCHAR(max)
AS
BEGIN
-- Declare the return variable here
DECLARE @result VARCHAR(MAX)
DECLARE @current VARCHAR(MAX)
DECLARE @counter INT
DECLARE @c CURSOR

SET @result = ''
SET @counter = 0
-- Add the T-SQL statements to compute the return value here
SET @c = CURSOR FAST_FORWARD
    FOR SELECT COALESCE(data,'') FROM @column
    OPEN @c
    FETCH NEXT FROM @c
    INTO @current
    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF @result <> '' AND @current <> '' SET @result = @result + ',' + @current
        IF @result = '' AND @current <> '' SET @result = @current
    FETCH NEXT FROM @c
    INTO @current
    END
    CLOSE @c
    DEALLOCATE @c
-- Return the result of the function
RETURN @result

END
GO

Maintenant, pour l'utiliser. Je sélectionne la colonne que je souhaite convertir en une chaîne séparée par des virgules dans le type SingleVarcharColumn.

DECLARE @s as SingleVarcharColumn

INSERT INTO @s VALUES ('rob')
INSERT INTO @s VALUES ('paul')
INSERT INTO @s VALUES ('james')
INSERT INTO @s VALUES (null)


INSERT INTO @s
SELECT iClientID FROM [dbo].tClient

SELECT [dbo].fnGetCommaSeparatedString(@s)

Pour obtenir des résultats comme celui-ci.

rob, paul, james, 1,9,10,11,12,13,14,15,16,18,19,23,26,27,28,29,30,31,32,34,35,36, 37,38,39,40,41,42,44,45,46,47,48,49,50,52,53,54,56,57,59,60,61,62,63,64,65, 66,67,68,69,70,71,72,74,75,76,77,78,81,82,83,84,87,88,90,91,92,93,94,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,120,121,122,123,124,125,126,127,128,129,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159

J'ai fait ma colonne de données dans mon type SingleVarcharColumn un NVARCHAR (MAX) qui peut nuire aux performances, mais la flexibilité était ce que je cherchais et elle fonctionne assez rapidement pour mes besoins. Ce serait probablement plus rapide s'il s'agissait d'un varchar et s'il avait une largeur fixe et plus petite, mais je ne l'ai pas testé.

1
Rob Peterson

Vous pouvez utiliser la méthode suivante:

select
STUFF(
        (
        select ', ' + CONVERT(varchar(10), ID) FROM @temp
        where ID<50
group by ID for xml path('')
        ), 1, 2, '') as IDs

La mise en oeuvre:

Declare @temp Table(
ID int
)
insert into @temp
(ID)
values
(1)
insert into @temp
(ID)
values
(3)
insert into @temp
(ID)
values
(5)
insert into @temp
(ID)
values
(9)

 select
STUFF(
        (
        select ', ' + CONVERT(varchar(10), ID) FROM @temp
        where ID<50
group by ID for xml path('')
        ), 1, 2, '') as IDs

Le résultat sera:

enter image description here

0
Muhammad Awais
ALTER PROCEDURE [dbo].[spConvertir_CampoACadena]( @nomb_tabla   varchar(30),
                          @campo_tabla  varchar(30),
                          @delimitador  varchar(5),
                          @respuesta    varchar(max) OUTPUT
)
AS
DECLARE @query      varchar(1000),
    @cadena     varchar(500)
BEGIN
  SET @query = 'SELECT @cadena  = COALESCE(@cadena + '''+ @delimitador +''', '+ '''''' +') + '+ @campo_tabla + ' FROM '+@nomb_tabla
  --select @query
  EXEC(@query)
  SET @respuesta = @cadena  
END
0
Huacho