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"
Vous pouvez le faire comme ceci:
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 |
select stuff(list,1,1,'')
from (
select ',' + cast(col1 as varchar(16)) as [text()]
from YourTable
for xml path('')
) as Sub(list)
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
SELECT CAST(<COLUMN Name> AS VARCHAR(3)) + ','
FROM <TABLE Name>
FOR XML PATH('')
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:
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é.
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
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
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