2012-06-13 14 views
12

Bardzo chciałbym poradzić się tutaj z niektórymi informacjami pomocnymi przy wstawianiu dzienników śledzenia komunikatów z Exchange 2007 do SQL. Ponieważ mamy miliony na miliony wierszy dziennie, używam instrukcji Bulk Insert, aby wstawić dane do tabeli SQL.Rozdzielanie rozgraniczonych wartości w kolumnie SQL na wiele wierszy

Właściwie to faktycznie wrzucam do tablicy tymczasowej, a następnie stamtąd łączę dane w żywą tabelę, to jest do rozwiązywania problemów testowych, ponieważ pewne pola mają inne cytaty i takie wokół wartości.

To działa dobrze, z wyjątkiem faktu, że kolumna adresata jest polem rozdzielanym oddzielonym przez a; i może być niewiarygodnie długi, ponieważ może być wielu odbiorców wiadomości e-mail.

Chciałbym wziąć tę kolumnę i podzielić wartości na wiele wierszy, które następnie zostaną wstawione do innej tabeli. Problem polega na tym, że wszystko, co próbuję, trwa albo zbyt długo, albo nie działa tak, jak chcę.

Weźmy ten przykład dane:

message-id            recipient-address 
[email protected] [email protected] 
[email protected]  [email protected] 
[email protected]    [email protected];[email protected];[email protected] 

chciałbym to być sformatowany jak na moim Odbiorcy tabeli:

message-id            recipient-address 
2D5E5[email protected] [email protected] 
[email protected]  [email protected] 
[email protected]    [email protected] 
[email protected]    [email protected] 
[email protected]    [email protected] 

Czy ktoś ma jakieś pomysły o tym, jak mogę to zabrać ?

Znam PowerShell całkiem dobrze, więc próbowałem w tym, ale pętla foreach nawet na rekordach 28K trwała wiecznie do przetworzenia, potrzebuję czegoś, co będzie działało tak szybko/sprawnie jak to tylko możliwe.

Dzięki!

+0

Myślę, że powinieneś umieścić trzy wyniki w tabeli za pomocą funkcji podziału Spójrz na to: http: // stackoverflow.com/questions/314824/t-sql-opposite-to-string-concatenation-how-to-split-string-into-multiple-reco A potem możesz dołączyć do swoich podzielonych danych na innym stole, aby uzyskać wynik – GregM

Odpowiedz

41

Najpierw należy utworzyć funkcję podziału:

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 

Teraz można ekstrapolować prostu przez:

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

Także ja nie sugeruję myślniki w nazwy kolumn. Oznacza to, że zawsze musisz umieścić je w [square brackets].

+2

Jesteś sir, zasługujesz na ciasteczko internetowe :) Musiałem wprowadzić kilka zmian, musiałem wywołać wartość pola Item zamiast, ponieważ PowerShell nie lubił nazwy Item. Musiałem również dodać "AS f" po CROSS APPLY, aby alias ten dział jako f tak nazwano f.item/f.value. – HungryHippos

+0

Dowiesz się również o nazwach kolumn, zrobiono to tylko po to, aby zachować parzystość z nazwami kolumn dziennika śledzenia, mam świadomość, że potrzebne są nawiasy klamrowe i wszystko jest w porządku. – HungryHippos

+0

Świetna próbka. moje oświadczenie wygląda następująco: SELECT s.item, f.Item OD DBconfig AS s CROSS APPLY SplitStrings (s.setting, ';') AS f WHERE s.item = 'EXE_PATHS' –

0

SQL Server 2016 zawiera nową funkcję tabeli string_split(), podobną do poprzedniej wersji.

Jedynym wymogiem jest ustawiony poziom zgodności do 130 (SQL Server 2016)

0

można użyć CROSS APPLY (dostępne w SQL Server 2005 i powyżej) i STRING_SPLIT funkcji (dostępne w SQL Server 2016 i powyżej):

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, '[email protected]; [email protected]; [email protected]'); 
INSERT INTO MessageRecipients VALUES (2, '[email protected]; [email protected]'); 

-- 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; 

Wyniki:

MessageId Recipients 
----------- ---------------------------------------------------- 
1   [email protected]; [email protected]; [email protected] 
2   [email protected]; [email protected] 

i

MessageId Recipient 
----------- ---------------- 
1   [email protected] 
1   [email protected] 
1   [email protected] 
2   [email protected] 
2   [email protected] 
Powiązane problemy