Tạo hệ thống phân cấp của nhiều cấp trong đó mỗi nút có số lượng con ngẫu nhiên


16

Tôi cần tạo một số dữ liệu thử nghiệm liên quan đến hệ thống phân cấp. Tôi có thể làm cho nó dễ dàng và thực hiện một vài CROSS JOINgiây, nhưng điều đó sẽ cho tôi một cấu trúc hoàn toàn thống nhất / không có bất kỳ biến thể nào. Điều đó không chỉ có vẻ buồn tẻ, mà còn thiếu sự thay đổi trong dữ liệu thử nghiệm đôi khi che giấu các vấn đề sẽ được tìm thấy. Vì vậy, tôi muốn tạo ra một hệ thống phân cấp không thống nhất tuân theo các quy tắc sau:

  • Sâu 3 cấp
    • Cấp 1 là ngẫu nhiên 5 - 20 nút
    • Cấp 2 là 1 - 10 nút, ngẫu nhiên trên mỗi nút của Cấp 1
    • Cấp 3 là 1 - 5 nút, ngẫu nhiên trên mỗi nút của Cấp 2
  • Tất cả các chi nhánh sẽ sâu 3 cấp. Đồng nhất về chiều sâu là ok ở điểm này.
  • Có thể có sự trùng lặp về tên của các nút con ở bất kỳ mức nào (nghĩa là tên của các nút con không cần phải là duy nhất trên tất cả các nút ở cùng cấp).
  • Thuật ngữ "ngẫu nhiên" được định nghĩa ở đây là giả ngẫu nhiên, không phải là ngẫu nhiên duy nhất. Điều này cần được đề cập vì thuật ngữ "ngẫu nhiên" thường được sử dụng có nghĩa là "thứ tự ngẫu nhiên của một tập hợp nhất định không tạo ra các bản sao". Tôi chấp nhận ngẫu nhiên = ngẫu nhiên và nếu số lượng trẻ em trên mỗi nút của Cấp 1 chỉ là 4, 7 và 8, thậm chí trên 20 nút trên Cấp 1 có khả năng lây lan từ 1 đến 10 trẻ cho mỗi nút đó, vậy thì tốt, bởi vì đó là những gì ngẫu nhiên.
  • Mặc dù điều này có thể được thực hiện khá dễ dàng với các WHILEvòng lặp lồng nhau , ưu tiên là tìm cách tiếp cận dựa trên tập hợp. Nói chung, việc tạo dữ liệu thử nghiệm không có yêu cầu về hiệu quả mà mã sản xuất sẽ có, nhưng việc chụp theo cách tiếp cận dựa trên tập hợp có thể sẽ mang tính giáo dục và trợ giúp nhiều hơn trong tương lai với việc tìm ra các cách tiếp cận dựa trên tập hợp cho các vấn đề. Vì vậy, WHILEcác vòng lặp không được loại trừ, nhưng chỉ có thể được sử dụng nếu không có cách tiếp cận dựa trên tập hợp nào.
  • Dựa trên tập hợp = lý tưởng là một truy vấn duy nhất, bất kể CTE, ỨNG DỤNG, v.v. Vì vậy, sử dụng bảng số hiện có hoặc nội tuyến là ổn. Sử dụng phương pháp tiếp cận WHILE / CURSOR / thủ tục sẽ không hoạt động. Tôi cho rằng việc sắp xếp các phần của dữ liệu vào các bảng tạm thời hoặc các biến của bảng là tốt, miễn là các hoạt động đều dựa trên tập hợp, không có vòng lặp. Tuy nhiên, điều đó đang được nói, một cách tiếp cận một truy vấn có thể sẽ được ưa chuộng hơn nhiều truy vấn, trừ khi có thể chỉ ra rằng cách tiếp cận đa truy vấn thực sự tốt hơn. Cũng xin lưu ý rằng những gì cấu thành "tốt hơn" thường mang tính chủ quan ;-). Cũng xin lưu ý rằng việc sử dụng "thông thường" trong câu trước cũng mang tính chủ quan.
  • Bất kỳ phiên bản và phiên bản nào của SQL Server (2005 và mới hơn, tôi cho rằng) sẽ làm.
  • Chỉ T-SQL thuần túy: không có thứ SQLCLR ngớ ngẩn nào !! Ít nhất là về mặt tạo ra dữ liệu. Tạo các thư mục và tệp sẽ được thực hiện bằng SQLCLR. Nhưng ở đây tôi chỉ tập trung vào việc tạo ra các giá trị của những gì cần tạo.
  • TVF đa câu lệnh T-SQL được coi là thủ tục, không dựa trên tập hợp, mặc dù ở bên ngoài chúng che dấu cách tiếp cận thủ tục trong một tập hợp. Có những lúc điều đó là hoàn toàn thích hợp. Đây không phải là một trong những thời điểm đó. Cùng các dòng đó, các hàm vô hướng T-SQL cũng không được phép, không chỉ bởi vì chúng còn mang tính thủ tục, mà Trình tối ưu hóa truy vấn đôi khi lưu lại giá trị của chúng và lặp lại nó sao cho đầu ra không như mong đợi.
  • Các TVF nội tuyến T-SQL (còn gọi là iTVF) là okey-dokey vì chúng dựa trên tập hợp và thực tế giống như sử dụng [ CROSS | OUTER ] APPLY, được nêu ở trên là ổn.
  • Các lần thực hiện lặp lại của các truy vấn sẽ tạo ra kết quả chủ yếu khác với lần chạy trước.
  • Cập nhật làm rõ 1: Tập kết quả cuối cùng phải được biểu thị là có một hàng cho mỗi nút riêng biệt của Cấp 3, có đường dẫn đầy đủ bắt đầu từ Cấp 1. Điều này có nghĩa là các giá trị Level1 và Level2 nhất thiết sẽ lặp lại trên một hoặc nhiều hàng, trừ trường hợp chỉ có một nút Level2 duy nhất chỉ chứa một nút Level3 duy nhất.
  • Cập nhật làm rõ 2: Có một ưu tiên rất mạnh mẽ cho mỗi nút có tên hoặc nhãn chứ không chỉ là một số. Điều này sẽ cho phép dữ liệu thử nghiệm kết quả có ý nghĩa và thực tế hơn.

Tôi không chắc liệu thông tin bổ sung này có vấn đề hay không, nhưng chỉ trong trường hợp nó giúp có một số bối cảnh, dữ liệu thử nghiệm liên quan đến câu trả lời của tôi về câu hỏi này:

Nhập tệp XML vào SQL Server 2012

Mặc dù không liên quan tại thời điểm này, mục tiêu cuối cùng của việc tạo cấu trúc phân cấp này là tạo cấu trúc thư mục để kiểm tra các phương thức hệ thống tệp đệ quy. Cấp 1 và 2 sẽ là các thư mục và Cấp 3 sẽ là tên tệp. Tôi đã tìm kiếm xung quanh (cả ở đây và thông qua Google) và chỉ tìm thấy một tài liệu tham khảo để tạo một hệ thống phân cấp ngẫu nhiên:

Linux: tạo phân cấp thư mục / tập tin ngẫu nhiên

Câu hỏi đó (trên StackOverflow) thực sự khá gần về kết quả mong muốn vì điều đó cũng tìm cách tạo cấu trúc thư mục để thử nghiệm. Nhưng câu hỏi đó (và câu trả lời) tập trung vào kịch bản shell Linux / Unix và không quá nhiều thế giới dựa trên tập hợp mà chúng ta đang sống.

Bây giờ, tôi biết cách tạo dữ liệu ngẫu nhiên và đang làm như vậy để tạo nội dung của các tệp để chúng cũng có thể hiển thị các biến thể. Phần khó khăn ở đây là số lượng phần tử trong mỗi bộ là ngẫu nhiên, không phải là một trường cụ thể. , số lượng phần tử trong mỗi nút cần phải ngẫu nhiên từ các nút khác trên cùng cấp đó.

Ví dụ phân cấp

     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

Kết quả ví dụ Đặt mô tả phân cấp ở trên

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

Câu trả lời:


9

( Lưu ý của OP: giải pháp ưa thích là khối mã thứ 4 / cuối cùng)

XML dường như là sự lựa chọn rõ ràng về cấu trúc dữ liệu để sử dụng ở đây.

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

Mẹo để tạo SQL Server sử dụng các giá trị khác nhau top()cho mỗi nút là làm cho các truy vấn phụ tương quan. N1.N > 0N2.N > 0.

Flatteing XML:

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

Và một phiên bản hoàn toàn không có 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 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;

Tương quan N1.N > 0N2.N > 0vẫn còn quan trọng.

Một phiên bản sử dụng bảng có 20 tên được sử dụng thay vì chỉ các số nguyên.

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
Tôi thích phiên bản mới tốt hơn. Nó gần như giống với những gì tôi đã nghĩ ra trong lần thử đầu tiên nhưng vì một số lý do tôi không thể làm TOP(n)cho nó hoạt động chính xác trong 2 CROSS APPLYgiây. Không chắc chắn những gì tôi đã làm khác đi / không chính xác vì tôi đã thoát khỏi mã đó một khi tôi có một cái gì đó khác hoạt động. Tôi sẽ đăng nó sớm, bây giờ bạn đã cung cấp bản cập nhật này. Và tôi đã làm sạch hầu hết các ý kiến ​​của tôi ở trên.
Solomon Rutzky

Tôi chỉ đăng phiên bản của tôi. Sự khác biệt chính là: 1) vì tôi không thể làm cho TOP (n) hoạt động, tôi đã sử dụng ncác phần tử thông qua điều kiện WHERE và 2) Tôi có namethành phần được kiểm soát nhiều hơn so với ngẫu nhiên tên thư mục và / hoặc tên tệp .
Solomon Rutzky

Xin lỗi vì đã đi quá lâu, nhưng tôi đã rất bận rộn. Tuy nhiên, tôi đã suy nghĩ về điều này và không thể quyết định giữa câu trả lời của tôi và phiên bản không phải là XML của bạn. Tôi thích sự đơn giản và linh hoạt của bạn, nhưng cần khả năng trả lại tên để sử dụng để tạo cấu trúc thư mục mà tôi có. Sau đó, tôi nhận ra rằng tôi đã cập nhật Vlad để có một bảng tra cứu và THAM GIA với nó để đưa ra kết quả lý tưởng. Vì vậy, nếu không phù hợp để hỏi, bạn có thể vui lòng cập nhật của bạn để bao gồm cùng một tra cứu không? Sau đó, cả 3 câu trả lời sẽ cho đầu ra tương đương (lý tưởng để so sánh cả 3) và tôi sẽ chấp nhận câu trả lời của bạn. Ổn chứ?
Solomon Rutzky

1
@srutzky Mình đã cập nhật câu trả lời. Đã được một thời gian trước vì vậy hy vọng tôi đã hiểu đúng và những gì bạn đang tìm kiếm. Tất nhiên bạn có thể thêm một cột cấp độ @Elemetsđể có được một bộ tên khác nhau cho mỗi cấp độ để lựa chọn.
Mikael Eriksson

1
@srutzky không lo lắng. Tôi rất vui vì câu trả lời hữu ích cho bạn.
Mikael Eriksson

6

Điều đó thật thú vị.

Mục đích của tôi là tạo ra một số cấp nhất định với số lượng hàng con ngẫu nhiên cho mỗi cấp trong một cấu trúc phân cấp được liên kết chính xác. Khi cấu trúc này đã sẵn sàng, thật dễ dàng để thêm thông tin bổ sung vào nó như tên tệp và thư mục.

Vì vậy, tôi muốn tạo một bảng cổ điển để lưu trữ cây:

ID int NOT NULL
ParentID int NULL
Lvl int NOT NULL

Vì chúng ta đang đối phó với đệ quy, CTE đệ quy dường như là một lựa chọn tự nhiên.

Tôi sẽ cần một bảng số . Các số trong bảng nên bắt đầu từ 1. Nên có ít nhất 20 số trong bảng : 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;

Các tham số để tạo dữ liệu nên được lưu trữ trong một bảng:

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

Lưu ý rằng truy vấn khá linh hoạt và tất cả các tham số được phân tách thành một nơi. Bạn có thể thêm nhiều cấp độ nếu cần, chỉ cần thêm một hàng tham số.

Để tạo ra khả năng tạo động như vậy, tôi phải nhớ số lượng hàng ngẫu nhiên cho cấp độ tiếp theo, vì vậy tôi có thêm một cột ChildRowCount.

Tạo độc đáo IDs cũng có phần khó khăn. Tôi đã mã hóa giới hạn 100 hàng con trên 1 hàng cha để đảm bảo IDskhông lặp lại. Đây là những gì đó POWER(100, CTE.Lvl)là về. Kết quả là có những khoảng trống lớn trong IDs. Con số đó có thể là một MAX(LvlMax), nhưng tôi đặt hằng số 100 trong truy vấn để đơn giản. Số lượng cấp độ không được mã hóa cứng, nhưng được xác định bởi @Intervals.

Công thức này

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

tạo ra một số dấu phẩy động ngẫu nhiên trong phạm vi [0..1), sau đó được chia tỷ lệ theo khoảng yêu cầu.

Logic truy vấn rất đơn giản. Đó là đệ quy. Bước đầu tiên tạo ra một tập hợp các hàng của cấp độ đầu tiên. Số lượng hàng được xác định bởi số ngẫu nhiên trong TOP. Ngoài ra, đối với mỗi hàng có một số hàng con ngẫu nhiên riêng biệt được lưu trữ trong ChildRowCount.

Phần đệ quy sử dụng CROSS APPLYđể tạo số lượng hàng con nhất định cho mỗi hàng cha. Tôi đã phải sử dụng WHERE Numbers.Number <= CTE.ChildRowCountthay vì TOP(CTE.ChildRowCount), vì TOPkhông được phép trong phần đệ quy của CTE. Trước đây không biết về giới hạn này của SQL Server.

WHERE CTE.ChildRowCount IS NOT NULL dừng đệ quy.

Câu đố SQL

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;

Kết quả (có thể có tối đa 20 + 20 * 10 + 200 * 5 = 1220 hàng nếu bạn may mắn)

+---------+----------+-----+-------------------+
|   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              |
+---------+----------+-----+-------------------+

Tạo đường dẫn đầy đủ thay vì phân cấp được liên kết

Nếu chúng ta chỉ quan tâm đến Nmức độ đường dẫn đầy đủ sâu, chúng ta có thể bỏ qua IDParentIDtừ CTE. Nếu chúng ta có một danh sách các tên có thể có trong bảng bổ trợ Names, thật dễ dàng để chọn chúng từ bảng này trong CTE. Các Namesbảng cần phải có đủ hàng cho mỗi cấp độ: 20 cho cấp 1, 10 cho cấp 2, 5 cho mức độ 3; Tổng cộng 20 + 10 + 5 = 35. Không cần thiết phải có các bộ hàng khác nhau cho mỗi cấp độ, nhưng rất dễ để thiết lập đúng, vì vậy tôi đã làm nó.

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 Đây là truy vấn cuối cùng. Tôi chia FullPaththành FilePathFileName.

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;

Kết quả

+-------------+----------+----------+
|  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        |
+-------------+----------+----------+

Cách tiếp cận thú vị :). Tôi thích nó. Để hoàn thiện, bạn có thể vui lòng thêm truy vấn để điền vào bảng Số (từ Fiddle SQL) hoặc chỉ bao gồm nội tuyến đó như một phần của CTE? Sau đó, dễ dàng hơn cho một ai đó chỉ cần sao chép và dán. Đối với câu trả lời này, đầu ra cuối cùng có thể được biểu thị khi mỗi hàng là một đường dẫn hoàn chỉnh từ Cấp 1 xuống Cấp 3 cho tất cả các giá trị Cấp 3 không? Tôi nghĩ rằng sẽ chỉ mất 2 INNER JOINgiây trong trận chung kết SELECT. Cuối cùng, tên / nhãn có thể được gán cho mỗi nút để chúng không chỉ là số? Tôi sẽ cập nhật câu hỏi để làm rõ cả hai điểm này.
Solomon Rutzky

Những tên / nhãn này đến từ đâu? Tôi có nên có bảng 'Tên', có 20 hàng và chọn tên từ đó không? Do đó, cùng một bộ tên sẽ xuất hiện ở mỗi cấp. Hoặc mỗi cấp độ nên có một bộ tên riêng?
Vladimir Baranov

Tôi nghĩ rằng các tên có thể đến từ một bảng (temp, real hoặc biến) hoặc nội tuyến như là một phần của CTE. Ban đầu tôi đã đặt chúng vào CTE nhưng sau đó chuyển chúng sang bảng tạm thời cục bộ để phần chính của truy vấn sẽ dễ đọc hơn ở đây. Tôi nghĩ với cấu trúc mà bạn có, nó sẽ đủ dễ dàng để phân tách theo từng cấp độ. Nhưng nếu nó chỉ là một bộ 20 cũng đủ, thì nó chỉ cung cấp ít thay đổi hơn một chút trong dữ liệu thử nghiệm. Yêu cầu đúng duy nhất là không có tên nào lặp lại trong một nút vì điều đó sẽ xảy ra lỗi khi cố gắng tạo các thư mục hoặc tệp :).
Solomon Rutzky

1
@srutzky, tôi đã thêm một biến thể thứ hai.
Vladimir Baranov

1
@srutzky, tôi chia FullPaththành FilePathFileName.
Vladimir Baranov

4

Vì vậy, đây là những gì tôi đã đưa ra. Với mục tiêu tạo ra một cấu trúc thư mục, tôi đã tìm kiếm "tên" có thể sử dụng cho các thư mục và tệp. Bởi vì tôi không thể có được công TOP(n)việc trong CROSS APPLYs (Tôi nghĩ rằng tôi đã cố gắng tương quan các truy vấn bằng cách sử dụng một giá trị từ cha mẹ như ntrong TOP(n)nhưng sau đó không phải là ngẫu nhiên), tôi đã quyết định tạo một loại "số" bảng sẽ cho phép một INNER JOINhoặc WHEREđiều kiện tạo ra một tập hợp các nphần tử chỉ bằng cách ngẫu nhiên một số và chỉ định nó là WHERE table.Level = random_number. Thủ thuật là chỉ có 1 hàng cho Cấp 1, 2 hàng cho Cấp 2, 3 hàng cho Cấp 3, v.v. Do đó, việc sử dụng WHERE LevelID = 3sẽ giúp tôi có 3 hàng và mỗi hàng có một giá trị mà tôi có thể sử dụng làm tên thư mục.

THIẾT LẬP

Phần này ban đầu được chỉ định nội tuyến, là một phần của CTE. Nhưng vì mục đích dễ đọc (để bạn không cần phải cuộn qua nhiều INSERTcâu lệnh để đi đến một vài dòng của truy vấn thực sự), tôi đã chia nó thành một bảng tạm thời cục bộ.

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;

SỐ LƯỢNG CHÍNH

Đối với Cấp 1, tôi chỉ lấy [name]các giá trị sys.objectsvì luôn có nhiều hàng ở đó. Nhưng, nếu tôi cần kiểm soát nhiều hơn các tên, tôi có thể mở rộng #Elementsbảng để chứa các cấp bổ sung.

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

NHIỀU QUẢNG CÁO ĐỂ SẢN XUẤT MACHI TÊN, TÊN VÀ NỘI DUNG

Để tạo đường dẫn đầy đủ cho các tệp và nội dung tệp, tôi đã tạo CHỌN chính của CTE chỉ là một CTE khác và thêm một CHỌN chính mới cung cấp các đầu ra thích hợp chỉ cần đi vào các tệp.

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;

TÍN DỤNG THÊM

Mặc dù không phải là một phần của các yêu cầu được nêu trong câu hỏi, mục tiêu (đã được đề cập) là tạo các tệp để kiểm tra các hàm Hệ thống tệp đệ quy với. Vậy làm thế nào để chúng ta lấy kết quả này của tên đường dẫn, tên tệp và nội dung tệp và làm một cái gì đó với nó? Chúng ta chỉ cần hai hàm SQLCLR: một để tạo các thư mục và một để tạo các tệp.

Để làm cho dữ liệu này hoạt động, tôi đã sửa đổi phần chính SELECTcủa CTE được hiển thị trực tiếp ở trên như sau:

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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.