sql >> Databasteknik >  >> RDS >> Sqlserver

Hur ändrar man informationen i den här tabellen till ett lättanvänt formulär?

Av (något morbid) nyfikenhet försökte jag komma på ett sätt att omvandla den exakta indata som du har angett.

Mycket bättre vore naturligtvis att strukturera originaldata ordentligt. Med ett äldre system kanske detta inte är möjligt, men en ETL-process kan skapas för att föra denna information till en mellanliggande plats så att en ful fråga som denna inte skulle behöva köras i realtid.

Exempel #1

Det här exemplet förutsätter att alla ID:n är konsekventa och sekventiella (annars ytterligare ROW_NUMBER() kolumn eller en ny identitetskolumn skulle behöva användas för att garantera korrekta återstående operationer 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

Exempel #2:Inget beroende av sekventiella ID:n

Detta är ett mer praktiskt exempel eftersom de faktiska ID-värdena inte spelar någon roll, bara radsekvensen.

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;

Exempel #3:Markör

Återigen, det skulle vara bäst att undvika att köra en fråga som denna i realtid och använda en schemalagd transaktions ETL-process. Enligt min erfarenhet är semi-strukturerad data som denna benägen till anomalier.

Medan exempel #1 och #2 (och de lösningar som tillhandahålls av andra) visar smarta sätt att arbeta med data, skulle ett mer praktiskt sätt att transformera denna data vara en markör. Varför? det kanske faktiskt fungerar bättre (inga kapslade frågor, rekursion, pivotering eller radnumrering) och även om det är långsammare ger det mycket bättre möjligheter för felhantering.

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

Prestanda

Jag skapade exempel på källdata på 100 000 rader och de tre ovannämnda exemplen verkar ungefär likvärdiga för att transformera data.

Jag skapade en miljon rader med källdata och en fråga som liknar följande ger utmärkt prestanda för att välja en delmängd av rader (som skulle användas i ett rutnät på en webbsida 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;

Jag ser körtider på 4-10 ms (i7-3960x) mot en uppsättning av en miljon rekord.



  1. Ändra kommando i Aurora DB (lägg till en ny kolumn)

  2. Hur gör man en sammanfogad fråga i ZF-tabeller-gränssnittet?

  3. Få resultat från mysql baserat på latitud longitud

  4. Hur kontrollerar du om IDENTITY_INSERT är inställt på PÅ eller AV i SQL Server?