İlk 100 milyon pozitif tamsayıyı dizelere nasıl dönüştürebilirim?


13

Bu, gerçek sorundan biraz saptırmadır. Bağlam sağlama yardımcı oluyorsa, bu verilerin oluşturulması, dizelerin işlenmesi için performans testi yöntemleri, imleç içinde kendilerine bir işlem uygulanması gereken dizeler oluşturmak veya hassas veriler için benzersiz, anonim ad değiştirmeleri oluşturmak için yararlı olabilir. Ben sadece SQL Serverlar içinde veri oluşturmak için verimli yolları ile ilgileniyorum, lütfen neden bu verileri oluşturmak için sorma.

Biraz resmi bir tanımla başlamaya çalışacağım. Bir dize, yalnızca A - Z'den büyük harflerden oluşuyorsa diziye dahil edilir. Serinin ilk terimi "A" dır. Dizi, önce uzunluk ve tipik alfabetik sıraya göre sıralanmış tüm geçerli dizelerden oluşur. Dizeler adlı bir sütundaki tabloda yer alıyorsa STRING_COL, sıra T-SQL'de olarak tanımlanabilir ORDER BY LEN(STRING_COL) ASC, STRING_COL ASC.

Daha az biçimsel bir tanım vermek için excel'deki alfabetik sütun başlıklarına bakınız. Seri aynı kalıptır. Bir tamsayıyı taban 26 numarasına nasıl dönüştürebileceğinizi düşünün:

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

Analoji tam olarak mükemmel değil çünkü "A" ilk on'da 0'dan farklı davranıyor. Aşağıda, umarım daha açık hale getirecek seçili değerlerin bir tablosu bulunmaktadır:

╔════════════╦════════╗
 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 
╚════════════╩════════╝

Amaç, SELECTyukarıda tanımlanan sırada ilk 100000000 dizeyi döndüren bir sorgu yazmaktır . Testimi SSMS'de sorguları çalıştırarak sonuç kümesi bir tabloya kaydetmek yerine atıldı:

sonuç kümesini sil

İdeal olarak sorgu makul derecede verimli olacaktır. Burada verimli bir seri sorgu için cpu zaman ve paralel bir sorgu için geçen zaman tanımlamak. İstediğiniz belgelenmemiş hileleri kullanabilirsiniz. Tanımsız veya garanti edilmeyen davranışlara güvenmek de iyidir, ancak cevabınızda bunu çağırırsanız takdir edilecektir.

Yukarıda açıklanan veri kümesini verimli bir şekilde oluşturmanın bazı yöntemleri nelerdir? Martin Smith , bir CLR saklı prosedürünün, bu kadar çok satırın işlenmesi nedeniyle muhtemelen iyi bir yaklaşım olmadığını belirtti.

Yanıtlar:


7

Çözümünüz dizüstü bilgisayarımda 35 saniye çalışıyor . Aşağıdaki kod 26 saniye sürer (geçici tabloların oluşturulması ve doldurulması dahil):

Geçici tablolar

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;

Buradaki fikir, dört karaktere kadar sıralı kombinasyonları önceden doldurmaktır.

Ana kod

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

Bu, önceden hesaplanmış dört tablonun basit bir düzen koruyucu birleşimidir *, 5 karakter ve 6 karakter dizeleri gerektiği gibi türetilmiştir. Ön ekin sonekten ayrılması sıralamayı önler.

Yürütme planı

100 milyon satır


* Yukarıdaki SQL'de doğrudan sipariş koruma birliğini belirten hiçbir şey yoktur . Optimize edici, üst düzey sıralama ölçütü de dahil olmak üzere SQL sorgu belirtimiyle eşleşen özelliklere sahip fiziksel işleçleri seçer. Burada, sıralamayı önlemek için birleştirme birleştirme fiziksel operatörü tarafından uygulanan birleştirme seçer.

Garanti, yürütme planının, soruna anlamsal ve üst düzey düzeni belirtime göre sunmasıdır. Birleştirme birleştirme concat koruma sırasını bildiğini bilmek, sorgu yazarının bir yürütme planı öngörmesini sağlar, ancak iyileştirici yalnızca beklentinin geçerli olması durumunda teslim eder.


6

Başlamak için bir cevap göndereceğim. İlk düşüncem, her harf için bir sıra olan birkaç yardımcı tablo ile birlikte iç içe bir döngü birleşiminin sipariş koruma doğasından faydalanabilmem gerektiğiydi. Zor kısım, sonuçlar uzunluğa göre sıralanacak ve kopyalardan kaçınacak şekilde ilmekleyecekti. Örneğin, '' ile birlikte 26 büyük harf içeren bir CTE'yi çapraz olarak birleştirirken, sonuçta 'A' + '' + 'A've '' + 'A' + 'A'elbette aynı dize olan sonuç elde edebilirsiniz .

İlk karar yardımcı verilerin nerede saklanacağıydı. Bir geçici tablo kullanmayı denedim, ancak veriler tek bir sayfaya sığsa bile, performans üzerinde şaşırtıcı derecede olumsuz bir etkisi oldu. Geçici tablo aşağıdaki verileri içeriyordu:

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

CTE kullanımıyla karşılaştırıldığında, sorgu kümelenmiş bir tabloyla 3 kat ve bir yığınla 4 kat daha uzun sürdü. Sorunun verinin disk üzerinde olduğuna inanmıyorum. Hafızaya tek bir sayfa olarak okunmalı ve tüm plan için hafızada işlenmelidir. SQL Server, bir Sabit Tarama operatörünün verileriyle, tipik satır mağaza sayfalarında depolanan verilerle olduğundan daha verimli çalışabilir.

İlginç bir şekilde, SQL Server sipariş edilen verileri içeren tek bir sayfa tempdb tablosundan sipariş edilen sonuçları bir tablo makarasına koymayı seçer:

kötü spoool

SQL Server, çapraz birleştirmenin iç tablosu için sonuçları, bunu yapmak saçma gibi görünse bile, bir tablo makarasına koyar. Optimizer'ın bu alanda biraz çalışmaya ihtiyacı olduğunu düşünüyorum. Ben NO_PERFORMANCE_SPOOLperformans isabet önlemek için ile sorgu çalıştırdı .

Yardımcı verileri depolamak için CTE kullanmanın bir sorunu, verilerin sipariş edileceğinin garanti edilmemesidir. Optimize edicinin neden sipariş vermemeyi seçtiğini düşünemiyorum ve tüm testlerimde veriler CTE'yi yazdığım sırada işlendi:

sürekli tarama sırası

Ancak, özellikle büyük bir performans yükü olmadan bunu yapmanın bir yolu varsa, herhangi bir şans almamanız en iyisidir. Gereksiz bir TOPoperatör ekleyerek türetilmiş bir tablodaki verileri sipariş etmek mümkündür . Örneğin:

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

Sorguya eklenmesi, sonuçların doğru sırada döndürülmesini garanti etmelidir. Her türlü performansın olumsuz bir etkisi olmasını bekliyordum. Sorgu optimize edici de tahmini maliyetlere göre bunu bekledi:

pahalı çeşitler

Çok şaşırtıcı bir şekilde, cpu zamanı veya çalışma süresinde açık siparişle veya sipariş olmadan istatistiksel olarak anlamlı bir fark gözlemleyemedim. Bir şey varsa, sorgu ile daha hızlı çalışıyor gibiydi ORDER BY! Bu davranış için hiçbir açıklamam yok.

Sorunun zor kısmı, boş karakterlerin doğru yerlere nasıl ekleneceğini bulmaktı. Daha önce de belirtildiği gibi, basit bir CROSS JOINveri yinelenir. 100000000. karakter dizisinin altı karakter uzunluğunda olacağını biliyoruz çünkü:

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

fakat

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

Bu nedenle CTE harfine sadece altı kez katılmamız gerekir. CTE'ye altı kez katıldığımızı, her CTE'den bir mektup aldığımızı ve hepsini bir araya getirdiğimizi varsayalım. En soldaki harfin boş olmadığını varsayalım. Sonraki harflerden herhangi biri boşsa, dizenin altı karakterden daha kısa olduğu ve yinelenen bir harf olduğu anlamına gelir. Bu nedenle, ilk boş olmayan karakteri bularak ve boş kalmadan sonra tüm karakterleri isteyerek yinelemeleri önleyebiliriz. FLAGCTE'lerden birine bir sütun atayarak ve WHEREmaddeye bir onay ekleyerek bunu izlemeyi seçtim . Sorguya baktıktan sonra bu daha açık olmalıdır. Son sorgu aşağıdaki gibidir:

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

CTE'ler yukarıda tarif edildiği gibidir. ALL_CHARboş bir karakter için bir satır içerdiğinden beş kez birleştirilir. Dizedeki son karakter hiçbir zaman boş bırakılmamalı, bu nedenle onun için ayrı bir CTE tanımlanmalıdır FIRST_CHAR. İçindeki ekstra bayrak sütunu, ALL_CHARyukarıda açıklandığı gibi kopyaları önlemek için kullanılır. Bu kontrolü yapmanın daha etkili bir yolu olabilir, ancak bunu yapmanın kesinlikle daha verimsiz yolları vardır. One benim tarafımdan girişimi LEN()ve POWER()güncel sürümü altı kat daha yavaş sorgu yolculuğuna devam etti.

MAXDOP 1Ve FORCE ORDERipuçları emin sipariş sorguda korunduğunu yapmak esastır. Açıklamalı bir tahmini plan, birleştirmelerin neden mevcut sıralarında olduklarını görmek için yardımcı olabilir:

açıklamalı tahmin

Sorgu planları genellikle sağdan sola okunur, ancak satır istekleri soldan sağa olur. İdeal olarak, SQL Server d1sabit tarama operatörünün tam 100 milyon satırını isteyecektir . Soldan sağa doğru hareket ettikçe, her operatörden daha az satır istenmesini bekliyorum. Bunu gerçek uygulama planında görebiliriz . Ayrıca, aşağıda SQL Sentry Plan Explorer'ın bir ekran görüntüsü yer almaktadır:

kâşif

D1'den tam olarak 100 milyon satır aldık, bu iyi bir şey. Çapraz birleştirmenin nasıl çalışacağını düşünüyorsanız, d2 ve d3 arasındaki satırların oranının neredeyse 27: 1 (165336 * 27 = 4464072) olduğuna dikkat edin. D1 ve d2 arasındaki satırların oranı 22.4'tür ve bu da boşa harcanmış bir işi temsil eder. Ben ekstra satırları filtreleme yapan iç içe döngü birleştirme operatörü geçmiş yapmak değil (dizelerin ortasında boş karakterler nedeniyle) yinelenen olduğuna inanıyorum.

LOOP JOINBir nedeni ipucu teknik olarak gereksiz CROSS JOINsadece bir döngü olarak uygulanacak kutu SQL Server katılmak. Bu NO_PERFORMANCE_SPOOLgereksiz masa biriktirmesini önlemek içindir. Biriktirme ipucunu atlamak sorguyu makinemde 3 kat daha uzun sürdü.

Son sorgunun işlemci süresi yaklaşık 17 saniye ve toplam geçen süresi 18 saniyedir. Bu, sorguyu SSMS aracılığıyla çalıştırıp sonuç kümesini atarken oldu. Verileri üretmenin diğer yöntemlerini görmekle çok ilgileniyorum.


2

217,180,147,158 (8 karakter) kadar herhangi bir belirli sayı için dize kodu elde etmek için optimize edilmiş bir çözüm var. Ama zamanını yenemem:

Makinemde, SQL Server 2014 ile sorgunuz 18 saniye, benimki ise 3m 46s alır. Her iki sorgu da belgelenmemiş izleme bayrağı 8690 kullanır, çünkü 2014 NO_PERFORMANCE_SPOOLipucunu desteklemez .

İşte kod:

/* 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);

Buradaki hile, farklı permütasyonların başladığı yeri önceden hesaplamaktır:

  1. Tek bir karakter çıktısı almanız gerektiğinde, 26 ^ 0 ile başlayan 26 ^ 1 permütasyonunuz olur.
  2. 2 karakter çıkarmanız gerektiğinde 26 ^ 0 + 26 ^ 1 ile başlayan 26 ^ 2 permütasyonunuz olur.
  3. 3 karakter çıkarmanız gerektiğinde 26 ^ 0 + 26 ^ 1 + 26 ^ 2 ile başlayan 26 ^ 3 permütasyonunuz olur.
  4. n karakter için tekrarla

Kullanılan diğer hile ise toplamı kullanarak birleşmeye çalışmak yerine doğru değere ulaşmaktır. Bunu başarmak için basitçe taban 26'dan taban 256'ya kadar olan rakamları kaydırıyorum ve her basamak için 'A' ascii değerini ekliyorum. Böylece aradığımız dizenin ikili temsilini elde ederiz. Bundan sonra bazı dize manipülasyonları işlemi tamamlar.


-1

tamam, en son senaryom burada.

Döngü yok, Özyinelemesiz.

Sadece 6 karakter için çalışır

En büyük dezavantajı 1,00,00,000 için 22 dakika sürer

Bu sefer senaryom çok kısa.

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

Türetilmiş tablo, 400.000 karakterden fazla kod olan tek bir hesaplama skalerine dönüştürülür. Bu hesaplamanın çok fazla yükü olduğundan şüpheleniyorum. Aşağıdakine benzer bir şey denemek isteyebilirsiniz: dbfiddle.uk/… Bunun bileşenlerini cevabınıza entegre etmekten çekinmeyin.
Joe Obbish
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.