sql >> Database teknologi >  >> RDS >> Sqlserver

Hvordan ændres oplysningerne i denne tabel til en brugervenlig formular?

Af (lidt morbid) nysgerrighed forsøgte jeg at finde på et middel til at transformere de nøjagtige inputdata, du har angivet.

Langt bedre ville selvfølgelig være at strukturere de originale data korrekt. Med et ældre system er dette muligvis ikke muligt, men der kunne oprettes en ETL-proces for at bringe disse oplysninger til en mellemliggende placering, så en grim forespørgsel som denne ikke behøver at blive kørt i realtid.

Eksempel #1

Dette eksempel forudsætter, at alle id'er er konsistente og sekventielle (ellers en ekstra ROW_NUMBER() kolonne eller en ny identitetskolonne skal bruges for at garantere korrekte resterende handlinger på 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

Eksempel #2:Ingen afhængighed af sekventielle ID'er

Dette er et mere praktisk eksempel, fordi de faktiske id-værdier er ligegyldige, kun rækkefølgen.

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;

Eksempel #3:Markør

Igen, det ville være bedst at undgå at køre en forespørgsel som denne i realtid og bruge en planlagt, transaktionel ETL-proces. Min erfaring er, at semi-strukturerede data som denne er tilbøjelige til anomalier.

Mens eksempel #1 og #2 (og løsningerne leveret af andre) viser smarte måder at arbejde med data på, ville en mere praktisk måde at transformere disse data på være en markør. Hvorfor? det kan faktisk yde bedre (ingen indlejrede forespørgsler, rekursion, pivotering eller rækkenummerering), og selvom det er langsommere, giver det meget bedre muligheder for fejlhåndtering.

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

Ydeevne

Jeg oprettede eksempler på kildedata på 100.000 rækker, og de tre førnævnte eksempler virker nogenlunde ækvivalente til transformation af data.

Jeg oprettede en million rækker af kildedata, og en forespørgsel, der ligner følgende, giver fremragende ydeevne til at vælge en undergruppe af rækker (som f.eks. ville blive brugt i et gitter på en webside eller en 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;

Jeg ser udførelsestider på 4-10 ms (i7-3960x) mod et sæt på en million rekorder.



  1. Sletning af en post fra datasæt og sql-server

  2. Brug tabelalias i en anden forespørgsel til at krydse et træ

  3. opret database med pdo i php

  4. Rekursiv CTE-stoptilstand for sløjfer