Saya perlu membuat beberapa data uji yang melibatkan hierarki. Saya bisa membuatnya mudah dan melakukan beberapa CROSS JOIN
s, tetapi itu akan memberi saya struktur yang benar-benar seragam / tanpa variasi apa pun. Itu tidak hanya tampak membosankan, tetapi kurangnya variasi dalam data pengujian terkadang menutupi masalah yang seharusnya ditemukan. Jadi, saya ingin membuat hierarki yang tidak seragam yang mengikuti aturan ini:
- 3 level
- Level 1 secara acak 5 - 20 node
- Level 2 adalah 1 - 10 node, acak per setiap node Level 1
- Level 3 adalah 1 - 5 node, acak per setiap node Level 2
- Semua cabang akan memiliki 3 level. Keseragaman secara mendalam ok pada saat ini.
- Mungkin ada tumpang tindih dalam nama-nama simpul anak pada tingkat tertentu (mis. Nama-nama simpul anak tidak perlu unik di semua simpul pada tingkat yang sama).
- Istilah "acak" didefinisikan di sini sebagai pseudo-acak, bukan acak unik. Ini perlu disebutkan karena istilah "acak" sering digunakan untuk berarti "pemesanan acak dari set yang diberikan yang tidak menghasilkan duplikat". Saya menerima bahwa acak = acak dan jika jumlah anak per setiap node Level 1 hanya 4, 7, dan 8, bahkan di 20 node pada Level 1 yang memiliki potensi penyebaran 1 - 10 anak per masing-masing node, maka itu baik-baik saja, karena itulah yang acak.
- Meskipun ini dapat dilakukan dengan cukup mudah dengan
WHILE
loop bersarang , preferensi adalah untuk menemukan pendekatan berbasis set. Secara umum, menghasilkan data uji tidak memiliki persyaratan untuk efisiensi yang akan dimiliki kode Produksi, tetapi memotret untuk pendekatan berbasis set kemungkinan akan lebih mendidik dan membantu di masa depan dengan menemukan pendekatan berbasis set untuk masalah. JadiWHILE
loop tidak dikesampingkan, tetapi hanya dapat digunakan jika tidak ada pendekatan berbasis set yang dimungkinkan. - Set-based = idealnya satu permintaan, terlepas dari CTE, BERLAKU, dll. Jadi, menggunakan tabel angka yang ada atau sebaris tidak masalah. Menggunakan pendekatan WHILE / CURSOR / prosedural tidak akan berfungsi. Saya kira staging bagian dari data ke dalam tabel temp atau variabel tabel baik-baik saja, asalkan semua operasi berbasis set, tidak ada loop. Namun, yang dikatakan, pendekatan kueri tunggal mungkin akan lebih disukai daripada beberapa kueri, kecuali jika dapat ditunjukkan bahwa pendekatan multi-kueri sebenarnya lebih baik. Harap juga diingat bahwa apa yang merupakan "lebih baik" biasanya subjektif ;-). Harap juga diingat bahwa penggunaan "biasanya" dalam kalimat sebelumnya juga subjektif.
- Setiap versi dan edisi SQL Server (2005 dan yang lebih baru, saya kira) akan dilakukan.
- Hanya murni T-SQL: tidak ada yang SQLCLR konyol !! Setidaknya dalam hal menghasilkan data. Membuat direktori dan file akan dilakukan menggunakan SQLCLR. Tapi di sini saya hanya fokus pada menghasilkan nilai-nilai apa yang harus dibuat.
- T-SQL Multi-statement TVF dianggap prosedural, tidak berbasis set, meskipun di luar mereka menutupi pendekatan prosedural dalam set. Ada saat-saat itu sangat tepat. Ini bukan salah satu dari waktu itu. Sejalan dengan itu, fungsi T-SQL Scalar juga tidak diperbolehkan, tidak hanya karena mereka juga prosedural, tetapi Query Optimizer kadang-kadang menyimpan nilainya dan mengulanginya sedemikian rupa sehingga hasilnya tidak seperti yang diharapkan.
- T-SQL Inline TVFs (alias iTVFs) adalah okey-dokey karena mereka berbasis-set, dan secara efektif sama dengan menggunakan
[ CROSS | OUTER ] APPLY
, yang dinyatakan di atas sebagai ok. - Eksekusi berulang dari query (ies) harus menghasilkan sebagian besar hasil yang berbeda dari jalankan sebelumnya.
- Pembaruan Klarifikasi 1: Kumpulan hasil akhir harus dinyatakan sebagai memiliki satu baris untuk setiap simpul Level3 yang berbeda, yang memiliki lintasan penuh mulai dari Level1. Ini berarti bahwa nilai Level1 dan Level2 perlu mengulangi satu atau lebih baris, kecuali dalam kasus hanya ada satu simpul Level2 tunggal yang hanya mengandung satu simpul Level3 tunggal.
- Pembaruan Klarifikasi 2: Ada preferensi yang sangat kuat untuk setiap node yang memiliki nama atau label, dan bukan hanya angka. Ini akan memungkinkan data uji yang dihasilkan menjadi lebih bermakna dan realistis.
Saya tidak yakin apakah info tambahan ini penting, tetapi untuk berjaga-jaga jika ada konteks, data pengujian terkait dengan jawaban saya pada pertanyaan ini:
Impor file XML ke SQL Server 2012
Meskipun tidak relevan pada titik ini, tujuan akhir menghasilkan hierarki ini adalah membuat struktur direktori untuk menguji metode sistem file rekursif. Level 1 dan 2 akan menjadi direktori, dan Level 3 pada akhirnya akan menjadi nama file. Saya telah mencari-cari (baik di sini maupun melalui Google) dan hanya menemukan satu referensi untuk menghasilkan hierarki acak:
Linux: buat hirarki direktori / file acak
Pertanyaan itu (pada StackOverflow) sebenarnya cukup dekat dalam hal hasil yang diinginkan karena itu juga berusaha membuat struktur direktori untuk pengujian. Tetapi pertanyaan itu (dan jawabannya) terfokus pada scripting Linux / Unix shell dan bukan pada dunia berbasis set yang kita tinggali.
Sekarang, saya tahu cara membuat data acak, dan saya sudah melakukannya untuk membuat konten file sehingga mereka juga dapat menunjukkan variasi. Bagian yang sulit di sini adalah bahwa jumlah elemen dalam setiap set adalah acak, bukan bidang tertentu. Dan , jumlah elemen dalam setiap node harus acak dari node lain pada level yang sama.
Contoh Hirarki
Level 1
Level 3
|---- A
| |-- 1
| | |--- I
| |
| |-- 2
| |--- III
| |--- VI
| |--- VII
| |--- IX
|
|---- B
| |-- 87
| |--- AAA
| |--- DDD
|
|---- C
|-- ASDF
| |--- 11
| |--- 22
| |--- 33
|
|-- QWERTY
| |--- beft
|
|-- ROYGBP
|--- Poi
|--- Moi
|--- Soy
|--- Joy
|--- Roy
Kumpulan Hasil Contoh Menggambarkan Hirarki Di Atas
Level 1 Level 2 Level 3
A 1 I
A 2 III
A 2 VI
A 2 VII
A 2 IX
B 87 AAA
B 87 DDD
C ASDF 11
C ASDF 22
C ASDF 33
C QWERTY beft
C ROYGBP Poi
C ROYGBP Moi
C ROYGBP Soy
C ROYGBP Joy
C ROYGBP Roy
sumber
TOP(n)
dengan benar dalam 2CROSS APPLY
detik. Tidak yakin apa yang saya lakukan berbeda / salah karena saya menyingkirkan kode itu begitu saya berhasil mengerjakan sesuatu. Saya akan memposting itu segera, sekarang setelah Anda memberikan pembaruan ini. Dan saya telah membersihkan sebagian besar komentar saya di atas.n
elemen melalui kondisi WHERE, dan 2) Saya memilikiname
komponen yang lebih terkontrol daripada pengacakan direktori dan / atau nama file .@Elemets
untuk mendapatkan serangkaian nama yang berbeda untuk setiap level yang dapat dipilih.Itu menarik.
Tujuan saya adalah untuk menghasilkan jumlah level tertentu dengan jumlah acak baris anak per setiap level dalam struktur hierarki yang terhubung dengan benar. Setelah struktur ini siap, mudah untuk menambahkan info tambahan ke dalamnya seperti nama file dan folder.
Jadi, saya ingin membuat tabel klasik untuk menyimpan pohon:
Karena kita berurusan dengan rekursi, CTE rekursif tampaknya merupakan pilihan alami.
Saya akan membutuhkan daftar angka . Angka dalam tabel harus dimulai dari 1. Harus ada setidaknya 20 angka dalam tabel:
MAX(LvlMax)
.Parameter untuk pembuatan data harus disimpan dalam tabel:
Perhatikan, bahwa kueri cukup fleksibel dan semua parameter dipisahkan menjadi satu tempat. Anda dapat menambahkan lebih banyak level jika perlu, cukup tambahkan baris parameter tambahan.
Untuk memungkinkan pembangkitan dinamis seperti itu, saya harus mengingat jumlah baris acak untuk level berikutnya, jadi saya memiliki kolom tambahan
ChildRowCount
.Membangkitkan keunikan
IDs
juga agak rumit. Saya mengkodekan batas 100 baris anak per 1 baris orang tua untuk menjaminIDs
tidak mengulangi. Ini tentang apaPOWER(100, CTE.Lvl)
. Akibatnya ada celah besar diIDs
. Angka itu bisa menjadiMAX(LvlMax)
, tetapi saya menempatkan 100 konstan dalam query untuk kesederhanaan. Jumlah level bukan kode-keras, tetapi ditentukan oleh@Intervals
.Rumus ini
menghasilkan angka floating point acak dalam rentang
[0..1)
, yang kemudian diskalakan ke interval yang diperlukan.Logika kueri itu sederhana. Itu rekursif. Langkah pertama menghasilkan satu set baris dari level pertama. Jumlah baris ditentukan oleh nomor acak di
TOP
. Juga, untuk setiap baris ada sejumlah acak baris anak yang disimpanChildRowCount
.Bagian rekursif digunakan
CROSS APPLY
untuk menghasilkan jumlah baris anak tertentu per setiap baris induk. Saya harus menggunakanWHERE Numbers.Number <= CTE.ChildRowCount
bukanTOP(CTE.ChildRowCount)
, karenaTOP
tidak diperbolehkan di bagian CTE rekursif. Tidak tahu tentang batasan SQL Server ini sebelumnya.WHERE CTE.ChildRowCount IS NOT NULL
menghentikan rekursi.SQL Fiddle
Hasil (bisa ada hingga 20 + 20 * 10 + 200 * 5 = 1220 baris jika Anda beruntung)
Membuat jalur lengkap alih-alih hierarki yang ditautkan
Jika kita hanya tertarik pada
N
level path lengkap yang dalam, kita dapat menghilangkanID
danParentID
dari CTE. Jika kami memiliki daftar kemungkinan nama dalam tabel tambahanNames
, mudah untuk memilihnya dari tabel ini dalam CTE. TheNames
tabel harus memiliki cukup baris untuk setiap tingkat: 20 untuk level 1, 10 untuk level 2, 5 untuk tingkat 3; 20 + 10 + 5 = 35 total. Tidak perlu memiliki rangkaian baris yang berbeda untuk setiap level, tetapi mudah untuk mengaturnya dengan benar, jadi saya melakukannya.SQL Fiddle Berikut ini adalah permintaan terakhir. Saya membagi
FullPath
menjadiFilePath
danFileName
.Hasil
sumber
INNER JOIN
detik di finalSELECT
. Akhirnya, dapatkah nama / label ditugaskan untuk setiap node sehingga mereka bukan hanya angka? Saya akan memperbarui pertanyaan untuk memperjelas kedua poin ini.FullPath
menjadiFilePath
danFileName
.Jadi inilah yang saya pikirkan. Dengan tujuan membuat struktur direktori, saya mencari "nama" yang dapat digunakan untuk direktori dan file. Karena saya tidak bisa mendapatkan
TOP(n)
pekerjaan diCROSS APPLY
s (saya pikir saya berusaha untuk mengkorelasikan kueri dengan menggunakan nilai dari orang tua sebagain
dalamTOP(n)
tetapi kemudian itu tidak acak), saya memutuskan untuk membuat jenis "angka" tabel yang akan memungkinkan suatuINNER JOIN
atauWHERE
kondisi untuk menghasilkan satu setn
elemen hanya dengan mengacak angka dan menetapkannya sebagaiWHERE table.Level = random_number
. Caranya adalah hanya ada 1 baris untuk Level1, 2 baris untuk Level2, 3 baris untuk Level3, dan seterusnya. Oleh karena itu, menggunakanWHERE LevelID = 3
akan memberi saya 3 baris, dan setiap baris memiliki nilai yang dapat saya gunakan sebagai nama direktori.MEMPERSIAPKAN
Bagian ini awalnya ditentukan sebaris, sebagai bagian dari CTE. Tetapi demi keterbacaan (sehingga Anda tidak perlu menelusuri banyak
INSERT
pernyataan untuk sampai ke beberapa baris dari permintaan sebenarnya), saya memecahnya menjadi tabel sementara lokal.QUERY UTAMA
Untuk Level 1 saya baru saja mengambil
[name]
nilaisys.objects
karena selalu ada banyak baris di sana. Tetapi, jika saya perlu lebih banyak kontrol atas nama-nama, saya hanya bisa memperluas#Elements
tabel untuk memuat level tambahan.QUERY DISESUAIKAN UNTUK MENGHASILKAN SETIAP JALUR, NAMA, dan ISI FILE
Untuk menghasilkan path lengkap untuk file dan isi file, saya membuat SELECT utama dari CTE hanya CTE lain dan menambahkan SELECT utama baru yang memberikan output yang tepat yang hanya perlu masuk ke file.
KREDIT TAMBAHAN
Meskipun bukan bagian dari persyaratan yang dinyatakan dalam pertanyaan, tujuannya (yang disebutkan) adalah membuat file untuk menguji fungsi Sistem File rekursif dengan. Jadi bagaimana kita mengambil set nama path, nama file, dan konten file hasil ini dan melakukan sesuatu dengannya? Kami hanya membutuhkan dua fungsi SQLCLR: satu untuk membuat folder dan satu lagi untuk membuat file.
Untuk membuat data ini berfungsi, saya memodifikasi utama
SELECT
CTE yang ditunjukkan langsung di atas sebagai berikut:sumber