Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Bagaimana cara mengubah informasi dalam tabel ini menjadi bentuk yang mudah digunakan?

Karena rasa ingin tahu (sedikit tidak wajar), saya mencoba menemukan cara untuk mengubah data input persis yang Anda berikan.

Jauh lebih baik, tentu saja, adalah menyusun data asli dengan benar. Dengan sistem lama, ini mungkin tidak mungkin, tetapi proses ETL dapat dibuat untuk membawa informasi ini ke lokasi perantara sehingga kueri jelek seperti ini tidak perlu dijalankan secara real time.

Contoh #1

Contoh ini mengasumsikan bahwa semua ID konsisten dan berurutan (jika tidak, ROW_NUMBER() tambahan kolom atau kolom identitas baru perlu digunakan untuk menjamin operasi sisa yang benar pada 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

Contoh #2:Tidak Ada Ketergantungan pada ID Sequential

Ini adalah contoh yang lebih praktis karena nilai ID yang sebenarnya tidak penting, hanya urutan barisnya saja.

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;

Contoh #3:Kursor

Sekali lagi, akan lebih baik untuk menghindari menjalankan kueri seperti ini secara real time dan menggunakan proses ETL transaksional terjadwal. Berdasarkan pengalaman saya, data semi terstruktur seperti ini rentan terhadap anomali.

Sementara contoh #1 dan #2 (dan solusi yang diberikan oleh orang lain) menunjukkan cara cerdas untuk bekerja dengan data, cara yang lebih praktis untuk mengubah data ini adalah dengan kursor. Mengapa? itu mungkin benar-benar berkinerja lebih baik (tidak ada kueri bersarang, rekursi, pivot, atau penomoran baris) dan bahkan jika lebih lambat, ini memberikan peluang yang jauh lebih baik untuk penanganan kesalahan.

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

Kinerja

Saya membuat data sumber sampel dari 100 ribu baris dan tiga contoh yang disebutkan di atas kira-kira setara untuk mentransformasi data.

Saya membuat satu juta baris data sumber dan kueri yang serupa dengan yang berikut ini memberikan kinerja yang sangat baik untuk memilih subset baris (seperti yang akan digunakan dalam kisi pada halaman web atau laporan).

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

Saya melihat waktu eksekusi 4-10 md (i7-3960x) dibandingkan dengan satu juta rekaman.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Apa yang bisa menjadi cara yang baik untuk menyebarkan Aplikasi Web ASP.Net?

  2. menggunakan nested if dalam prosedur tersimpan

  3. Bagaimana cara menambahkan kolom "terakhir diubah" dan dibuat dalam tabel SQL Server?

  4. Apa alternatif untuk kursor untuk perulangan sql?

  5. Mengambil baris terakhir kedua dengan hanya satu pilihan di SQL Server?