Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

SQL:Uporządkuj według podciągu mieszanych liter i cyfr

Umieszczam to jako nową odpowiedź, ponieważ tak naprawdę nie jest to odpowiedź, ale raczej porównanie różnych podejść:

Wniosek:

  • wszystkie podejścia skalują się dość liniowo, z wyjątkiem XML
  • XML jest najszybszy przy małej liczbie wierszy, ale pogarsza się przy dużej liczbie wierszy

Utwórz scenariusz testowy

CREATE TABLE #tbl (ID INT IDENTITY,sortColumn VARCHAR(100));
INSERT INTO #tbl VALUES
 ('A-1')
,('A-10')
,('A-2')
,('A-3')
,('A-4')
,('A-5')
,('A-6')
,('A-7')
,('A-8')
,('A-9')
,('A-3a')
,('A-3b')
,('A-3c')
,('B-1')
,('B-10')
,('B-11')
,('B-12')
,('B-12a')
,('B-12b')
,('B-13')
,('B-2')
,('B-3')
,('B-4')
,('B-5')
,('B-6')
,('B-7')
,('B-8')
,('A-8a')
,('B-8')
,('B-9'); --30 rows
GO 1000  -- x 1.000 = 30.000 rows

Podejście Matta (oczyszczone do niezbędnego)

  • 46 sekund w 3 milionach rzędów
  • 4,5 sekundy na 300 000 rzędów
  • 1.3 sekundy na 30 000 rzędów
  • 0,7 sekundy na 3000 rzędów

Kod

SELECT ID,sortColumn
FROM
    #tbl
ORDER BY
LEFT(sortColumn,CHARINDEX('-',sortColumn) -1)
,CAST((CASE
    WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,3)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,3)
    WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,2)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,2)
    WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,1)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,1)
    ELSE NULL
END) AS INT)
,RIGHT(sortColumn,
    LEN(sortColumn) - 
    LEN(LEFT(sortColumn,CHARINDEX('-',sortColumn) -1)) 
    - LEN(CASE
            WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,3)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,3)
            WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,2)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,2)
            WHEN ISNUMERIC(SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,1)) = 1 THEN SUBSTRING(sortColumn,CHARINDEX('-',sortColumn) + 1,1)
            ELSE NULL
    END)
    - 1 --the '-'
),ID;

Kalkulacja krokowa w CROSS APPLY s, sortowanie według kolumn obliczeniowych

  • 44 sekundy w 3 milionach rzędów
  • 4,4 sekundy na 300 000 rzędów
  • 0,9 sekundy na 30 000 rzędów
  • 0,3 sekundy na 3000 rzędów

Kod

SELECT ID,sortColumn
FROM #tbl
CROSS APPLY(SELECT CHARINDEX('-',sortColumn) AS posMinus) AS pos
CROSS APPLY(SELECT SUBSTRING(sortColumn,1,posMinus-1) AS part1
                  ,SUBSTRING(sortColumn,posMinus+1,1000) AS part2
            ) AS parts
CROSS APPLY(SELECT ISNUMERIC(part2) AS p2isnum) AS checknum
CROSS APPLY(SELECT CASE WHEN p2isnum=1 THEN '' ELSE RIGHT(part2,1) END AS part3
                  ,CASE WHEN p2isnum=1 THEN part2 ELSE SUBSTRING(part2,1,LEN(part2)-1) END AS part2New
           ) AS partsNew
ORDER BY part1,part2new,part3,ID;

Kalkulacja krokowa w CROSS APPLY s, sortowanie według połączonego dopełnionego ciągu

  • 42 sekundy w 3 milionach rzędów
  • 4,2 sekundy na 300 000 rzędów
  • 0,7 sekundy na 30 000 rzędów
  • 0,4 sekundy na 3000 rzędów

Kod

SELECT ID,sortColumn
FROM #tbl
CROSS APPLY(SELECT CHARINDEX('-',sortColumn) AS posMinus) AS pos
CROSS APPLY(SELECT SUBSTRING(sortColumn,1,posMinus-1) AS part1
                  ,SUBSTRING(sortColumn,posMinus+1,1000) AS part2
            ) AS parts
ORDER BY RIGHT('.....' + part1,5) + RIGHT('.....' + part2,5 - ISNUMERIC(RIGHT(part2,1)))
        ,ID;

Dzielenie za pomocą XML, sortowanie według połączonego dopełnionego ciągu

  • 67 sekund w 3 milionach rzędów
  • 6,2 sekundy na 300 000 rzędów
  • 0,7 sekundy na 30 000 rzędów
  • 0,3 sekundy na 3000 rzędów

Kod

SELECT ID,sortColumn
FROM
(
    SELECT CAST('<r>' + REPLACE(sortColumn,'-','</r><r>') + '</r>' AS XML) AS SortColumnSplitted
          ,*
    FROM #tbl
) AS tbl
ORDER BY RIGHT('.....' + SortColumnSplitted.value('r[1]','varchar(max)'),5) + RIGHT('.....' + SortColumnSplitted.value('r[2]','varchar(max)'),5 - ISNUMERIC(RIGHT(SortColumnSplitted.value('r[2]','varchar(max)'),1)))
        ,ID;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Czy funkcje skalarne mogą być stosowane przed filtrowaniem podczas wykonywania instrukcji SQL?

  2. T-sql - określ, czy wartość jest liczbą całkowitą

  3. Ustaw pary klucz/wartość w kontekście sesji w programie SQL Server (sp_set_session_context)

  4. mssql konwertuj varchar na float

  5. Zapytanie SQL, które działa dobrze w SSMS, działa bardzo wolno w ASP.NET