Vì tò mò (hơi bệnh hoạn), tôi đã cố gắng tìm ra một phương pháp chuyển đổi dữ liệu đầu vào chính xác mà bạn đã cung cấp.
Tất nhiên, tốt hơn nhiều là cấu trúc dữ liệu gốc đúng cách. Với một hệ thống kế thừa, điều này có thể không thực hiện được, nhưng một quy trình ETL có thể được tạo để đưa thông tin này vào một vị trí trung gian để một truy vấn xấu xí như thế này không cần phải chạy trong thời gian thực.
Ví dụ # 1
Ví dụ này giả định rằng tất cả các ID đều nhất quán và tuần tự (nếu không, một ROW_NUMBER()
bổ sung cột hoặc cột nhận dạng mới sẽ cần được sử dụng để đảm bảo các hoạt động còn lại chính xác trên ID).
SELECT
Name = REPLACE( Name, 'name: ', '' ),
Age = REPLACE( Age, 'age: ', '' )
FROM
(
SELECT
Name = T2.Data,
Age = T1.Data,
RowNumber = ROW_NUMBER() OVER( ORDER BY T1.Id ASC )
FROM @t T1
INNER JOIN @t T2 ON T1.id = T2.id +1 -- offset by one to combine two rows
WHERE T1.id % 3 != 0 -- skip delimiter records
) Q1
-- skip every other record (minus delimiters, which have already been stripped)
WHERE RowNumber % 2 != 0
Ví dụ # 2:Không phụ thuộc vào ID tuần tự
Đây là một ví dụ thực tế hơn vì các giá trị ID thực tế không quan trọng, chỉ là trình tự hàng.
DECLARE @NumberedData TABLE( RowNumber INT, Data VARCHAR( 100 ) );
INSERT @NumberedData( RowNumber, Data )
SELECT
RowNumber = ROW_NUMBER() OVER( ORDER BY id ASC ),
Data
FROM @t;
SELECT
Name = REPLACE( N2.Data, 'name: ', '' ),
Age = REPLACE( N1.Data, 'age: ', '' )
FROM @NumberedData N1
INNER JOIN @NumberedData N2 ON N1.RowNumber = N2.RowNumber + 1
WHERE ( N1.RowNumber % 3 ) = 2;
DELETE @NumberedData;
Ví dụ # 3:Con trỏ
Một lần nữa, tốt nhất là bạn nên tránh chạy một truy vấn như thế này trong thời gian thực và sử dụng quy trình ETL giao dịch theo lịch trình. Theo kinh nghiệm của tôi, dữ liệu bán cấu trúc như thế này dễ bị dị thường.
Trong khi các ví dụ # 1 và # 2 (và các giải pháp do những người khác cung cấp) thể hiện các cách làm việc thông minh với dữ liệu, thì một cách thực tế hơn để biến đổi dữ liệu này sẽ là con trỏ. Tại sao? nó thực sự có thể hoạt động tốt hơn (không có truy vấn lồng nhau, đệ quy, xoay vòng hoặc đánh số hàng) và ngay cả khi nó chậm hơn, nó cung cấp nhiều cơ hội tốt hơn để xử lý lỗi.
-- this could be a table variable, temp table, or staging table
DECLARE @Results TABLE ( Name VARCHAR( 100 ), Age INT );
DECLARE @Index INT = 0, @Data VARCHAR( 100 ), @Name VARCHAR( 100 ), @Age INT;
DECLARE Person_Cursor CURSOR FOR SELECT Data FROM @t;
OPEN Person_Cursor;
FETCH NEXT FROM Person_Cursor INTO @Data;
WHILE( 1 = 1 )BEGIN -- busy loop so we can handle the iteration following completion
IF( @Index = 2 ) BEGIN
INSERT @Results( Name, Age ) VALUES( @Name, @Age );
SET @Index = 0;
END
ELSE BEGIN
-- optional: examine @Data for integrity
IF( @Index = 0 ) SET @Name = REPLACE( @Data, 'name: ', '' );
IF( @Index = 1 ) SET @Age = CAST( REPLACE( @Data, 'age: ', '' ) AS INT );
SET @Index = @Index + 1;
END
-- optional: examine @Index to see that there are no superfluous trailing
-- rows or rows omitted at the end.
IF( @@FETCH_STATUS != 0 ) BREAK;
FETCH NEXT FROM Person_Cursor INTO @Data;
END
CLOSE Person_Cursor;
DEALLOCATE Person_Cursor;
Hiệu suất
Tôi đã tạo dữ liệu nguồn mẫu gồm 100K hàng và ba ví dụ nói trên có vẻ gần tương đương để chuyển đổi dữ liệu.
Tôi đã tạo một triệu hàng dữ liệu nguồn và một truy vấn tương tự như sau mang lại hiệu suất tuyệt vời để chọn một tập hợp con các hàng (chẳng hạn như sẽ được sử dụng trong lưới trên trang web hoặc báo cáo).
-- INT IDENTITY( 1, 1 ) numbers the rows for us
DECLARE @NumberedData TABLE( RowNumber INT IDENTITY( 1, 1 ), Data VARCHAR( 100 ) );
-- subset selection; ordering/filtering can be done here but it will need to preserve
-- the original 3 rows-per-result structure and it will impact performance
INSERT @NumberedData( Data )
SELECT TOP 1000 Data FROM @t;
SELECT
N1.RowNumber,
Name = REPLACE( N2.Data, 'name: ', '' ),
Age = REPLACE( N1.Data, 'age: ', '' )
FROM @NumberedData N1
INNER JOIN @NumberedData N2 ON N1.RowNumber = N2.RowNumber + 1
WHERE ( N1.RowNumber % 3 ) = 2;
DELETE @NumberedData;
Tôi thấy thời gian thực thi là 4-10ms (i7-3960x) so với tập hợp một triệu bản ghi.