it-swarm.asia

Mengapa tabel angka "tidak ternilai"?

Penduduk kami pakar basis data memberi tahu kami bahwa tabel angka tidak ternilai . Saya tidak begitu mengerti mengapa. Ini tabel angka:

USE Model
GO

CREATE TABLE Numbers
(
    Number INT NOT NULL,
    CONSTRAINT PK_Numbers 
        PRIMARY KEY CLUSTERED (Number)
        WITH FILLFACTOR = 100
)

INSERT INTO Numbers
SELECT
    (a.Number * 256) + b.Number AS Number
FROM 
    (
        SELECT number
        FROM master..spt_values
        WHERE 
            type = 'P'
            AND number <= 255
    ) a (Number),
    (
        SELECT number
        FROM master..spt_values
        WHERE 
            type = 'P'
            AND number <= 255
    ) b (Number)
GO

Per posting blog, alasan yang diberikan adalah

Tabel angka benar-benar tak ternilai. Saya menggunakannya sepanjang waktu untuk manipulasi string, mensimulasikan fungsi jendela, mengisi tabel uji dengan banyak data, menghilangkan logika kursor, dan banyak tugas lain yang akan sangat sulit tanpanya.

Tapi saya tidak mengerti apa yang mereka gunakan, tepatnya - dapatkah Anda memberikan beberapa contoh spesifik yang menarik tentang "tabel angka" yang menghemat banyak pekerjaan di SQL Server - dan mengapa kita harus memilikinya?

112
Jeff Atwood

Saya telah melihat banyak kegunaan ketika Anda perlu memproyeksikan 'data yang hilang'. Misalnya. Anda memiliki deret waktu (misalnya log akses) dan Anda ingin menunjukkan jumlah klik per hari selama 30 hari terakhir (pikirkan dasbor analitik). Jika Anda melakukan select count(...) from ... group by day Anda akan mendapatkan hitungan untuk setiap hari, tetapi hasilnya hanya akan memiliki baris untuk setiap hari Anda benar-benar memiliki setidaknya satu akses. Di sisi lain jika Anda pertama memproyeksikan tabel hari dari tabel angka Anda (select dateadd(day, -number, today) as day from numbers) dan kemudian Anda pergi bergabung dengan perhitungan (atau menerapkan luar, apa pun yang Anda suka) maka Anda akan mendapatkan hasil yang memiliki 0 untuk hitungan untuk hari-hari Anda tidak memiliki akses. Ini hanya satu contoh. Tentu saja, orang mungkin berpendapat bahwa lapisan presentasi dasbor Anda dapat menangani hari-hari yang hilang dan hanya menunjukkan 0 sebagai gantinya, tetapi beberapa alat (mis. SSR) tidak akan bisa menangani ini.

Contoh lain yang pernah saya lihat menggunakan trik seri waktu yang sama (tanggal/waktu +/- nomor) untuk melakukan semua jenis perhitungan jendela. Secara umum, setiap kali dalam bahasa imperatif Anda akan menggunakan for for loop dengan jumlah iterasi yang terkenal, deklaratif dan set sifat SQL dapat menggunakan trik berdasarkan tabel angka.

BTW, saya merasa perlu untuk memanggil fakta bahwa meskipun menggunakan tabel angka itu terasa seperti eksekusi prosedural imperatif, jangan jatuh ke dalam kekeliruan dengan menganggapnya adalah keharusan. Biarkan saya memberi contoh:

int x;
for (int i=0;i<1000000;++i)
  x = i;
printf("%d",x);

Program ini akan menghasilkan 999999, yang dijamin cukup banyak.

Mari kita coba hal yang sama di SQL Server, menggunakan tabel angka. Pertama buat tabel 1.000.000 angka:

create table numbers (number int not null primary key);
go

declare @i int = 0
    , @j int = 0;

set nocount on;
begin transaction
while @i < 1000
begin
    set @j = 0;
    while @j < 1000
    begin
        insert into numbers (number) 
            values (@j*[email protected]);
        set @j += 1;
    end
    commit;
    raiserror (N'Inserted %d*1000', 0, 0, @i)
    begin transaction;
    set @i += 1;
end
commit
go

Sekarang mari kita lakukan 'for loop':

declare @x int;
select @x = number 
from numbers with(nolock);
select @x as [@x];

Hasilnya adalah:

@x
-----------
88698

Jika Anda sekarang memiliki momen WTF (setelah semua number adalah kunci primer yang dikelompokkan!), Triknya disebut - pemindaian urutan alokasi dan saya tidak memasukkan @j*[email protected] secara tidak sengaja ... Anda juga bisa menebak dan mengatakan hasilnya adalah karena paralelisme dan kadang-kadang boleh menjadi jawaban yang benar.

Ada banyak troll di bawah jembatan ini dan saya sebutkan beberapa di Pada SQL Server hubungan pendek operator boolean dan fungsi T-SQL tidak menyiratkan urutan tertentu dari eksekusi

82
Remus Rusanu

Saya telah menemukan tabel angka yang cukup berguna dalam berbagai situasi.

Di Mengapa saya harus mempertimbangkan menggunakan tabel angka bantu? , yang ditulis pada tahun 2004, saya menunjukkan beberapa contoh:

  • Mengurai string
  • Menemukan celah identitas
  • Menghasilkan rentang tanggal (mis. Mengisi tabel kalender, yang juga bisa sangat berharga)
  • Menghasilkan irisan waktu
  • Menghasilkan rentang IP

Di Kebiasaan buruk untuk menendang: menggunakan loop untuk mengisi tabel besar , saya menunjukkan bagaimana tabel angka dapat digunakan untuk membuat pekerjaan singkat dengan memasukkan banyak baris (yang bertentangan dengan pendekatan spontan menggunakan loop sementara).

Di Memproses daftar bilangan bulat: pendekatan saya dan Lebih lanjut tentang pemisahan daftar: pembatas khusus, mencegah duplikat, dan mempertahankan pesanan , saya menunjukkan cara menggunakan tabel angka untuk membagi sebuah string (misalnya seperangkat nilai yang dipisahkan koma) dan memberikan perbandingan kinerja antara ini dan metode lain. Info lebih lanjut tentang pemisahan dan penanganan string lainnya:

Dan di Tabel SQL Server Numbers, Dijelaskan - Bagian 1 , saya memberikan beberapa latar belakang tentang konsep dan memiliki posting masa depan di toko untuk detail aplikasi spesifik.

Ada banyak kegunaan lain, itu hanya beberapa yang cukup menonjol bagi saya untuk menulis tentang mereka.

Dan seperti @gbn, saya punya beberapa jawaban tentang stack overflow dan di situs ini yang menggunakan tabel angka juga.

Akhirnya, saya memiliki serangkaian posting blog tentang menghasilkan set tanpa perulangan, yang sebagian menunjukkan keunggulan kinerja menggunakan tabel angka dibandingkan dengan sebagian besar metode lainnya (Remus 'outlier yang aneh):

56
Aaron Bertrand

Berikut ini contoh bagus yang saya gunakan baru-baru ini dari Adam Machanic:

CREATE FUNCTION dbo.GetSubstringCount
(
    @InputString TEXT, 
    @SubString VARCHAR(200),
    @NoisePattern VARCHAR(20)
)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
    RETURN 
    (
        SELECT COUNT(*)
        FROM dbo.Numbers N
        WHERE
            SUBSTRING(@InputString, N.Number, LEN(@SubString)) = @SubString
            AND PATINDEX(@NoisePattern, SUBSTRING(@InputString, N.Number + LEN(@SubString), 1)) = 0
            AND 0 = 
                CASE 
                    WHEN @NoisePattern = '' THEN 0
                    ELSE PATINDEX(@NoisePattern, SUBSTRING(@InputString, N.Number - 1, 1))
                END
    )
END

Saya menggunakan sesuatu yang mirip dengan CTE untuk menemukan contoh substring tertentu (mis. "Temukan pipa ke-3 dalam string ini") untuk bekerja dengan data terbatas yang dikorelasikan:

declare @TargetStr varchar(8000), 
@SearchedStr varchar(8000), 
@Occurrence int
set @TargetStr='a'
set @SearchedStr='abbabba'
set @Occurrence=3;

WITH Occurrences AS (
SELECT Number,
       ROW_NUMBER() OVER(ORDER BY Number) AS Occurrence
FROM master.dbo.spt_values
WHERE Number BETWEEN 1 AND LEN(@SearchedStr) AND type='P'
  AND SUBSTRING(@SearchedStr,Number,LEN(@TargetStr))[email protected])
SELECT Number
FROM Occurrences
WHERE [email protected]

Jika Anda tidak memiliki tabel angka, alternatifnya adalah menggunakan semacam loop. Pada dasarnya, tabel angka memungkinkan Anda melakukan iterasi berbasis set, tanpa kursor atau loop.

26
JNK

Saya akan menggunakan tabel angka setiap kali saya membutuhkan SQL setara dengan Enumerable.Range. Sebagai contoh, saya hanya menggunakannya dalam jawaban di situs ini: menghitung jumlah permutasi

12
A-K