Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Cara paling elegan untuk menghasilkan permutasi di SQL server

Setelah membuat beberapa komentar yang mungkin sinis, masalah ini melekat di otak saya sepanjang malam, dan akhirnya saya menemukan pendekatan berbasis himpunan berikut. Saya percaya itu pasti memenuhi syarat sebagai "elegan", tetapi kemudian saya juga berpikir itu memenuhi syarat sebagai "agak bodoh". Anda yang menelepon.

Pertama, siapkan beberapa tabel:

--  For testing purposes
DROP TABLE Source
DROP TABLE Numbers
DROP TABLE Results


--  Add as many rows as need be processed--though note that you get N! (number of rows, factorial) results,
--  and that gets big fast. The Identity column must start at 1, or the algorithm will have to be adjusted.
--  Element could be more than char(1), though the algorithm would have to be adjusted again, and each element
--  must be the same length.
CREATE TABLE Source
 (
   SourceId  int      not null  identity(1,1)
  ,Element   char(1)  not null
 )

INSERT Source (Element) values ('A')
INSERT Source (Element) values ('B')
INSERT Source (Element) values ('C')
INSERT Source (Element) values ('D')
--INSERT Source (Element) values ('E')
--INSERT Source (Element) values ('F')


--  This is a standard Tally table (or "table of numbers")
--  It only needs to be as long as there are elements in table Source
CREATE TABLE Numbers (Number int not null)
INSERT Numbers (Number) values (1)
INSERT Numbers (Number) values (2)
INSERT Numbers (Number) values (3)
INSERT Numbers (Number) values (4)
INSERT Numbers (Number) values (5)
INSERT Numbers (Number) values (6)
INSERT Numbers (Number) values (7)
INSERT Numbers (Number) values (8)
INSERT Numbers (Number) values (9)
INSERT Numbers (Number) values (10)


--  Results are iteratively built here. This could be a temp table. An index on "Length" might make runs
--  faster for large sets.  Combo must be at least as long as there are characters to be permuted.
CREATE TABLE Results
 (
   Combo   varchar(10)  not null
  ,Length  int          not null
 )

Berikut rutinitasnya:

SET NOCOUNT on

DECLARE
  @Loop     int
 ,@MaxLoop  int


--  How many elements there are to process
SELECT @MaxLoop = max(SourceId)
 from Source


--  Initialize first value
TRUNCATE TABLE Results
INSERT Results (Combo, Length)
 select Element, 1
  from Source
  where SourceId = 1

SET @Loop = 2

--  Iterate to add each element after the first
WHILE @Loop <= @MaxLoop
 BEGIN

    --  See comments below. Note that the "distinct" remove duplicates, if a given value
    --  is to be included more than once
    INSERT Results (Combo, Length)
     select 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
       inner join Source so
        on so.SourceId = @Loop
      where re.Length = @Loop - 1

    --  For performance, add this in if sets will be large
    --DELETE Results
    -- where Length <> @Loop

    SET @Loop = @Loop + 1
 END

--  Show results
SELECT *
 from Results
 where Length = @MaxLoop
 order by Combo

Ide umumnya adalah:ketika menambahkan elemen baru (misalnya "B") ke string apa pun (misalnya, "A"), untuk menangkap semua permutasi, Anda akan menambahkan B ke semua posisi yang mungkin (Ba, aB), menghasilkan set baru dari string. Kemudian ulangi:Tambahkan elemen baru (C) ke setiap posisi dalam string (AB menjadi Cab, aCb, abC), untuk semua string (Cba, bCa, baC), dan Anda memiliki himpunan permutasi. Ulangi setiap hasil yang ditetapkan dengan karakter berikutnya hingga Anda kehabisan karakter... atau sumber daya. 10 elemen adalah 3,6 juta permutasi, kira-kira 48 MB dengan algoritme di atas, dan 14 (unik) elemen akan mencapai 87 miliar permutasi dan 1,163 terabyte.

Saya yakin itu pada akhirnya bisa dimasukkan ke dalam CTE, tetapi pada akhirnya semua itu hanyalah loop yang dimuliakan. Logikanya lebih jelas dengan cara ini, dan mau tidak mau saya berpikir bahwa rencana eksekusi CTE akan menjadi mimpi buruk.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana saya bisa terhubung ke database eksternal dari pernyataan sql atau prosedur tersimpan?

  2. Urutan Bersyarat T-SQL Oleh

  3. Cara membuat Batasan Kunci Asing dengan ON DELETE CASCADE di SQL Server - Tutorial SQL Server / TSQL Bagian 80

  4. Nilai acak untuk kolom DATETIME

  5. Cara Menghubungkan ke SQL Server Default Instance dan SQL Server Named Instances - Tutorial SQL Server / TSQL Bagian 2