sql >> Database >  >> RDS >> Sqlserver

Hoe verander ik de informatie in deze tabel in een gebruiksvriendelijk formulier?

Uit (enigszins morbide) nieuwsgierigheid probeerde ik een manier te bedenken om de exacte invoergegevens die je hebt verstrekt te transformeren.

Veel beter zou natuurlijk zijn om de originele gegevens goed te structureren. Met een verouderd systeem is dit misschien niet mogelijk, maar er zou een ETL-proces kunnen worden gemaakt om deze informatie naar een tussenliggende locatie te brengen, zodat een lelijke zoekopdracht als deze niet in realtime hoeft te worden uitgevoerd.

Voorbeeld #1

In dit voorbeeld wordt ervan uitgegaan dat alle ID's consistent en opeenvolgend zijn (anders een extra ROW_NUMBER() kolom of een nieuwe identiteitskolom zou moeten worden gebruikt om correcte resterende bewerkingen op ID te garanderen).

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

Voorbeeld #2:Geen afhankelijkheid van opeenvolgende ID's

Dit is een meer praktisch voorbeeld omdat de werkelijke ID-waarden er niet toe doen, alleen de rijvolgorde.

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;

Voorbeeld #3:Cursor

Nogmaals, het is het beste om een ​​dergelijke query niet in realtime uit te voeren en een gepland, transactioneel ETL-proces te gebruiken. In mijn ervaring zijn semi-gestructureerde gegevens zoals deze gevoelig voor afwijkingen.

Terwijl voorbeelden #1 en #2 (en de oplossingen van anderen) slimme manieren laten zien om met de gegevens te werken, zou een meer praktische manier om deze gegevens te transformeren een cursor zijn. Waarom? het kan zelfs beter presteren (geen geneste zoekopdrachten, recursie, draaien of rijnummering) en zelfs als het langzamer is, biedt het veel betere mogelijkheden voor foutafhandeling.

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

Prestaties

Ik heb voorbeeldbrongegevens van 100.000 rijen gemaakt en de drie bovengenoemde voorbeelden lijken ongeveer equivalent voor het transformeren van gegevens.

Ik heb een miljoen rijen met brongegevens gemaakt en een query die lijkt op de volgende geeft uitstekende prestaties voor het selecteren van een subset van rijen (zoals zou worden gebruikt in een raster op een webpagina of een rapport).

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

Ik zie uitvoeringstijden van 4-10 ms (i7-3960x) tegen een reeks van een miljoen records.



  1. IF-statement is niet geldig in deze positie

  2. Scheid door komma's gescheiden mySql-databaseveldwaarde met php

  3. Django-instellingen configureren databases met twee engines

  4. Oracle RAW id-kolommen en JDBC