Bagaimana saya bisa mengubah 100 juta bilangan bulat positif pertama menjadi string?

13

Ini sedikit pengalihan dari masalah sebenarnya. Jika menyediakan konteks membantu, menghasilkan data ini dapat berguna untuk cara pengujian kinerja memproses string, untuk menghasilkan string yang perlu memiliki beberapa operasi yang diterapkan padanya dalam kursor, atau untuk menghasilkan penggantian nama unik dan anonim untuk data sensitif. Saya hanya tertarik pada cara efisien menghasilkan data dalam SQL Server, jangan tanya mengapa saya perlu menghasilkan data ini.

Saya akan mencoba memulai dengan definisi yang agak formal. Sebuah string termasuk dalam seri jika hanya terdiri dari huruf kapital dari A - Z. Istilah pertama dari seri adalah "A". Seri ini terdiri dari semua string yang valid yang diurutkan berdasarkan panjang pertama dan urutan abjad tipikal kedua. Jika string berada dalam tabel di kolom yang disebut STRING_COL, urutannya dapat didefinisikan dalam T-SQL sebagai ORDER BY LEN(STRING_COL) ASC, STRING_COL ASC.

Untuk memberikan definisi yang kurang formal lihat header kolom alfabet di excel. Serial ini memiliki pola yang sama. Pertimbangkan bagaimana Anda dapat mengonversi bilangan bulat ke nomor basis 26:

1 -> A, 2 -> B, 3 -> C, ..., 25 -> Y, 26 -> Z, 27 -> AA, 28 -> AB, ...

Analogi ini tidak terlalu sempurna karena "A" berperilaku berbeda dari 0 pada basis sepuluh. Di bawah ini adalah tabel nilai yang dipilih yang diharapkan akan membuatnya lebih jelas:

╔════════════╦════════╗
 ROW_NUMBER  STRING 
╠════════════╬════════╣
          1  A      
          2  B      
         25  Y      
         26  Z      
         27  AA     
         28  AB     
         51  AY     
         52  AZ     
         53  BA     
         54  BB     
      18278  ZZZ    
      18279  AAAA   
     475253  ZZZY   
     475254  ZZZZ   
     475255  AAAAA  
  100000000  HJUNYV 
╚════════════╩════════╝

Tujuannya adalah menulis SELECTkueri yang mengembalikan string 10.000.000 pertama dalam urutan yang ditentukan di atas. Saya melakukan pengujian dengan menjalankan kueri di SSMS dengan set hasil yang dibuang sebagai lawan menyimpannya ke tabel:

Buang hasil yang ditetapkan

Idealnya permintaan akan cukup efisien. Di sini saya mendefinisikan efisien sebagai waktu cpu untuk kueri seri dan waktu berlalu untuk kueri paralel. Anda dapat menggunakan trik tidak berdokumen apa pun yang Anda suka. Mengandalkan perilaku yang tidak terdefinisi atau tidak dijamin juga tidak apa-apa, tetapi itu akan dihargai jika Anda menyebutkannya dalam jawaban Anda.

Apa saja metode untuk menghasilkan set data yang dijelaskan di atas secara efisien? Martin Smith menunjukkan bahwa prosedur tersimpan CLR mungkin bukan pendekatan yang baik karena overhead memproses begitu banyak baris.

Joe Obbish
sumber

Jawaban:

7

Solusi Anda berjalan selama 35 detik di laptop saya. Kode berikut ini membutuhkan waktu 26 detik (termasuk membuat dan mengisi tabel sementara):

Meja sementara

DROP TABLE IF EXISTS #T1, #T2, #T3, #T4;

CREATE TABLE #T1 (string varchar(6) NOT NULL PRIMARY KEY);
CREATE TABLE #T2 (string varchar(6) NOT NULL PRIMARY KEY);
CREATE TABLE #T3 (string varchar(6) NOT NULL PRIMARY KEY);
CREATE TABLE #T4 (string varchar(6) NOT NULL PRIMARY KEY);

INSERT #T1 (string)
VALUES
    ('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'),
    ('H'), ('I'), ('J'), ('K'), ('L'), ('M'), ('N'),
    ('O'), ('P'), ('Q'), ('R'), ('S'), ('T'), ('U'),
    ('V'), ('W'), ('X'), ('Y'), ('Z');

INSERT #T2 (string)
SELECT T1a.string + T1b.string
FROM #T1 AS T1a, #T1 AS T1b;

INSERT #T3 (string)
SELECT #T2.string + #T1.string
FROM #T2, #T1;

INSERT #T4 (string)
SELECT #T3.string + #T1.string
FROM #T3, #T1;

Idenya adalah untuk mempopulasikan kombinasi berurut hingga empat karakter.

Kode utama

SELECT TOP (100000000)
    UA.string + UA.string2
FROM
(
    SELECT U.Size, U.string, string2 = '' FROM 
    (
        SELECT Size = 1, string FROM #T1
        UNION ALL
        SELECT Size = 2, string FROM #T2
        UNION ALL
        SELECT Size = 3, string FROM #T3
        UNION ALL
        SELECT Size = 4, string FROM #T4
    ) AS U
    UNION ALL
    SELECT Size = 5, #T1.string, string2 = #T4.string
    FROM #T1, #T4
    UNION ALL
    SELECT Size = 6, #T2.string, #T4.string
    FROM #T2, #T4
) AS UA
ORDER BY 
    UA.Size, 
    UA.string, 
    UA.string2
OPTION (NO_PERFORMANCE_SPOOL, MAXDOP 1);

Itu adalah penyatuan pelestarian pesanan * sederhana dari empat tabel yang dihitung sebelumnya, dengan string 5 karakter dan 6 karakter diturunkan sesuai kebutuhan. Memisahkan awalan dari akhiran menghindari penyortiran.

Rencana eksekusi

100 juta baris


* Tidak ada dalam SQL di atas yang menentukan serikat pengawet pesanan secara langsung. Pengoptimal memilih operator fisik dengan properti yang cocok dengan spesifikasi permintaan SQL, termasuk urutan tingkat atas oleh. Di sini, ia memilih penggabungan yang diterapkan oleh penggabung bergabung dengan operator fisik untuk menghindari penyortiran.

Jaminannya adalah bahwa rencana eksekusi memberikan kueri semantik dan pesanan tingkat atas menurut spesifikasi. Mengetahui bahwa penggabungan gabung dengan concat mempertahankan pesanan memungkinkan penulis kueri mengantisipasi rencana eksekusi, tetapi pengoptimal hanya akan memberikan jika harapan itu valid.

Paul White 9
sumber
6

Saya akan memposting jawaban untuk memulai. Pikiran pertama saya adalah bahwa mungkin untuk mengambil keuntungan dari sifat menjaga urutan loop bersatu bergabung bersama dengan beberapa tabel pembantu yang memiliki satu baris untuk setiap huruf. Bagian yang sulit akan menjadi pengulangan sedemikian rupa sehingga hasilnya dipesan panjang dan menghindari duplikat. Misalnya, ketika bergabung dengan CTE yang mencakup semua 26 huruf kapital bersama dengan '', Anda dapat menghasilkan 'A' + '' + 'A'dan '' + 'A' + 'A'yang tentu saja string yang sama.

Keputusan pertama adalah tempat menyimpan data pembantu. Saya mencoba menggunakan tabel temp tetapi ini memiliki dampak negatif yang mengejutkan pada kinerja, meskipun data masuk ke dalam satu halaman. Tabel temp berisi data di bawah ini:

SELECT 'A'
UNION ALL SELECT 'B'
...
UNION ALL SELECT 'Y'
UNION ALL SELECT 'Z'

Dibandingkan dengan menggunakan CTE, kueri membutuhkan waktu 3X lebih lama dengan tabel berkerumun dan 4X lebih lama dengan heap. Saya tidak percaya masalahnya adalah data ada di disk. Itu harus dibaca ke dalam memori sebagai satu halaman dan diproses dalam memori untuk seluruh paket. Mungkin SQL Server dapat bekerja dengan data dari operator Constant Scan lebih efisien daripada yang dapat dilakukan dengan data yang disimpan di halaman-halaman toko baris biasa.

Menariknya, SQL Server memilih untuk menempatkan hasil yang dipesan dari tabel tempdb halaman tunggal dengan data yang dipesan ke dalam gulungan tabel:

spoool buruk

SQL Server sering menempatkan hasil untuk tabel dalam dari gabungan bergabung ke dalam spool tabel, bahkan jika tampaknya tidak masuk akal untuk melakukannya. Saya pikir pengoptimal membutuhkan sedikit pekerjaan di bidang ini. Saya menjalankan kueri dengan NO_PERFORMANCE_SPOOLuntuk menghindari hit kinerja.

Satu masalah dengan menggunakan CTE untuk menyimpan data pembantu adalah bahwa data tidak dijamin dipesan. Saya tidak bisa memikirkan mengapa pengoptimal akan memilih untuk tidak memesannya dan dalam semua pengujian saya data diproses dalam urutan yang saya tulis CTE:

urutan pemindaian konstan

Namun, sebaiknya jangan mengambil risiko apa pun, terutama jika ada cara untuk melakukannya tanpa overhead kinerja yang besar. Dimungkinkan untuk memesan data dalam tabel turunan dengan menambahkan TOPoperator yang berlebihan . Sebagai contoh:

(SELECT TOP (26) CHR FROM FIRST_CHAR ORDER BY CHR)

Penambahan kueri itu harus menjamin bahwa hasilnya akan dikembalikan dalam urutan yang benar. Saya berharap semua jenis akan memiliki dampak kinerja negatif yang besar. Pengoptimal kueri juga mengharapkan ini berdasarkan pada perkiraan biaya:

jenis mahal

Sangat mengejutkan, saya tidak bisa mengamati perbedaan yang signifikan secara statistik dalam waktu cpu atau runtime dengan atau tanpa pemesanan eksplisit. Jika ada, permintaan tampaknya berjalan lebih cepat dengan ORDER BY! Saya tidak punya penjelasan untuk perilaku ini.

Bagian rumit dari masalah adalah untuk mencari cara memasukkan karakter kosong ke tempat yang tepat. Seperti disebutkan sebelumnya sederhana CROSS JOINakan menghasilkan data rangkap. Kita tahu bahwa string 100000000 akan memiliki panjang enam karakter karena:

26 + 26 ^ 2 + 26 ^ 3 + 26 ^ 4 + 26 ^ 5 = 914654 <100000000

tapi

26 + 26 ^ 2 + 26 ^ 3 + 26 ^ 4 + 26 ^ 5 + 26 ^ 6 = 321272406> 100000000

Karena itu kita hanya perlu bergabung dengan surat CTE enam kali. Misalkan kita bergabung ke CTE enam kali, ambil satu huruf dari masing-masing CTE, dan menyatukan semuanya. Misalkan huruf paling kiri tidak kosong. Jika salah satu dari huruf berikutnya kosong, itu artinya string tersebut kurang dari enam karakter sehingga merupakan duplikat. Oleh karena itu, kami dapat mencegah duplikat dengan menemukan karakter non-kosong pertama dan memerlukan semua karakter setelah itu juga tidak kosong. Saya memilih untuk melacak ini dengan menetapkan FLAGkolom ke salah satu CTE dan dengan menambahkan tanda centang pada WHEREklausa. Ini harus lebih jelas setelah melihat kueri. Kueri terakhir adalah sebagai berikut:

WITH FIRST_CHAR (CHR) AS
(
    SELECT 'A'
    UNION ALL SELECT 'B'
    UNION ALL SELECT 'C'
    UNION ALL SELECT 'D'
    UNION ALL SELECT 'E'
    UNION ALL SELECT 'F'
    UNION ALL SELECT 'G'
    UNION ALL SELECT 'H'
    UNION ALL SELECT 'I'
    UNION ALL SELECT 'J'
    UNION ALL SELECT 'K'
    UNION ALL SELECT 'L'
    UNION ALL SELECT 'M'
    UNION ALL SELECT 'N'
    UNION ALL SELECT 'O'
    UNION ALL SELECT 'P'
    UNION ALL SELECT 'Q'
    UNION ALL SELECT 'R'
    UNION ALL SELECT 'S'
    UNION ALL SELECT 'T'
    UNION ALL SELECT 'U'
    UNION ALL SELECT 'V'
    UNION ALL SELECT 'W'
    UNION ALL SELECT 'X'
    UNION ALL SELECT 'Y'
    UNION ALL SELECT 'Z'
)
, ALL_CHAR (CHR, FLAG) AS
(
    SELECT '', 0 CHR
    UNION ALL SELECT 'A', 1
    UNION ALL SELECT 'B', 1
    UNION ALL SELECT 'C', 1
    UNION ALL SELECT 'D', 1
    UNION ALL SELECT 'E', 1
    UNION ALL SELECT 'F', 1
    UNION ALL SELECT 'G', 1
    UNION ALL SELECT 'H', 1
    UNION ALL SELECT 'I', 1
    UNION ALL SELECT 'J', 1
    UNION ALL SELECT 'K', 1
    UNION ALL SELECT 'L', 1
    UNION ALL SELECT 'M', 1
    UNION ALL SELECT 'N', 1
    UNION ALL SELECT 'O', 1
    UNION ALL SELECT 'P', 1
    UNION ALL SELECT 'Q', 1
    UNION ALL SELECT 'R', 1
    UNION ALL SELECT 'S', 1
    UNION ALL SELECT 'T', 1
    UNION ALL SELECT 'U', 1
    UNION ALL SELECT 'V', 1
    UNION ALL SELECT 'W', 1
    UNION ALL SELECT 'X', 1
    UNION ALL SELECT 'Y', 1
    UNION ALL SELECT 'Z', 1
)
SELECT TOP (100000000)
d6.CHR + d5.CHR + d4.CHR + d3.CHR + d2.CHR + d1.CHR
FROM (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d6
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d5
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d4
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d3
CROSS JOIN (SELECT TOP (27) FLAG, CHR FROM ALL_CHAR ORDER BY CHR) d2
CROSS JOIN (SELECT TOP (26) CHR FROM FIRST_CHAR ORDER BY CHR) d1
WHERE (d2.FLAG + d3.FLAG + d4.FLAG + d5.FLAG + d6.FLAG) =
    CASE 
    WHEN d6.FLAG = 1 THEN 5
    WHEN d5.FLAG = 1 THEN 4
    WHEN d4.FLAG = 1 THEN 3
    WHEN d3.FLAG = 1 THEN 2
    WHEN d2.FLAG = 1 THEN 1
    ELSE 0 END
OPTION (MAXDOP 1, FORCE ORDER, LOOP JOIN, NO_PERFORMANCE_SPOOL);

CTEs seperti dijelaskan di atas. ALL_CHARdigabung menjadi lima kali karena itu termasuk baris untuk karakter kosong. Karakter terakhir dalam string tidak boleh kosong sehingga CTE terpisah didefinisikan untuk itu FIRST_CHAR,. Kolom bendera tambahan di ALL_CHARdigunakan untuk mencegah duplikat seperti dijelaskan di atas. Mungkin ada cara yang lebih efisien untuk melakukan pemeriksaan ini tetapi pasti ada cara yang lebih tidak efisien untuk melakukannya. Satu upaya oleh saya dengan LEN()dan POWER()membuat kueri berjalan enam kali lebih lambat dari versi saat ini.

The MAXDOP 1dan FORCE ORDERpetunjuk penting untuk memastikan bahwa perintah yang diawetkan dalam query. Rencana taksiran beranotasi mungkin membantu untuk mengetahui mengapa gabungan tersebut berada dalam urutan saat ini:

estimasi beranotasi

Paket kueri sering dibaca dari kanan ke kiri tetapi permintaan baris terjadi dari kiri ke kanan. Idealnya, SQL Server akan meminta tepat 100 juta baris dari d1operator pemindaian konstan. Saat Anda bergerak dari kiri ke kanan, saya berharap lebih sedikit baris yang diminta dari masing-masing operator. Kita bisa melihat ini dalam rencana eksekusi yang sebenarnya . Selain itu, di bawah ini adalah tangkapan layar dari SQL Sentry Plan Explorer:

penjelajah

Kami mendapat tepat 100 juta baris dari d1 yang merupakan hal yang baik. Perhatikan bahwa rasio baris antara d2 dan d3 hampir persis 27: 1 (165336 * 27 = 4464072) yang masuk akal jika Anda berpikir tentang cara kerja sambungan silang. Rasio baris antara d1 dan d2 adalah 22,4 yang mewakili beberapa pekerjaan yang sia-sia. Saya percaya baris tambahan berasal dari duplikat (karena karakter kosong di tengah-tengah string) yang tidak membuatnya melewati operator bergabung loop bersarang yang melakukan penyaringan.

The LOOP JOINpetunjuk teknis yang tidak perlu karena CROSS JOINdapat hanya dilaksanakan sebagai loop bergabung dalam SQL Server. The NO_PERFORMANCE_SPOOLadalah untuk mencegah meja yang tidak perlu spooling. Menghilangkan spool hint membuat kueri membutuhkan waktu 3X lebih lama di mesin saya.

Kueri akhir memiliki waktu cpu sekitar 17 detik dan total waktu berlalu 18 detik. Saat itulah menjalankan kueri melalui SSMS dan membuang set hasil. Saya sangat tertarik melihat metode lain untuk menghasilkan data.

Joe Obbish
sumber
2

Saya punya solusi yang dioptimalkan untuk mendapatkan kode string untuk nomor tertentu hingga 217.180.147.158 (8 karakter). Tapi saya tidak bisa mengalahkan waktu Anda:

Di mesin saya, dengan SQL Server 2014, permintaan Anda membutuhkan waktu 18 detik, sedangkan milik saya membutuhkan waktu 3m 46s. Kedua queri menggunakan flag jejak tidak berdokumen 8690 karena 2014 tidak mendukung NO_PERFORMANCE_SPOOLpetunjuk.

Berikut kodenya:

/* precompute offsets and powers to simplify final query */
CREATE TABLE #ExponentsLookup (
    offset          BIGINT NOT NULL,
    offset_end      BIGINT NOT NULL,
    position        INTEGER NOT NULL,
    divisor         BIGINT NOT NULL,
    shifts          BIGINT NOT NULL,
    chars           INTEGER NOT NULL,
    PRIMARY KEY(offset, offset_end, position)
);

WITH base_26_multiples AS ( 
    SELECT  number  AS exponent,
            CAST(POWER(26.0, number) AS BIGINT) AS multiple
    FROM    master.dbo.spt_values
    WHERE   [type] = 'P'
            AND number < 8
),
num_offsets AS (
    SELECT  *,
            -- The maximum posible value is 217180147159 - 1
            LEAD(offset, 1, 217180147159) OVER(
                ORDER BY exponent
            ) AS offset_end
    FROM    (
                SELECT  exponent,
                        SUM(multiple) OVER(
                            ORDER BY exponent
                        ) AS offset
                FROM    base_26_multiples
            ) x
)
INSERT INTO #ExponentsLookup(offset, offset_end, position, divisor, shifts, chars)
SELECT  ofst.offset, ofst.offset_end,
        dgt.number AS position,
        CAST(POWER(26.0, dgt.number) AS BIGINT)     AS divisor,
        CAST(POWER(256.0, dgt.number) AS BIGINT)    AS shifts,
        ofst.exponent + 1                           AS chars
FROM    num_offsets ofst
        LEFT JOIN master.dbo.spt_values dgt --> as many rows as resulting chars in string
            ON [type] = 'P'
            AND dgt.number <= ofst.exponent;

/*  Test the cases in table example */
SELECT  /*  1.- Get the base 26 digit and then shift it to align it to 8 bit boundaries
            2.- Sum the resulting values
            3.- Bias the value with a reference that represent the string 'AAAAAAAA'
            4.- Take the required chars */
        ref.[row_number],
        REVERSE(SUBSTRING(REVERSE(CAST(SUM((((ref.[row_number] - ofst.offset) / ofst.divisor) % 26) * ofst.shifts) +
            CAST(CAST('AAAAAAAA' AS BINARY(8)) AS BIGINT) AS BINARY(8))),
            1, MAX(ofst.chars))) AS string
FROM    (
            VALUES(1),(2),(25),(26),(27),(28),(51),(52),(53),(54),
            (18278),(18279),(475253),(475254),(475255),
            (100000000), (CAST(217180147158 AS BIGINT))
        ) ref([row_number])
        LEFT JOIN #ExponentsLookup ofst
            ON ofst.offset <= ref.[row_number]
            AND ofst.offset_end > ref.[row_number]
GROUP BY
        ref.[row_number]
ORDER BY
        ref.[row_number];

/*  Test with huge set  */
WITH numbers AS (
    SELECT  TOP(100000000)
            ROW_NUMBER() OVER(
                ORDER BY x1.number
            ) AS [row_number]
    FROM    master.dbo.spt_values x1
            CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 676) x2
            CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 676) x3
    WHERE   x1.number < 219
)
SELECT  /*  1.- Get the base 26 digit and then shift it to align it to 8 bit boundaries
            2.- Sum the resulting values
            3.- Bias the value with a reference that represent the string 'AAAAAAAA'
            4.- Take the required chars */
        ref.[row_number],
        REVERSE(SUBSTRING(REVERSE(CAST(SUM((((ref.[row_number] - ofst.offset) / ofst.divisor) % 26) * ofst.shifts) +
            CAST(CAST('AAAAAAAA' AS BINARY(8)) AS BIGINT) AS BINARY(8))),
            1, MAX(ofst.chars))) AS string
FROM    numbers ref
        LEFT JOIN #ExponentsLookup ofst
            ON ofst.offset <= ref.[row_number]
            AND ofst.offset_end > ref.[row_number]
GROUP BY
        ref.[row_number]
ORDER BY
        ref.[row_number]
OPTION (QUERYTRACEON 8690);

Kuncinya di sini adalah untuk memulai di mana permutasi yang berbeda dimulai:

  1. Saat Anda harus mengeluarkan satu karakter, Anda memiliki 26 ^ 1 permutasi yang dimulai pada 26 ^ 0.
  2. Ketika Anda harus menghasilkan 2 karakter Anda memiliki 26 ^ 2 permutasi yang dimulai pada 26 ^ 0 + 26 ^ 1
  3. Ketika Anda harus menghasilkan 3 karakter Anda memiliki 26 ^ 3 permutasi yang dimulai pada 26 ^ 0 + 26 ^ 1 + 26 ^ 2
  4. ulangi untuk n karakter

Trik lain yang digunakan adalah dengan hanya menggunakan jumlah untuk mendapatkan nilai yang tepat alih-alih mencoba untuk menggabungkan. Untuk mencapai ini, saya cukup mengimbangi digit dari basis 26 ke basis 256 dan menambahkan nilai ascii 'A' untuk setiap digit. Jadi kita mendapatkan representasi biner dari string yang kita cari. Setelah itu beberapa manipulasi string menyelesaikan proses.

Adán Bucio
sumber
-1

ok, ini skrip terbaru saya.

Tanpa loop, Tanpa Rekursif.

Ini hanya berfungsi untuk 6 karakter

Kekurangan terbesar adalah dibutuhkan sekitar 22 menit untuk 1,00,00,000

Kali ini skrip saya sangat pendek.

SET NoCount on

declare @z int=26
declare @start int=@z+1 
declare @MaxLimit int=10000000

SELECT TOP (@MaxLimit) IDENTITY(int,1,1) AS N
    INTO NumbersTest1
    FROM     master.dbo.spt_values x1   
   CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 500) x2
            CROSS JOIN (SELECT number FROM master.dbo.spt_values WHERE [type] = 'P' AND number < 500) x3
    WHERE   x1.number < 219
ALTER TABLE NumbersTest1 ADD CONSTRAINT PK_NumbersTest1 PRIMARY KEY CLUSTERED (N)


select N, strCol from NumbersTest1
cross apply
(
select 
case when IntCol6>0 then  char((IntCol6%@z)+64) else '' end 
+case when IntCol5=0 then 'Z' else isnull(char(IntCol5+64),'') end 
+case when IntCol4=0 then 'Z' else isnull(char(IntCol4+64),'') end 
+case when IntCol3=0 then 'Z' else isnull(char(IntCol3+64),'') end 
+case when IntCol2=0 then 'Z' else isnull(char(IntCol2+64),'') end 
+case when IntCol1=0 then 'Z' else isnull(char(IntCol1+64),'') end strCol
from
(
select  IntCol1,IntCol2,IntCol3,IntCol4
,case when IntCol5>0 then  IntCol5%@z else null end IntCol5

,case when IntCol5/@z>0 and  IntCol5%@z=0 then  IntCol5/@z-1 
when IntCol5/@z>0 then IntCol5/@z
else null end IntCol6
from
(
select IntCol1,IntCol2,IntCol3
,case when IntCol4>0 then  IntCol4%@z else null end IntCol4

,case when IntCol4/@z>0 and  IntCol4%@z=0 then  IntCol4/@z-1 
when IntCol4/@z>0 then IntCol4/@z
else null end IntCol5
from
(
select IntCol1,IntCol2
,case when IntCol3>0 then  IntCol3%@z else null end IntCol3
,case when IntCol3/@z>0 and  IntCol3%@z=0 then  IntCol3/@z-1 
when IntCol3/@z>0 then IntCol3/@z
else null end IntCol4

from
(
select IntCol1
,case when IntCol2>0 then  IntCol2%@z else null end IntCol2
,case when IntCol2/@z>0 and  IntCol2%@z=0 then  IntCol2/@z-1 
when IntCol2/@z>0 then IntCol2/@z
else null end IntCol3

from
(
select case when N>0 then N%@z else null end IntCol1
,case when N%@z=0 and  (N/@z)>1 then (N/@z)-1 else  (N/@z) end IntCol2 

)Lv2
)Lv3
)Lv4
)Lv5
)LV6

)ca

DROP TABLE NumbersTest1
KumarHarsh
sumber
Sepertinya tabel yang diturunkan akan dikonversi menjadi skalar komputasi tunggal yang lebih dari 400.000 karakter kode. Saya menduga ada banyak overhead untuk perhitungan itu. Anda mungkin ingin mencoba sesuatu yang mirip dengan yang berikut: dbfiddle.uk/… Jangan ragu untuk mengintegrasikan komponen-komponen itu ke dalam jawaban Anda.
Joe Obbish