Разделение запятыми значений в столбце SQL на несколько строк

мне бы очень хотелось получить некоторые советы здесь, чтобы дать некоторую справочную информацию я работаю с вставкой журналов отслеживания сообщений из Exchange 2007 В SQL. Поскольку у нас миллионы и миллионы строк в день, я использую оператор Bulk Insert для вставки данных в таблицу SQL.

на самом деле я на самом деле массовая вставка в временную таблицу, а затем оттуда я объединяю данные в живую таблицу, это для проблем с тестовым разбором, поскольку некоторые поля в противном случае имеют кавычки и такие вокруг ценности.

это работает хорошо, за исключением того, что столбец адрес получателя является разделенным полем, разделенным символом;, и иногда он может быть невероятно длинным, так как может быть много получателей электронной почты.

Я хотел бы взять этот столбец и разделить значения на несколько строк, которые затем будут вставлены в другую таблицу. Проблема, что я пытаюсь либо слишком долго, либо не работает так, как я хочу.

возьмем такой пример данные:

message-id                                              recipient-address
2D5E558D4B5A3D4F962DA5051EE364BE06CF37A3A5@Server.com   user1@domain1.com
E52F650C53A275488552FFD49F98E9A6BEA1262E@Server.com     user2@domain2.com
4fd70c47.4d600e0a.0a7b.ffff87e1@Server.com              user3@domain3.com;user4@domain4.com;user5@domain5.com

Я хотел бы, чтобы это было отформатировано следующим образом в моей таблице получателей:

message-id                                              recipient-address
2D5E558D4B5A3D4F962DA5051EE364BE06CF37A3A5@Server.com   user1@domain1.com
E52F650C53A275488552FFD49F98E9A6BEA1262E@Server.com     user2@domain2.com
4fd70c47.4d600e0a.0a7b.ffff87e1@Server.com              user3@domain3.com
4fd70c47.4d600e0a.0a7b.ffff87e1@Server.com              user4@domain4.com
4fd70c47.4d600e0a.0a7b.ffff87e1@Server.com              user5@domain5.com

есть ли у кого-нибудь идеи о том, как я могу это сделать?

Я знаю PowerShell довольно хорошо, поэтому я попытался в этом, но цикл foreach даже на 28k-записях занял целую вечность, мне нужно что-то, что будет работать как можно быстрее/эффективно.

спасибо!

3 ответов


во-первых, разделить функции:

CREATE FUNCTION dbo.SplitStrings
(
    @List       NVARCHAR(MAX),
    @Delimiter  NVARCHAR(255)
)
RETURNS TABLE
AS
    RETURN (SELECT Number = ROW_NUMBER() OVER (ORDER BY Number),
        Item FROM (SELECT Number, Item = LTRIM(RTRIM(SUBSTRING(@List, Number, 
        CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number)))
    FROM (SELECT ROW_NUMBER() OVER (ORDER BY s1.[object_id])
        FROM sys.all_objects AS s1 CROSS APPLY sys.all_objects) AS n(Number)
    WHERE Number <= CONVERT(INT, LEN(@List))
        AND SUBSTRING(@Delimiter + @List, Number, 1) = @Delimiter
    ) AS y);
GO

Теперь вы сможете самостоятельно, просто:

SELECT s.[message-id], f.Item
  FROM dbo.SourceData AS s
  CROSS APPLY dbo.SplitStrings(s.[recipient-address], ';') as f;

также я предлагаю не помещать тире в имена столбцов. Это означает, что вы всегда должны положить их в [square brackets].


SQL Server 2016 включает новую табличную функцию string_split (), аналогичную предыдущему решению.

единственное требование-установить уровень совместимости 130 (SQL Server 2016)


вы можете использовать КРЕСТ ПРИМЕНИТЬ (доступно в SQL Server 2005 и выше) и STRING_SPLIT функция (доступна в SQL Server 2016 и выше):

DECLARE @delimiter nvarchar(255) = ';';

-- create tables
CREATE TABLE MessageRecipients (MessageId int, Recipients nvarchar(max));
CREATE TABLE MessageRecipient (MessageId int, Recipient nvarchar(max));

-- insert data
INSERT INTO MessageRecipients VALUES (1, 'user1@domain.com; user2@domain.com; user3@domain.com');
INSERT INTO MessageRecipients VALUES (2, 'user@domain1.com; user@domain2.com');

-- insert into MessageRecipient
INSERT INTO MessageRecipient
SELECT MessageId, ltrim(rtrim(value))
FROM MessageRecipients 
CROSS APPLY STRING_SPLIT(Recipients, @delimiter)

-- output results
SELECT * FROM MessageRecipients;
SELECT * FROM MessageRecipient;

-- delete tables
DROP TABLE MessageRecipients;
DROP TABLE MessageRecipient;

результаты:

MessageId   Recipients
----------- ----------------------------------------------------
1           user1@domain.com; user2@domain.com; user3@domain.com
2           user@domain1.com; user@domain2.com

и

MessageId   Recipient
----------- ----------------
1           user1@domain.com
1           user2@domain.com
1           user3@domain.com
2           user@domain1.com
2           user@domain2.com