2012-06-13 12 views
12

Tôi thực sự muốn một số lời khuyên ở đây, để cung cấp một số thông tin cơ bản tôi đang làm việc với chèn các bản ghi Theo dõi thư từ Exchange 2007 vào SQL. Khi chúng tôi có hàng triệu hàng triệu hàng mỗi ngày, tôi đang sử dụng lệnh Chèn hàng loạt để chèn dữ liệu vào bảng SQL. Trong thực tế, tôi thực sự số lượng lớn chèn vào một bảng tạm thời và sau đó từ đó tôi MERGE dữ liệu vào bảng sống, điều này là cho các vấn đề phân tích thử nghiệm như một số lĩnh vực khác có dấu ngoặc kép và như vậy xung quanh các giá trị.Tách các giá trị phân tách trong một cột SQL thành nhiều hàng

Điều này hoạt động tốt, ngoại trừ thực tế là cột địa chỉ người nhận là một trường được phân tách bởi một; và đôi khi nó có thể cực kỳ dài vì có thể có nhiều người nhận email.

Tôi muốn lấy cột này và chia các giá trị thành nhiều hàng mà sau đó sẽ được chèn vào một bảng khác. Vấn đề là bất cứ điều gì tôi đang cố gắng là mất quá nhiều thời gian hoặc không hoạt động theo cách tôi muốn.

Hãy ví dụ này dữ liệu:

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

Tôi muốn này phải được định dạng như sau trong bảng nhận của tôi:

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

Có ai có bất kỳ ý tưởng về làm thế nào tôi có thể đi về việc này ?

Tôi biết PowerShell khá tốt, vì vậy tôi đã thử trong đó, nhưng vòng lặp foreach ngay cả trên hồ sơ 28K mất mãi mãi để xử lý, tôi cần thứ gì đó sẽ chạy nhanh nhất/hiệu quả nhất có thể.

Cảm ơn!

+0

Tôi nghĩ bạn nên đưa bạn ba kết quả trong một bảng bằng cách sử dụng chức năng chia tách Xem xét điều này: http: // stackoverflow.com/questions/314824/t-sql-đối diện-nối-chuỗi-nối-cách-chia-chuỗi-thành-nhiều-reco Và sau đó bạn có thể quản lý để kết hợp dữ liệu phân tách của bạn với bạn bảng khác để có được kết quả của bạn – GregM

Trả lời

41

Đầu tiên, tạo một hàm split:

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 

Bây giờ bạn có thể suy luận đơn giản bằng cách:

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

dấu gạch ngang Ngoài ra tôi đề nghị không đưa vào tên cột. Nó có nghĩa là bạn luôn phải đặt chúng trong [square brackets].

+2

Bạn thưa ông, xứng đáng với một cookie internet :) Tôi đã phải thực hiện một vài thay đổi, tôi đã phải gọi trường Item giá trị thay vì PowerShell không thích tên Item. Tôi cũng đã phải thêm 'AS f' sau khi CROSS ÁP DỤNG để bí danh rằng phần như f để gọi f.item/f.value làm việc. – HungryHippos

+0

Cũng nghe bạn về tên cột, điều này đã được thực hiện chỉ để giữ tính chẵn lẻ với tên cột theo dõi nhật ký theo dõi, tôi biết sự cần thiết của dấu ngoặc và ok. – HungryHippos

+0

mẫu briliant. tuyên bố của tôi trông như thế này: SELECT s.item, f.Item TỪ dbconfig AS s CROSS ÁP DỤNG SplitStrings (s.setting, ';') AS f WHERE s.item = 'EXE_PATHS' –

0

SQL Server 2016 bao gồm hàm bảng mới string_split(), tương tự như giải pháp trước đó.

Yêu cầu duy nhất là Thiết lập mức độ tương thích với 130 (SQL Server 2016)

0

Bạn có thể sử dụng CROSS APPLY (có sẵn trong SQL Server 2005 trở lên) và STRING_SPLIT chức năng (có sẵn trong SQL Server 2016 và ở trên):

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; 

Kết quả:

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

MessageId Recipient 
----------- ---------------- 
1   [email protected] 
1   [email protected] 
1   [email protected] 
2   [email protected] 
2   [email protected]