Как «взорвать» (де-нормализовать / конкатировать) несколько столбцов в один столбец? - PullRequest
9 голосов
/ 10 ноября 2011

У меня есть запрос, который выводит что-то вроде этого:

+-------+----+--------------+
| F_KEY | EV | OTHER_COLUMN |
+-------+----+--------------+
| 100   | 1  | ...          |
| 100   | 2  | ...          |
| 150   | 2  | ...          |
| 100   | 3  | ...          |
| 150   | 4  | ...          |
+-------+----+--------------+

Я уверен, что я видел функцию агрегирования, которая превращает ее (используя GROUP BY F_KEY) во что-то вроде этого:

+-------+------------+--------------+
| F_KEY | ?          | OTHER_COLUMN |
+-------+------------+--------------+
| 100   | (1, 2, 3)  | ...          |
| 150   | (2, 4)     | ...          |
+-------+------------+--------------+

Значит, он как-то "объединяет" значения EV вместе в одно поле.Как я могу это сделать?К сожалению, я не помню имя функции.

Я использую SQL Server.

Это упрощение моего запроса:

SELECT
    F_KEY,
    EV,
    OTHER_COLUMN
FROM
    TABLE1
JOIN
    TABLE2 ON F_KEY = TABLE2.ID
WHERE
    EVENT_TIME BETWEEN '2011-01-01 00:00:00.000' AND '2011-12-31 23:59:59.999'
ORDER BY
    EVENT_TIME ASC

Любая идеяоценили!

Ответы [ 4 ]

2 голосов
/ 11 ноября 2011

здесь лучший метод конкатенации, он не расширяет специальные символы, как другие методы XML:

--Concatenation with FOR XML & eliminating control/encoded char expansion "& < >"
set nocount on;
declare @YourTable table (RowID int, HeaderValue int, ChildValue varchar(5))
insert into @YourTable VALUES (1,1,'CCC')
insert into @YourTable VALUES (2,2,'B<&>B')
insert into @YourTable VALUES (3,2,'AAA')
insert into @YourTable VALUES (4,3,'<br>')
insert into @YourTable VALUES (5,3,'A & Z')
set nocount off
SELECT
    t1.HeaderValue
        ,STUFF(
                   (SELECT
                        ', ' + t2.ChildValue
                        FROM @YourTable t2
                        WHERE t1.HeaderValue=t2.HeaderValue
                        ORDER BY t2.ChildValue
                        FOR XML PATH(''), TYPE
                   ).value('.','varchar(max)')
                   ,1,2, ''
              ) AS ChildValues
    FROM @YourTable t1
    GROUP BY t1.HeaderValue

ВЫВОД:

HeaderValue ChildValues
----------- ---------------
1           CCC
2           AAA, B<&>B
3           <br>, A & Z

(3 row(s) affected)
1 голос
/ 11 ноября 2011

Вы можете сделать это достаточно легко с помощью функции: Предполагается, что вы будете искать один и тот же столбец / таблицу все время.Динамический SQL необходим, если вы хотите иметь возможность изменять столбцы / таблицы

CREATE FUNCTION [dbo].[fn_recursion]
(@F_KEY int)  
RETURNS varchar(2000) AS 
BEGIN 

    DECLARE @ReturnVal Varchar(2000)

    SELECT @ReturnVal = COALESCE(@ReturnVal + ', ', '') + EV
    FROM TABLE2 
    WHERE @F_KEY = @F_KEY

    RETURN ISNULL(@ReturnVal,'')

END
GO


SELECT
    F_KEY,
    EV = [dbo].[fn_recursion](F_KEY),
    OTHER_COLUMN
FROM
    TABLE1
JOIN
    TABLE2 ON F_KEY = TABLE2.ID
WHERE
    EVENT_TIME BETWEEN '2011-01-01 00:00:00.000' AND '2011-12-31 23:59:59.999'
ORDER BY
    EVENT_TIME ASC

GO

DROP FUNCTION [dbo].[fn_recursion]
GO
0 голосов
/ 22 ноября 2011

Изучите использование FOR XML PATH, вы можете преобразовать его, используя строку xml, как varchar, это также поддерживает разделительный символ / выражение. Он пойдет в конце вашего запроса, но, скорее всего, потребует от вас использования структуры подзапроса.

0 голосов
/ 10 ноября 2011

Вы, вероятно, можете использовать описанную технику здесь .(Полное раскрытие: это мой блог.) В нем рассказывается о создании сцепленных строк в T-SQL без использования курсоров.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...