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

Den mest elegante måde at generere permutationer i SQL server

Efter at have fremsat nogle måske snertne kommentarer, sad dette problem fast i min hjerne hele aftenen, og jeg kom til sidst med følgende sæt-baserede tilgang. Jeg mener bestemt, at den kvalificerer sig som "elegant", men så synes jeg også, den kvalificerer sig som "lidt dum". Du foretager opkaldet.

Først skal du oprette nogle tabeller:

-- Til testformål DROP TABLE SourceDROP TABLE NumbersDROP TABEL Resultater-- Tilføj så mange rækker, som det er nødvendigt at behandle - men bemærk, at du får N! (antal rækker, faktorielle) resultater,-- og det bliver hurtigt stort. Identitetskolonnen skal starte ved 1, ellers skal algoritmen justeres.-- Element kunne være mere end char(1), selvom algoritmen skulle justeres igen, og hvert element-- skal have samme længde. CREATE TABLE Kilde ( SourceId int not null identity(1,1) ,Element char(1) not null )INSERT Kilde (Element) værdier ('A')INSERT Kilde (Element) værdier ('B')INSERT Kilde (Element) værdier ('C')INSERT Kilde (Element) værdier ('D')--INSERT Kilde (Element) værdier ('E')--INSERT Kilde (Element) værdier ('F')-- Dette er en standard Tally tabel (eller "tabel over tal")-- Det behøver kun at være så længe der er elementer i tabellen KildeCREATE TABLE Tal (Number int ikke null)INSERT Tal (Number) værdier (1)INSERT Tal (Number) værdier (2) )INDSÆT Tal (Tal) værdier (3)INDSÆT Tal (Tal) værdier (4)INDSÆT Tal (Tal) værdier (5)INDSÆT Tal (Tal) værdier (6)INDSÆT Tal (Antal) værdier (7)INDSÆT Tal (Antal) ) værdier (8)INDSÆT numre (tal) værdier (9)INDSÆT Tal (Antal) værdier (10)-- Resultater er iterativt bygget her. Dette kunne være et vikarbord. Et indeks på "Længde" kan gøre løb - hurtigere for store sæt. Combo skal være mindst så længe der er tegn, der skal permuteres. CREATE TABLE Results ( Combo varchar(10) not null ,Length int not null )

Her er rutinen:

SET NOCOUNT onDECLARE @Loop int ,@MaxLoop int-- Hvor mange elementer der skal behandlesSELECT @MaxLoop =max(SourceId) from Source-- Initialize first valueTRUNCATE TABLE ResultsINSERT Results (Combo, Length) vælg Element, 1 fra kilde hvor SourceId =1SET @Loop =2-- Gentag for at tilføje hvert element efter den første WHILE @Loop <=@MaxLoop BEGIN -- Se kommentarer nedenfor. Bemærk, at "distinkte" fjerner dubletter, hvis en given værdi -- skal inkluderes mere end én gang. INSERT Results (Combo, Length) vælg distinct left(re.Combo, @Loop - nm.Number) + so.Element + right (re.Combo, nm.Number - 1) ,@Loop from Results re inner join Numbers nm on nm.Number <=@Loop indre join Kilde så videre so.SourceId =@Loop hvor re.Length =@Loop - 1 - - For ydeevne skal du tilføje dette, hvis sæt bliver store --SLET resultater -- hvor længde <> @Loop SET @Loop =@Loop + 1 END-- Vis resultaterSELECT * fra resultater hvor længde =@MaxLoop rækkefølge efter kombination 

Den generelle idé er:når du tilføjer et nyt element (f.eks. "B") til en hvilken som helst streng (f.eks. "A"), for at fange alle permutationer, vil du tilføje B til alle mulige positioner (Ba, aB), hvilket resulterer i et nyt sæt af strenge. Gentag derefter:Tilføj et nyt element (C) til hver position i en streng (AB bliver Cab, aCb, abC), for alle strenge (Cba, bCa, baC), og du har sættet af permutationer. Gentag over hvert resultatsæt med det næste tegn, indtil du løber tør for tegn... eller ressourcer. 10 elementer er 3,6 millioner permutationer, ca. 48 MB med ovenstående algoritme, og 14 (unikke) elementer ville ramme 87 milliarder permutationer og 1,163 terabyte.

Jeg er sikker på, at det i sidste ende kunne kiles ind i en CTE, men i sidste ende ville det kun være en glorificeret loop. Logikken er klarere på denne måde, og jeg kan ikke undgå at tro, at CTE-udførelsesplanen ville være et mareridt.



  1. Opgradering af MariaDB 10.0 til 10.3.9 på Ubuntu 16.04

  2. Fjern mærkelige tegn (A med hat) fra SQL Server varchar-kolonnen

  3. SQL Server Blocking Query

  4. Hvad er LIKE Logical Operator i SQL Server - SQL Server / TSQL Tutorial Del 123