Ответ 1
Вы можете сделать это следующим образом:
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 выглядит примерно так:
SELECT column
FROM table
WHERE column<10
и результатом будет столбец со значениями
|column|
--------
| 1 |
| 3 |
| 5 |
| 9 |
В результате я хочу, чтобы строка "1, 3, 5, 9"
Вы можете сделать это следующим образом:
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)
Это удар в создании столбца многократного использования для разделенной запятой строки. В этом случае у меня есть только одна строка, имеющая значения, и я не хочу пустые строки или нули.
Сначала я создаю пользовательский тип, который представляет собой таблицу с одним столбцом.
-- ================================
-- Create User-defined Table Type
-- ================================
USE [RSINET.MVC]
GO
-- Create the data type
CREATE TYPE [dbo].[SingleVarcharColumn] AS TABLE
(
data NVARCHAR(max)
)
GO
Реальная цель этого типа заключается в том, чтобы упростить создание скалярной функции, чтобы поместить столбец в значения, разделенные запятыми.
-- ================================================
-- 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
Теперь, чтобы использовать это. Я выбираю столбец, который я хочу преобразовать в строку, разделенную запятой, в тип 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)
Чтобы получить такие результаты.
грабит, Поль, Джеймс, 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
Я сделал свой столбец данных в моем SingleVarcharColumn типом NVARCHAR (MAX), который может повредить производительность, но я был гибким, и я был в нем, и он работает достаточно быстро для моих целей. Вероятно, это было бы быстрее, если бы это был varchar, и если бы он имел фиксированную и меньшую ширину, но я его не тестировал.
SELECT CAST(<COLUMN Name> AS VARCHAR(3)) + ','
FROM <TABLE Name>
FOR XML PATH('')
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 '[email protected]_tabla
--select @query
EXEC(@query)
SET @respuesta = @cadena
END
Вы можете использовать следующий метод:
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
Текущий принятый ответ не работает для нескольких групп.
Попробуйте это, когда вам нужно оперировать категориями значений строк столбцов.
Предположим, у меня есть следующие данные:
+---------+-----------+
| column1 | column2 |
+---------+-----------+
| cat | Felon |
| cat | Purz |
| dog | Fido |
| dog | Beethoven |
| dog | Buddy |
| bird | Tweety |
+---------+-----------+
И я хочу это как мой вывод:
+------+----------------------+
| type | names |
+------+----------------------+
| cat | Felon,Purz |
| dog | Fido,Beethoven,Buddy |
| bird | Tweety |
+------+----------------------+
(Если вы следуете:
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')
)
Теперь - я не хочу вдаваться во весь синтаксис, но, как вы можете видеть, это делает начальный трюк для нас:
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 cant give a name to our selection, hence the weird column_name
выход:
+------------------------------------------+
| XML_F52E2B61-18A1-11d1-B105-00805F49916B |
+------------------------------------------+
| ,Fido,Beethoven,Buddy |
+------------------------------------------+
Вы можете видеть его ограниченность в том, что он был только для одной группы (где column1 = 'собака), и он оставил запятую впереди, и, кроме того, его назвали странным.
Итак, сначала давайте обработаем начальную запятую с помощью функции stuff и назовем наш столбец 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.
Выход:
+----------------------+
| stuff_list |
+----------------------+
| Fido,Beethoven,Buddy |
+----------------------+
Наконец, давайте просто добавим это в оператор select, отметив ссылку на псевдоним top_query, определяющий, какой столбец1 мы хотим (в 5-й строке здесь):
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
выход:
+---------+----------------------+
| column1 | pet_list |
+---------+----------------------+
| bird | Tweety |
| cat | Felon,Purz |
| dog | Fido,Beethoven,Buddy |
+---------+----------------------+
И были сделаны.
Вы можете прочитать больше здесь:
В SQL Server 2017 появился новый метод:
SELECT STRING_AGG (column, ',') AS column FROM Table;
это даст вам 1,3,5,9