Her düğümün rasgele sayıda çocuğu olduğu birden çok düzey hiyerarşisi oluşturun


16

Bir hiyerarşi içeren bazı test verileri oluşturmak gerekiyor. Bunu kolaylaştırabilir ve birkaç tane yapabilirim CROSS JOIN, ama bu bana tamamen üniform / varyasyon içermeyen bir yapı verecekti. Bu sadece donuk görünmekle kalmaz, aynı zamanda test verilerinde değişiklik olmaması bazen başka türlü bulunabilecek sorunları maskeler. Bu nedenle, bu kurallara uyan tek tip olmayan bir hiyerarşi oluşturmak istiyorum:

  • 3 seviye derin
    • Seviye 1 rastgele 5-20 düğümdür
    • Seviye 2, Seviye 1'in her düğümü için rastgele 1-10 düğümdür
    • Seviye 3, Seviye 2'nin her düğümü için rastgele 1 - 5 düğümdür
  • Tüm dallar 3 seviye derin olacak. Bu noktada derinlikteki tekdüzelik tamam.
  • Herhangi bir düzeydeki alt düğümlerin adlarında çakışma olabilir (yani alt düğümlerin adlarının aynı düzeydeki tüm düğümlerde benzersiz olması gerekmez).
  • "Rastgele" terimi burada benzersiz rastgele değil , sahte rastgele olarak tanımlanır . "Rastgele" terimi, genellikle "kopya üretmeyen belirli bir kümenin rasgele sıralaması" anlamında kullanıldığından bahsedilmelidir. Rastgele = rastgele kabul ediyorum ve Seviye 1'in her düğümü için çocuk sayısı sadece 4, 7 ve 8 ise, Seviye 1'deki 20 düğüm boyunca bile, bu düğümlerin her biri için 1 - 10 çocuk potansiyel yayılımı varsa, o zaman bu iyidir, çünkü rastgele olan budur.
  • Bu, iç içe WHILEdöngülerle oldukça kolay bir şekilde yapılabilse de , tercih küme tabanlı bir yaklaşım bulmaktır. Genel olarak konuşmak gerekirse, test verilerinin üretilmesi, Üretim kodunun sahip olacağı verimlilik için gerekliliklere sahip değildir, ancak set tabanlı bir yaklaşım için çekim yapmak, muhtemelen sorunlara set tabanlı yaklaşımlar bulma konusunda daha eğitici ve yardımcı olacaktır. YaniWHILE döngüler reddedilmez, ancak yalnızca kümeye dayalı bir yaklaşım mümkün değilse kullanılabilir.
  • Set tabanlı = ideal olarak CTE'ler, UYGULAMALAR vb. Ne olursa olsun tek bir sorgu. Bu nedenle mevcut veya satır içi numaralar tablosu kullanmak iyidir. WHILE / CURSOR / prosedürel yaklaşım kullanmak işe yaramaz. İşlemlerin tüm set tabanlı olduğu, döngüler olmadığı sürece, verilerin geçici bölümlerini geçici tablolara veya tablo değişkenlerine iyi şekilde yerleştirdiğini varsayalım. Bununla birlikte, çok sorgu yaklaşımının aslında daha iyi olduğu gösterilemezse, tek sorgu yaklaşımı muhtemelen birden çok sorguya tercih edilecektir. Ayrıca, "daha iyi" olan şeyin genellikle öznel ;-) olduğunu da unutmayın. Ayrıca, önceki cümle içinde "tipik" kullanımının da öznel olduğunu lütfen unutmayın.
  • Herhangi bir sürüm ve SQL Server sürümü (2005 ve daha yeni, sanırım) yapacağız.
  • Sadece saf T-SQL: o aptal SQLCLR şeylerin hiçbiri !! En azından verilerin oluşturulması açısından. Dizinlerin ve dosyaların oluşturulması SQLCLR kullanılarak yapılacaktır. Ama burada sadece ne yaratacağımın değerlerini üretmeye odaklanıyorum.
  • T-SQL Çok İfade TVF prosedürel olarak kabul edilir, set tabanlı değil, dışarıdan bir sette prosedürel yaklaşımı maskelemelerine rağmen. Bunun kesinlikle uygun olduğu zamanlar vardır. Bu o zamanlardan biri değil. Aynı satırlar boyunca, T-SQL Skaler fonksiyonlarına da sadece prosedürel oldukları için değil, aynı zamanda Query Optimizer bazen değerlerini önbelleğe alır ve çıktı beklendiği gibi olmayacak şekilde tekrarlar.
  • T-SQL Inline TVF'ler (diğer adıyla iTVF'ler), set tabanlı oldukları için okey-dokey'dir ve etkili bir şekilde, [ CROSS | OUTER ] APPLYyukarıda ok olduğu belirtilen ifade ile aynıdır .
  • Sorgu (lar) ın tekrar tekrar yürütülmesi, önceki çalıştırmadan çoğunlukla farklı sonuç üretmelidir.
  • Açıklama Güncelleme 1: Son sonuç kümesi, Seviye3'ün her bir ayrı düğümü için bir satır içerdiği ve Seviye1'den başlayan tam yolun olduğu şeklinde ifade edilmelidir. Bu, yalnızca tek bir Level3 düğümü içeren tek bir Level2 düğümü olması durumu hariç, Level1 ve Level2 değerlerinin mutlaka bir veya daha fazla satırda tekrarlanacağı anlamına gelir.
  • Açıklama Güncelleme 2: Her bir düğüm için sadece bir numara değil, bir isim veya etikete sahip olmak için çok güçlü bir tercih vardır. Bu, elde edilen test verilerinin daha anlamlı ve gerçekçi olmasını sağlayacaktır.

Bu ek bilginin önemli olup olmadığından emin değilim, ancak bir bağlamın olmasına yardımcı olması durumunda, test verileri bu sorudaki cevabımla ilgilidir:

XML dosyalarını SQL Server 2012'ye aktarma

Bu noktada ilgili olmasa da, bu hiyerarşiyi oluşturmanın nihai amacı, özyinelemeli dosya sistemi yöntemlerini test etmek için bir dizin yapısı oluşturmaktır. Seviye 1 ve 2 dizinler olacak ve Seviye 3 dosya adı olacak. (Hem burada hem de Googles üzerinden) aradım ve rastgele bir hiyerarşi oluşturmak için sadece bir referans bulduk:

Linux: rastgele dizin / dosya hiyerarşisi oluştur

Bu soru (StackOverflow'da) istenen sonuç açısından aslında oldukça yakındır, çünkü aynı zamanda test için bir dizin yapısı oluşturmaya çalışır. Ancak bu soru (ve cevapları) içinde yaşadığımız set tabanlı dünyaya değil, Linux / Unix kabuk komut dosyasına odaklanıyor.

Şimdi, rastgele veri oluşturmayı biliyorum ve zaten varyasyonları gösterebilmek için dosyaların içeriğini oluşturmak için bunu yapıyorum. Buradaki zor kısım, her kümedeki eleman sayısının belirli bir alan değil rastgele olmasıdır. Ve her bir düğümdeki eleman sayısının aynı seviyelerdeki diğer düğümlerden rastgele olması gerekir.

Örnek Hiyerarşi

     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

Yukarıdaki Hiyerarşiyi Açıklayan Örnek Sonuç Kümesi

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

Yanıtlar:


9

( OP notu: tercih edilen çözüm 4. / son kod bloğudur)

XML bana burada kullanılacak veri yapısının bariz bir tercihi gibi görünüyor.

with N as
(
  select T.N
  from (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),
              (12),(13),(14),(15),(16),(17),(18),(19),(20)) as T(N)
)

select top(5 + abs(checksum(newid())) % 15)
  N1.N as '@Value',
  (
  select top(1 + abs(checksum(newid())) % 10)
    N2.N as '@Value',
    (
    select top(1 + abs(checksum(newid())) % 5)
      N3.N as '@Value'
    from N as N3
    where N2.N > 0
    for xml path('Level3'), type
    )
  from N as N2
  where N1.N > 0
  for xml path('Level2'), type
  )
from N as N1
for xml path('Level1'), root('Root');

SQL Server'ı top()her düğüm için farklı değerler kullanmanın hilesi , alt sorguları ilişkilendirilmiş yapmaktır. N1.N > 0ve N2.N > 0.

XML'i düzleştirme:

declare @X xml;

with N as
(
  select T.N
  from (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),
              (12),(13),(14),(15),(16),(17),(18),(19),(20)) as T(N)
)
select @X  = (
             select top(5 + abs(checksum(newid())) % 15)
               N1.N as '@Value',
               (
               select top(1 + abs(checksum(newid())) % 10)
                 N2.N as '@Value',
                 (
                 select top(1 + abs(checksum(newid())) % 5)
                   N3.N as '@Value'
                 from N as N3
                 where N2.N > 0
                 for xml path('Level3'), type
                 )
               from N as N2
               where N1.N > 0
               for xml path('Level2'), type
               )
             from N as N1
             for xml path('Level1')
             );


select L1.X.value('@Value', 'varchar(10)')+'\'+
       L2.X.value('@Value', 'varchar(10)')+'\'+
       L3.X.value('@Value', 'varchar(10)')
from @X.nodes('/Level1') as L1(X)
  cross apply L1.X.nodes('Level2') as L2(X)
  cross apply L2.X.nodes('Level3') as L3(X);

Ve XML'den tamamen boş bir sürüm.

with N as
(
  select T.N
  from (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),
              (12),(13),(14),(15),(16),(17),(18),(19),(20)) as T(N)
)
select cast(N1.N as varchar(10))+'\'+
       cast(N2.N as varchar(10))+'\'+
       cast(N3.N as varchar(10))
from (
     select top(5 + abs(checksum(newid())) % 15)
       N.N
     from N
     ) as N1
  cross apply
     (
     select top(1 + abs(checksum(newid())) % 10)
       N.N
     from N
     where N1.N > 0
     ) as N2
  cross apply
     (
     select top(1 + abs(checksum(newid())) % 5)
       N.N
     from N
     where N2.N > 0
     ) as N3;

Korelasyon N1.N > 0ve N2.N > 0hala önemlidir.

Yalnızca tamsayılar yerine 20 adlı tablo kullanan bir sürüm.

declare @Elements table
(
  Name nvarchar(50) not null
);

insert into @Elements(Name)
select top(20) C.name 
from sys.columns as C
group by C.name;

select N1.Name + N'\' + N2.Name + N'\' + N3.Name
from (
     select top(5 + abs(checksum(newid())) % 15)
       E.Name
     from @Elements as E
     ) as N1
  cross apply
     (
     select top(1 + abs(checksum(newid())) % 10)
       E.Name
     from @Elements as E
     where N1.Name > ''
     ) as N2
  cross apply
     (
     select top(1 + abs(checksum(newid())) % 5)
       E.Name
     from @Elements as E
     where N2.Name > ''
     ) as N3;

1
Yeni sürümü daha çok seviyorum. Neredeyse ilk denememde bulduğum şeyle aynı, ama nedense TOP(n)2 CROSS APPLYs'de doğru çalışamadım . Başka bir şey çalışan bir kez var bu koddan kurtuldum beri ben farklı / yanlış yaptım emin değilim. Bu güncellemeyi sağladığınıza göre, yakında yayınlayacağım. Ve yukarıdaki yorumların çoğunu temizledim.
Solomon Rutzky

Sürümümü yeni yayınladım. Başlıca farklılıklar şunlardır: 1) TOP (n) 'yi çalıştıramadım, nWHERE koşulu ile eleman almaya gittim ve 2)name Dizin ve / veya dosya adlarını rastgele seçmekten daha kontrollü bir bileşene sahibim .
Solomon Rutzky

Çok uzun süre uzak kaldığım için üzgünüm, ama meşgulüm. Yine de, bunu düşünüyorum ve cevabım ile XML olmayan sürümünüz arasında karar veremiyorum. Basitliğinizi ve esnekliğinizi seviyorum, ancak benimki olan bir klasör yapısı oluşturmak için adları iade etme yeteneğine ihtiyacım var. Sonra Vlad'ı onun bir arama tablosu için güncellediğimi fark ettim ve ideal çıktıyı vermek için ona katıldım. Bu nedenle, sormak uygun değilse, lütfen aynı aramayı içerecek şekilde kendi bilgilerinizi güncelleyebilir misiniz? O zaman 3 cevabın hepsi eşdeğer çıktı (3'ü karşılaştırmak için ideal) verecek ve ben seninkini kabul ediyorum. Bu tamam mı?
Solomon Rutzky

1
@srutzky Cevabı güncelledim. Bir süre önce oldu, umarım doğru anladım ve ne aradığınızı. Elbette @Elemets, seçebileceğiniz her seviye için farklı bir ad kümesi almak için bir seviye sütunu ekleyebilirsiniz .
Mikael Eriksson

1
@srutzky endişelenme. Cevabın sizin için yararlı olduğuna sevindim.
Mikael Eriksson

6

Bu ilginçti.

Amacım düzgün bağlanmış bir hiyerarşik yapıda her seviye için rastgele sayıda alt sıra içeren belirli sayıda seviye oluşturmaktı. Bu yapı hazır olduğunda, dosya ve klasör adları gibi ek bilgiler eklemek kolaydır.

Bu yüzden, bir ağacı saklamak için klasik bir masa oluşturmak istedim:

ID int NOT NULL
ParentID int NULL
Lvl int NOT NULL

Özyineleme ile uğraştığımız için, özyinelemeli CTE doğal bir seçim gibi görünüyor.

Bir sayı tablosuna ihtiyacım olacak . Tablodaki sayılar tablosundan en az 20 sayı olmalıdır 1'den başlamalıdır: MAX(LvlMax).

CREATE TABLE [dbo].[Numbers](
    [Number] [int] NOT NULL,
CONSTRAINT [PK_Numbers] PRIMARY KEY CLUSTERED 
(
    [Number] ASC
));

INSERT INTO Numbers(Number)
SELECT TOP(1000)
    ROW_NUMBER() OVER(ORDER BY S.object_id)  AS Number
FROM
    sys.all_objects AS S
ORDER BY Number;

Veri oluşturma parametreleri bir tabloda saklanmalıdır:

DECLARE @Intervals TABLE (Lvl int, LvlMin int, LvlMax int);
INSERT INTO @Intervals (Lvl, LvlMin, LvlMax) VALUES
(1, 5, 20),
(2, 1, 10),
(3, 1, 5);

Sorgunun oldukça esnek olduğunu ve tüm parametrelerin tek bir yerde ayrıldığını unutmayın. Gerekirse daha fazla seviye ekleyebilirsiniz, sadece fazladan bir parametre satırı ekleyin.

Böyle bir dinamik üretimi mümkün kılmak için bir sonraki seviye için rastgele sıra sayısını hatırlamak zorunda kaldım, bu yüzden fazladan bir sütunum var ChildRowCount.

Yaratma özgü IDs da biraz zordur. IDsTekrarlamamanızı sağlamak için 1 ana satır başına 100 alt satır sınırını kodladım. İşte bununla POWER(100, CTE.Lvl)ilgili. Sonuç olarak büyük boşluklar var IDs. Bu sayı bir olabilir MAX(LvlMax), ama basitlik için sorgu 100 sabit koymak. Seviye sayısı sabit olarak kodlanmamıştır, ancak tarafından belirlenir @Intervals.

Bu formül

CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5

aralıkta rastgele bir kayan nokta sayısı oluşturur ve bu sayı [0..1)daha sonra gerekli aralığa ölçeklenir.

Sorgu mantığı basittir. Özyinelemeli. İlk adım, birinci seviyenin bir satır kümesini oluşturur. Satır sayısı, içindeki rastgele sayı ile belirlenir TOP. Ayrıca, her satır için ayrı bir rasgele sayıda alt satır saklanır ChildRowCount.

Özyinelemeli bölüm, CROSS APPLYher ana satır başına belirli sayıda alt satır oluşturmak için kullanılır . Bunun WHERE Numbers.Number <= CTE.ChildRowCountyerine kullanmak zorundaydım TOP(CTE.ChildRowCount), çünkü TOPCTE'nin özyinelemeli bölümüne izin verilmiyor. Daha önce SQL Server'ın bu sınırlaması hakkında bir bilgim yoktu.

WHERE CTE.ChildRowCount IS NOT NULL özyinelemeyi durdurur.

SQL Keman

WITH
CTE
AS
(
    SELECT 
        TOP(CAST(
            (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) * 
            (
                1 + (SELECT I.LvlMax FROM @Intervals AS I WHERE I.Lvl = 1)
                  - (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = 1)
            )
            + (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = 1)
            AS int))
        Numbers.Number AS ID
        ,NULL AS ParentID
        ,1 AS Lvl
        ,CAST(
            (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) * 
            (
                1 + (SELECT I.LvlMax FROM @Intervals AS I WHERE I.Lvl = 2)
                  - (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = 2)
            )
            + (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = 2)
            AS int) AS ChildRowCount
    FROM Numbers
    ORDER BY Numbers.Number

    UNION ALL

    SELECT
        CA.Number + CTE.ID * POWER(100, CTE.Lvl) AS ID
        ,CTE.ID AS ParentID
        ,CTE.Lvl + 1 AS Lvl
        ,CA.ChildRowCount
    FROM
        CTE
        CROSS APPLY
        (
            SELECT
                Numbers.Number
                ,CAST(
                    (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) * 
                    (
                    1 + (SELECT I.LvlMax FROM @Intervals AS I WHERE I.Lvl = CTE.Lvl + 2)
                      - (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = CTE.Lvl + 2)
                    )
                    + (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = CTE.Lvl + 2)
                    AS int) AS ChildRowCount
            FROM Numbers
            WHERE Numbers.Number <= CTE.ChildRowCount
        ) AS CA
    WHERE
        CTE.ChildRowCount IS NOT NULL
)
SELECT *
FROM CTE
ORDER BY Lvl, ParentID, ID;

Sonuç (eğer şanslıysanız 20 + 20 * 10 + 200 * 5 = 1220 sıraya kadar olabilir)

+---------+----------+-----+-------------------+
|   ID    | ParentID | Lvl | ChildRowCount     |
+---------+----------+-----+-------------------+
|       1 | NULL     |   1 | 3                 |
|       2 | NULL     |   1 | 1                 |
|       3 | NULL     |   1 | 6                 |
|       4 | NULL     |   1 | 5                 |
|       5 | NULL     |   1 | 3                 |
|       6 | NULL     |   1 | 7                 |
|       7 | NULL     |   1 | 1                 |
|       8 | NULL     |   1 | 6                 |
|     101 | 1        |   2 | 3                 |
|     102 | 1        |   2 | 5                 |
|     103 | 1        |   2 | 1                 |
|     201 | 2        |   2 | 5                 |
|     301 | 3        |   2 | 4                 |
|     302 | 3        |   2 | 5                 |
|     303 | 3        |   2 | 1                 |
|     304 | 3        |   2 | 2                 |
|     305 | 3        |   2 | 4                 |
|     306 | 3        |   2 | 3                 |
|     401 | 4        |   2 | 3                 |
|     402 | 4        |   2 | 1                 |
|     403 | 4        |   2 | 2                 |
|     404 | 4        |   2 | 2                 |
|     405 | 4        |   2 | 4                 |
|     501 | 5        |   2 | 1                 |
|     502 | 5        |   2 | 3                 |
|     503 | 5        |   2 | 5                 |
|     601 | 6        |   2 | 2                 |
|     602 | 6        |   2 | 5                 |
|     603 | 6        |   2 | 3                 |
|     604 | 6        |   2 | 3                 |
|     605 | 6        |   2 | 4                 |
|     606 | 6        |   2 | 5                 |
|     607 | 6        |   2 | 4                 |
|     701 | 7        |   2 | 2                 |
|     801 | 8        |   2 | 2                 |
|     802 | 8        |   2 | 3                 |
|     803 | 8        |   2 | 3                 |
|     804 | 8        |   2 | 3                 |
|     805 | 8        |   2 | 5                 |
|     806 | 8        |   2 | 2                 |
| 1010001 | 101      |   3 | NULL              |
| 1010002 | 101      |   3 | NULL              |
| 1010003 | 101      |   3 | NULL              |
| 1020001 | 102      |   3 | NULL              |
| 1020002 | 102      |   3 | NULL              |
| 1020003 | 102      |   3 | NULL              |
| 1020004 | 102      |   3 | NULL              |
| 1020005 | 102      |   3 | NULL              |
| 1030001 | 103      |   3 | NULL              |
| 2010001 | 201      |   3 | NULL              |
| 2010002 | 201      |   3 | NULL              |
| 2010003 | 201      |   3 | NULL              |
| 2010004 | 201      |   3 | NULL              |
| 2010005 | 201      |   3 | NULL              |
| 3010001 | 301      |   3 | NULL              |
| 3010002 | 301      |   3 | NULL              |
| 3010003 | 301      |   3 | NULL              |
| 3010004 | 301      |   3 | NULL              |
| 3020001 | 302      |   3 | NULL              |
| 3020002 | 302      |   3 | NULL              |
| 3020003 | 302      |   3 | NULL              |
| 3020004 | 302      |   3 | NULL              |
| 3020005 | 302      |   3 | NULL              |
| 3030001 | 303      |   3 | NULL              |
| 3040001 | 304      |   3 | NULL              |
| 3040002 | 304      |   3 | NULL              |
| 3050001 | 305      |   3 | NULL              |
| 3050002 | 305      |   3 | NULL              |
| 3050003 | 305      |   3 | NULL              |
| 3050004 | 305      |   3 | NULL              |
| 3060001 | 306      |   3 | NULL              |
| 3060002 | 306      |   3 | NULL              |
| 3060003 | 306      |   3 | NULL              |
| 4010001 | 401      |   3 | NULL              |
| 4010002 | 401      |   3 | NULL              |
| 4010003 | 401      |   3 | NULL              |
| 4020001 | 402      |   3 | NULL              |
| 4030001 | 403      |   3 | NULL              |
| 4030002 | 403      |   3 | NULL              |
| 4040001 | 404      |   3 | NULL              |
| 4040002 | 404      |   3 | NULL              |
| 4050001 | 405      |   3 | NULL              |
| 4050002 | 405      |   3 | NULL              |
| 4050003 | 405      |   3 | NULL              |
| 4050004 | 405      |   3 | NULL              |
| 5010001 | 501      |   3 | NULL              |
| 5020001 | 502      |   3 | NULL              |
| 5020002 | 502      |   3 | NULL              |
| 5020003 | 502      |   3 | NULL              |
| 5030001 | 503      |   3 | NULL              |
| 5030002 | 503      |   3 | NULL              |
| 5030003 | 503      |   3 | NULL              |
| 5030004 | 503      |   3 | NULL              |
| 5030005 | 503      |   3 | NULL              |
| 6010001 | 601      |   3 | NULL              |
| 6010002 | 601      |   3 | NULL              |
| 6020001 | 602      |   3 | NULL              |
| 6020002 | 602      |   3 | NULL              |
| 6020003 | 602      |   3 | NULL              |
| 6020004 | 602      |   3 | NULL              |
| 6020005 | 602      |   3 | NULL              |
| 6030001 | 603      |   3 | NULL              |
| 6030002 | 603      |   3 | NULL              |
| 6030003 | 603      |   3 | NULL              |
| 6040001 | 604      |   3 | NULL              |
| 6040002 | 604      |   3 | NULL              |
| 6040003 | 604      |   3 | NULL              |
| 6050001 | 605      |   3 | NULL              |
| 6050002 | 605      |   3 | NULL              |
| 6050003 | 605      |   3 | NULL              |
| 6050004 | 605      |   3 | NULL              |
| 6060001 | 606      |   3 | NULL              |
| 6060002 | 606      |   3 | NULL              |
| 6060003 | 606      |   3 | NULL              |
| 6060004 | 606      |   3 | NULL              |
| 6060005 | 606      |   3 | NULL              |
| 6070001 | 607      |   3 | NULL              |
| 6070002 | 607      |   3 | NULL              |
| 6070003 | 607      |   3 | NULL              |
| 6070004 | 607      |   3 | NULL              |
| 7010001 | 701      |   3 | NULL              |
| 7010002 | 701      |   3 | NULL              |
| 8010001 | 801      |   3 | NULL              |
| 8010002 | 801      |   3 | NULL              |
| 8020001 | 802      |   3 | NULL              |
| 8020002 | 802      |   3 | NULL              |
| 8020003 | 802      |   3 | NULL              |
| 8030001 | 803      |   3 | NULL              |
| 8030002 | 803      |   3 | NULL              |
| 8030003 | 803      |   3 | NULL              |
| 8040001 | 804      |   3 | NULL              |
| 8040002 | 804      |   3 | NULL              |
| 8040003 | 804      |   3 | NULL              |
| 8050001 | 805      |   3 | NULL              |
| 8050002 | 805      |   3 | NULL              |
| 8050003 | 805      |   3 | NULL              |
| 8050004 | 805      |   3 | NULL              |
| 8050005 | 805      |   3 | NULL              |
| 8060001 | 806      |   3 | NULL              |
| 8060002 | 806      |   3 | NULL              |
+---------+----------+-----+-------------------+

Bağlantılı hiyerarşi yerine tam yol oluşturma

Sadece tam yol Nseviyelerinin derinliği IDile ParentIDilgileniyorsak, CTE'yi atlayabiliriz . Ek tabloda olası isimlerin bir listesi varsa Names, bunları CTE'deki bu tablodan seçmek kolaydır. NamesTablo, her seviye için yeterli satır sahip olmalıdır: 20 seviyesinde 1, 10, 3. seviye 2, 5; Toplam 20 + 10 + 5 = 35. Her seviye için farklı satır kümelerine sahip olmak gerekli değildir, ancak düzgün bir şekilde ayarlanması kolaydır, bu yüzden yaptım.

DECLARE @Names TABLE (Lvl int, Name nvarchar(4000), SeqNumber int);

-- First level: AAA, BBB, CCC, etc.
INSERT INTO @Names (Lvl, Name, SeqNumber)
SELECT 1, REPLICATE(CHAR(Number+64), 3) AS Name, Number AS SeqNumber
FROM Numbers
WHERE Number <= 20;

-- Second level: 001, 002, 003, etc.
INSERT INTO @Names (Lvl, Name, SeqNumber)
SELECT 2, REPLACE(STR(Number, 3), ' ', '0') AS Name, Number AS SeqNumber
FROM Numbers
WHERE Number <= 10;

-- Third level: I, II, III, IV, V
INSERT INTO @Names (Lvl, Name, SeqNumber) VALUES
(3, 'I',   1),
(3, 'II',  2),
(3, 'III', 3),
(3, 'IV',  4),
(3, 'V',   5);

SQL Fiddle İşte son sorgu. Ben bölünmüş FullPathiçine FilePathve FileName.

WITH
CTE
AS
(
    SELECT 
        TOP(CAST(
            (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) * 
            (
                1 + (SELECT I.LvlMax FROM @Intervals AS I WHERE I.Lvl = 1)
                  - (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = 1)
            )
            + (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = 1)
            AS int))

        1 AS Lvl
        ,CAST(
            (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) * 
            (
                1 + (SELECT I.LvlMax FROM @Intervals AS I WHERE I.Lvl = 2)
                  - (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = 2)
            )
            + (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = 2)
            AS int) AS ChildRowCount
        ,N.Name AS FullPath
        ,N.Name AS [FilePath]
        ,CAST(N'' AS nvarchar(4000)) AS [FileName]
    FROM
        Numbers
        INNER JOIN @Names AS N ON 
            N.SeqNumber = Numbers.Number AND N.Lvl = 1
    ORDER BY Numbers.Number

    UNION ALL

    SELECT
        CTE.Lvl + 1 AS Lvl
        ,CA.ChildRowCount
        ,CTE.FullPath + '\' + CA.Name AS FullPath

        ,CASE WHEN CA.ChildRowCount IS NOT NULL 
            THEN CTE.FullPath + '\' + CA.Name
            ELSE CTE.FullPath END AS [FilePath]

        ,CASE WHEN CA.ChildRowCount IS NULL 
            THEN CA.Name
            ELSE N'' END AS [FileName]
    FROM
        CTE
        CROSS APPLY
        (
            SELECT
                Numbers.Number
                ,CAST(
                    (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) * 
                    (
                    1 + (SELECT I.LvlMax FROM @Intervals AS I WHERE I.Lvl = CTE.Lvl + 2)
                      - (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = CTE.Lvl + 2)
                    )
                    + (SELECT I.LvlMin FROM @Intervals AS I WHERE I.Lvl = CTE.Lvl + 2)
                    AS int) AS ChildRowCount
                ,N.Name
            FROM
                Numbers
                INNER JOIN @Names AS N ON 
                    N.SeqNumber = Numbers.Number AND N.Lvl = CTE.Lvl + 1
            WHERE Numbers.Number <= CTE.ChildRowCount
        ) AS CA
    WHERE
        CTE.ChildRowCount IS NOT NULL
)
SELECT
    CTE.FullPath
    ,CTE.[FilePath]
    ,CTE.[FileName]
FROM CTE
WHERE CTE.ChildRowCount IS NULL
ORDER BY FullPath;

Sonuç

+-------------+----------+----------+
|  FullPath   | FilePath | FileName |
+-------------+----------+----------+
| AAA\001\I   | AAA\001  | I        |
| AAA\001\II  | AAA\001  | II       |
| AAA\002\I   | AAA\002  | I        |
| AAA\002\II  | AAA\002  | II       |
| AAA\002\III | AAA\002  | III      |
| AAA\002\IV  | AAA\002  | IV       |
| AAA\002\V   | AAA\002  | V        |
| AAA\003\I   | AAA\003  | I        |
| AAA\003\II  | AAA\003  | II       |
| AAA\003\III | AAA\003  | III      |
| AAA\004\I   | AAA\004  | I        |
| AAA\004\II  | AAA\004  | II       |
| AAA\004\III | AAA\004  | III      |
| AAA\004\IV  | AAA\004  | IV       |
| BBB\001\I   | BBB\001  | I        |
| BBB\001\II  | BBB\001  | II       |
| CCC\001\I   | CCC\001  | I        |
| CCC\001\II  | CCC\001  | II       |
| CCC\001\III | CCC\001  | III      |
| CCC\001\IV  | CCC\001  | IV       |
| CCC\001\V   | CCC\001  | V        |
| CCC\002\I   | CCC\002  | I        |
| CCC\003\I   | CCC\003  | I        |
| CCC\003\II  | CCC\003  | II       |
| CCC\004\I   | CCC\004  | I        |
| CCC\004\II  | CCC\004  | II       |
| CCC\005\I   | CCC\005  | I        |
| CCC\005\II  | CCC\005  | II       |
| CCC\005\III | CCC\005  | III      |
| CCC\006\I   | CCC\006  | I        |
| CCC\006\II  | CCC\006  | II       |
| CCC\006\III | CCC\006  | III      |
| CCC\006\IV  | CCC\006  | IV       |
| CCC\007\I   | CCC\007  | I        |
| CCC\007\II  | CCC\007  | II       |
| CCC\007\III | CCC\007  | III      |
| CCC\007\IV  | CCC\007  | IV       |
| CCC\008\I   | CCC\008  | I        |
| CCC\008\II  | CCC\008  | II       |
| CCC\008\III | CCC\008  | III      |
| CCC\009\I   | CCC\009  | I        |
| CCC\009\II  | CCC\009  | II       |
| CCC\009\III | CCC\009  | III      |
| CCC\009\IV  | CCC\009  | IV       |
| CCC\010\I   | CCC\010  | I        |
| CCC\010\II  | CCC\010  | II       |
| CCC\010\III | CCC\010  | III      |
| DDD\001\I   | DDD\001  | I        |
| DDD\001\II  | DDD\001  | II       |
| DDD\001\III | DDD\001  | III      |
| DDD\001\IV  | DDD\001  | IV       |
| DDD\002\I   | DDD\002  | I        |
| DDD\003\I   | DDD\003  | I        |
| DDD\003\II  | DDD\003  | II       |
| DDD\003\III | DDD\003  | III      |
| DDD\003\IV  | DDD\003  | IV       |
| DDD\004\I   | DDD\004  | I        |
| DDD\004\II  | DDD\004  | II       |
| DDD\004\III | DDD\004  | III      |
| DDD\005\I   | DDD\005  | I        |
| DDD\006\I   | DDD\006  | I        |
| DDD\006\II  | DDD\006  | II       |
| DDD\006\III | DDD\006  | III      |
| DDD\007\I   | DDD\007  | I        |
| DDD\007\II  | DDD\007  | II       |
| DDD\008\I   | DDD\008  | I        |
| DDD\008\II  | DDD\008  | II       |
| DDD\008\III | DDD\008  | III      |
| DDD\009\I   | DDD\009  | I        |
| DDD\009\II  | DDD\009  | II       |
| DDD\010\I   | DDD\010  | I        |
| DDD\010\II  | DDD\010  | II       |
| DDD\010\III | DDD\010  | III      |
| DDD\010\IV  | DDD\010  | IV       |
| DDD\010\V   | DDD\010  | V        |
| EEE\001\I   | EEE\001  | I        |
| EEE\001\II  | EEE\001  | II       |
| FFF\001\I   | FFF\001  | I        |
| FFF\002\I   | FFF\002  | I        |
| FFF\002\II  | FFF\002  | II       |
| FFF\003\I   | FFF\003  | I        |
| FFF\003\II  | FFF\003  | II       |
| FFF\003\III | FFF\003  | III      |
| FFF\003\IV  | FFF\003  | IV       |
| FFF\003\V   | FFF\003  | V        |
| FFF\004\I   | FFF\004  | I        |
| FFF\004\II  | FFF\004  | II       |
| FFF\004\III | FFF\004  | III      |
| FFF\004\IV  | FFF\004  | IV       |
| FFF\005\I   | FFF\005  | I        |
| FFF\006\I   | FFF\006  | I        |
| FFF\007\I   | FFF\007  | I        |
| FFF\007\II  | FFF\007  | II       |
| FFF\007\III | FFF\007  | III      |
| GGG\001\I   | GGG\001  | I        |
| GGG\001\II  | GGG\001  | II       |
| GGG\001\III | GGG\001  | III      |
| GGG\002\I   | GGG\002  | I        |
| GGG\003\I   | GGG\003  | I        |
| GGG\003\II  | GGG\003  | II       |
| GGG\003\III | GGG\003  | III      |
| GGG\004\I   | GGG\004  | I        |
| GGG\004\II  | GGG\004  | II       |
| HHH\001\I   | HHH\001  | I        |
| HHH\001\II  | HHH\001  | II       |
| HHH\001\III | HHH\001  | III      |
| HHH\002\I   | HHH\002  | I        |
| HHH\002\II  | HHH\002  | II       |
| HHH\002\III | HHH\002  | III      |
| HHH\002\IV  | HHH\002  | IV       |
| HHH\002\V   | HHH\002  | V        |
| HHH\003\I   | HHH\003  | I        |
| HHH\003\II  | HHH\003  | II       |
| HHH\003\III | HHH\003  | III      |
| HHH\003\IV  | HHH\003  | IV       |
| HHH\003\V   | HHH\003  | V        |
| HHH\004\I   | HHH\004  | I        |
| HHH\004\II  | HHH\004  | II       |
| HHH\004\III | HHH\004  | III      |
| HHH\004\IV  | HHH\004  | IV       |
| HHH\004\V   | HHH\004  | V        |
| HHH\005\I   | HHH\005  | I        |
| HHH\005\II  | HHH\005  | II       |
| HHH\005\III | HHH\005  | III      |
| HHH\005\IV  | HHH\005  | IV       |
| HHH\005\V   | HHH\005  | V        |
| HHH\006\I   | HHH\006  | I        |
| HHH\007\I   | HHH\007  | I        |
| HHH\007\II  | HHH\007  | II       |
| HHH\007\III | HHH\007  | III      |
| HHH\008\I   | HHH\008  | I        |
| HHH\008\II  | HHH\008  | II       |
| HHH\008\III | HHH\008  | III      |
| HHH\008\IV  | HHH\008  | IV       |
| HHH\008\V   | HHH\008  | V        |
+-------------+----------+----------+

İlginç bir yaklaşım :). Bunu sevdim. Tamlık uğruna, lütfen Sayılar tablosunu (SQL Fiddle'dan) doldurmak için sorguyu ekleyebilir veya CTE'nin bir parçası olarak bu satır içi simgesini ekleyebilir misiniz? Sonra birisinin sadece kopyalayıp yapıştırması daha kolaydır. Bu cevap için, nihai çıktı her satır tüm Level3 değerleri için Level1'den Level3'e kadar tam bir yol olarak ifade edilebilir mi? Bence bu INNER JOINfinalde sadece 2 saniye sürecek SELECT. Son olarak, her bir düğüme adlar / etiketler atanabilir, böylece bunlar yalnızca sayılar değildir? Bu iki noktayı da netleştirmek için soruyu güncelleyeceğim.
Solomon Rutzky

Bu adlar / etiketler nereden geliyor? 20 sıralı bir 'Adlar' tablom olmalı ve ondan bir ad mı seçmeliyim? Böylece her seviyede aynı isim seti görünür. Yoksa her seviyenin kendi ayrı isimleri mi olmalı?
Vladimir Baranov

İsimlerin CTE'nin bir parçası olarak bir tablodan (geçici, gerçek veya değişken) veya satır içi olabileceğini düşünüyorum. Başlangıçta CTE onları koymak ama sonra sorgunun ana kısmı burada daha okunabilir olacağını böylece yerel bir geçici tabloya onları taşındı. Bence sahip olduğunuz yapı ile seviye başına ayrı olması yeterince kolay olurdu. Ancak, yeterli olacak sadece 20 setten biriyse, test verilerinde biraz daha az değişiklik sağlar. Tek gerçek gereksinim, dizinler veya dosyalar oluşturmaya çalışırken hata olacağı için hiçbir adın bir düğüm içinde tekrarlanmamasıdır :).
Solomon Rutzky

1
@srutzky, ikinci bir varyant ekledim.
Vladimir Baranov

1
@srutzky, ben bölmek FullPathiçine FilePathve FileName.
Vladimir Baranov

4

İşte benim ortaya koyduğum şey. Bir dizin yapısı oluşturmak amacıyla, dizinler ve dosyalar için kullanılabilir "adlar" arıyordum. Ben alamadı Çünkü TOP(n)içinde çalışma CROSS APPLY(ı olarak ebeveyn arasında bir değer kullanarak sorguları ilişkilendirmek için çalıştı düşünüyorum s niçinde TOP(n)ama sonra rastgele değildi), ben "sayılar" bir tür oluşturmak için karar bir sayının rasgele seçilmesi ve bir sayı olarak belirtilmesi yoluyla bir INNER JOINveya WHEREkoşul kümesinin üretilmesine izin veren tablo . İşin püf noktası, Seviye1 için yalnızca 1 satır, Düzey2 için 2 satır, Düzey3 için 3 satır vb. Bu nedenle, kullanmak bana 3 satır alır ve her satırın dizin adı olarak kullanabileceğim bir değeri vardır.nWHERE table.Level = random_numberWHERE LevelID = 3

KURMAK

Bu bölüm başlangıçta CTE'nin bir parçası olarak satır içi olarak belirtilmiştir. Ancak okunabilirlik uğruna (böylece INSERTgerçek sorgunun birkaç satırına ulaşmak için birçok ifadeyi kaydırmanıza gerek yok ), yerel bir geçici tabloya çıktım.

IF (OBJECT_ID(N'tempdb..#Elements') IS NULL)
BEGIN
  PRINT 'Creating #Elements table...';
  CREATE TABLE #Elements (
     ElementLevel TINYINT NOT NULL,
     LevelName NVARCHAR(50) NOT NULL
                         );

  PRINT 'Populating #Elements table...';
  INSERT INTO #Elements (ElementLevel, LevelName)
    SELECT tmp.[Level], tmp.[Name]
    FROM (
                  SELECT 1,  N'Ella'
       UNION ALL  SELECT 2,  N'Itchy'
       UNION ALL  SELECT 2,  N'Scratchy'
       UNION ALL  SELECT 3,  N'Moe'
       UNION ALL  SELECT 3,  N'Larry'
       UNION ALL  SELECT 3,  N'Curly'
       UNION ALL  SELECT 4,  N'Ian'
       UNION ALL  SELECT 4,  N'Stephen'
       UNION ALL  SELECT 4,  N'Peter'
       UNION ALL  SELECT 4,  N'Bernard'
       UNION ALL  SELECT 5,  N'Michigan'
       UNION ALL  SELECT 5,  N'Erie'
       UNION ALL  SELECT 5,  N'Huron'
       UNION ALL  SELECT 5,  N'Ontario'
       UNION ALL  SELECT 5,  N'Superior'
       UNION ALL  SELECT 6,  N'White'
       UNION ALL  SELECT 6,  N'Orange'
       UNION ALL  SELECT 6,  N'Blonde'
       UNION ALL  SELECT 6,  N'Pink'
       UNION ALL  SELECT 6,  N'Blue'
       UNION ALL  SELECT 6,  N'Brown'
       UNION ALL  SELECT 7,  N'Asia'
       UNION ALL  SELECT 7,  N'Africa'
       UNION ALL  SELECT 7,  N'North America'
       UNION ALL  SELECT 7,  N'South America'
       UNION ALL  SELECT 7,  N'Antarctica'
       UNION ALL  SELECT 7,  N'Europe'
       UNION ALL  SELECT 7,  N'Australia'
       UNION ALL  SELECT 8,  N'AA'
       UNION ALL  SELECT 8,  N'BB'
       UNION ALL  SELECT 8,  N'CC'
       UNION ALL  SELECT 8,  N'DD'
       UNION ALL  SELECT 8,  N'EE'
       UNION ALL  SELECT 8,  N'FF'
       UNION ALL  SELECT 8,  N'GG'
       UNION ALL  SELECT 8,  N'HH'
       UNION ALL  SELECT 9,  N'I'
       UNION ALL  SELECT 9,  N'II'
       UNION ALL  SELECT 9,  N'III'
       UNION ALL  SELECT 9,  N'IV'
       UNION ALL  SELECT 9,  N'V'
       UNION ALL  SELECT 9,  N'VI'
       UNION ALL  SELECT 9,  N'VII'
       UNION ALL  SELECT 9,  N'VIII'
       UNION ALL  SELECT 9,  N'IX'
       UNION ALL  SELECT 10, N'Million'
       UNION ALL  SELECT 10, N'Billion'
       UNION ALL  SELECT 10, N'Trillion'
       UNION ALL  SELECT 10, N'Quadrillion'
       UNION ALL  SELECT 10, N'Quintillion'
       UNION ALL  SELECT 10, N'Sestillion'
       UNION ALL  SELECT 10, N'Sextillion'
       UNION ALL  SELECT 10, N'Octillion'
       UNION ALL  SELECT 10, N'Nonillion'
       UNION ALL  SELECT 10, N'Decillion'
     ) tmp([Level], [Name]);
END;

ANA SORGULAMA

Seviye 1 için [name], sys.objectsorada her zaman bol miktarda satır olduğu için değerleri aldım . Ancak, isimler üzerinde daha fazla kontrole ihtiyaç duyarsam, #Elementstabloyu ek seviyeler içerecek şekilde genişletebilirim .

;WITH topdir(Level1, Randy) AS
(
    SELECT TOP ( (CONVERT(INT, CRYPT_GEN_RANDOM(1)) % 20) + 5 ) so.[name],
                ( (CONVERT(INT, CRYPT_GEN_RANDOM(1)) % 10) + 1 )
    FROM sys.objects so
    ORDER BY CRYPT_GEN_RANDOM(8) ASC
)
SELECT  td.Level1, tmp1.Level2, tmp2.Level3
FROM    topdir td
CROSS APPLY (SELECT help.LevelName, (CONVERT(INT, CRYPT_GEN_RANDOM(1)) % 5) + 1
            FROM #Elements help
            WHERE help.ElementLevel = td.Randy
            ) tmp1 (Level2, Bandy)
CROSS APPLY (SELECT help.LevelName
            FROM #Elements help
            WHERE help.ElementLevel = tmp1.Bandy
            ) tmp2 (Level3);

HER DOSYA YOLU, ADI VE İÇERİĞİ ÜRETMEK İÇİN SORGULAMA

Dosyaların ve dosya içeriğinin tam yollarını oluşturmak için, CTE'nin ana SELECT'ini sadece başka bir CTE yaptım ve sadece dosyalara gitmesi gereken uygun çıktıları veren yeni bir ana SELECT ekledim.

DECLARE @Template NVARCHAR(4000);
SET @Template = N'<?xml version="1.0" encoding="ISO-8859-1"?>
<ns0:P4131 xmlns:ns0="http://switching/xi">
<R000000>
    <R00000010>R000000</R00000010>
    <R00000020>I</R00000020>
    <R00000030>{{Tag30}}</R00000030>
    <R00000040>{{Tag40}}</R00000040>
    <R00000050>{{Tag50}}</R00000050>
    <R00000060>2</R00000060>
</R000000>
</ns0:P4131>
';


;WITH topdir(Level1, Thing1) AS
(
    SELECT TOP ( (CONVERT(INT, CRYPT_GEN_RANDOM(1)) % 20) + 5 ) so.[name],
                ( (CONVERT(INT, CRYPT_GEN_RANDOM(1)) % 10) + 1 )
    FROM sys.objects so
    ORDER BY CRYPT_GEN_RANDOM(8) ASC
), main AS
(
   SELECT  td.Level1, tmp1.Level2, tmp2.Level3,
           td.Level1 + N'\' + tmp1.Level2 AS [FullPath],
           RIGHT('000' + CONVERT(VARCHAR(10),
                          (CONVERT(INT, CRYPT_GEN_RANDOM(2)) % 9999) + 1), 4) AS [R30],
           RIGHT('000' + CONVERT(VARCHAR(10),
                          (CONVERT(INT, CRYPT_GEN_RANDOM(2)) % 500) + 100), 4) AS [R50],
           ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS [RowNum]
   FROM    topdir td
   CROSS APPLY (SELECT help.LevelName, (CONVERT(INT, CRYPT_GEN_RANDOM(1)) % 5) + 1
                FROM #Elements help
                WHERE help.ElementLevel = td.Thing1
               ) tmp1 (Level2, Thing2)
   CROSS APPLY (SELECT help.LevelName
                FROM #Elements help
                WHERE help.ElementLevel = tmp1.Thing2
               ) tmp2 (Level3)
)
SELECT  mn.FullPath,
        mn.Level3 + N'.xml' AS [FileName],
        REPLACE(
            REPLACE(
                REPLACE(
                    @Template,
                    N'{{Tag30}}',
                    mn.R30),
                N'{{Tag40}}',
                mn.RowNum),
            N'{{Tag50}}',
            mn.R50) AS [Contents]
FROM    main mn;

EKSTRA KREDİ

Soruda belirtilen gereksinimlerin bir parçası olmasa da, amaç (bahsedilen) özyinelemeli Dosya Sistemi işlevlerini sınamak için dosyalar oluşturmaktı. Peki bu sonuç yol adları, dosya adları ve dosya içerikleri setini nasıl alıp onunla bir şeyler yapabiliriz? Sadece iki SQLCLR fonksiyonuna ihtiyacımız var: biri klasör oluşturmak için diğeri dosyaları oluşturmak için.

Bu verileri işlevsel hale getirmek için, SELECTdoğrudan yukarıda gösterilen CTE'nin ana modunu aşağıdaki gibi değiştirdim:

SELECT  SQL#.File_CreateDirectory(
            N'C:\Stuff\TestXmlFiles\' + mn.FullPath) AS [CreateTheDirectory],
        SQL#.File_WriteFile(
            N'C:\Stuff\TestXmlFiles\' + mn.FullPath + N'\' + mn.Level3 + N'.xml',
            REPLACE(
                REPLACE(
                    REPLACE(
                        @Template,
                        N'{{Tag30}}',
                        mn.R30),
                    N'{{Tag40}}',
                    mn.RowNum),
                N'{{Tag50}}',
                mn.R50), -- @FileData
            0, -- @AppendData
            '' -- @FileEncoding
                            ) AS [WriteTheFile]
FROM    main mn;
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.