각 노드에 임의의 수의 자식이있는 여러 레벨의 계층 구조 작성


16

계층 구조와 관련된 테스트 데이터를 만들어야합니다. 쉽게 만들고 몇 가지 작업을 수행 할 수는 CROSS JOIN있지만 변형없이 완전히 균일 한 구조를 제공합니다. 그것은 둔한 것처럼 보일뿐만 아니라 테스트 데이터의 변화가 부족하면 때때로 발견 될 수있는 문제를 숨 깁니다. 따라서 다음 규칙을 따르는 비 균일 계층을 생성하려고합니다.

  • 3 단계 깊이
    • 레벨 1은 임의로 5-20 개의 노드입니다.
    • 레벨 2는 1-10 개의 노드이며 레벨 1의 각 노드마다 무작위입니다.
    • 레벨 3은 1-5 개의 노드이며 레벨 2의 각 노드마다 무작위입니다.
  • 모든 가지의 깊이는 3 단계입니다. 이 시점에서 깊이의 균일 성은 괜찮습니다.
  • 특정 수준에서 하위 노드 이름이 겹칠 수 있습니다 (즉, 하위 노드 이름이 동일한 수준의 모든 노드에서 고유 할 필요는 없음).
  • 여기서 "랜덤"이라는 용어는 고유 한 무작위가 아닌 의사 랜덤 인 것으로 정의됩니다 . "랜덤"이라는 용어는 종종 "중복을 생성하지 않는 주어진 세트의 랜덤 순서"를 의미하기 때문에 사용되어야합니다. 나는 임의의 = 랜덤을 수용하고 레벨 1의 각 노드 당 자식 수가 4, 7, 8 인 경우에도 레벨 1의 20 개 노드에서도 노드마다 1-10 개의 자식이 확산 될 수 있음을 인정합니다. 그것은 무작위입니다.
  • 중첩 WHILE루프를 사용하면 이 작업을 쉽게 수행 할 수 있지만 집합 기반 접근 방식을 찾는 것이 좋습니다. 일반적으로 테스트 데이터 생성에는 프로덕션 코드에 필요한 효율성에 대한 요구 사항이 없지만 세트 기반 접근 방식의 촬영은 더 교육적이고 문제에 대한 세트 기반 접근 방식을 찾는 데 도움이 될 것입니다. 따라서 WHILE루프는 배제되지 않지만 세트 기반 접근이 불가능한 경우에만 사용할 수 있습니다.
  • 집합 기반 = CTE, APPLY 등에 상관없이 단일 쿼리에 이상적입니다. 따라서 기존 또는 인라인 숫자 테이블을 사용하는 것이 좋습니다. WHILE / CURSOR / 절차 적 접근 방식을 사용하면 작동하지 않습니다. 작업이 모두 세트 기반이고 루프가없는 한 데이터의 일부를 임시 테이블 또는 테이블 변수로 스테이징한다고 가정합니다. 그러나 다중 쿼리 접근 방식이 실제로 더 우수하다는 것을 보여주지 않는 한 단일 쿼리 접근 방식이 여러 쿼리보다 선호 될 것입니다. 또한 "더 나은"구성 요소는 일반적으로 주관적이며 ;-)입니다. 이전 문장에서 "일반적으로"를 사용하는 것도 주관적이라는 점을 명심하십시오.
  • SQL Server의 모든 버전과 에디션 (2005 이상)이 가능합니다.
  • 순수한 T-SQL 만 해당 바보 같은 SQLCLR 항목은 없습니다! 적어도 데이터 생성 측면에서. 디렉토리 및 파일 작성은 SQLCLR을 사용하여 수행됩니다. 그러나 여기서는 무엇을 만들지 가치를 창출하는 데 중점을 둡니다.
  • T-SQL Multi-statement TVF는 외부에서 세트 방식으로 절차 적 접근 방식을 숨기는 경우에도 세트 기반이 아닌 절차 적 것으로 간주됩니다. 그것이 절대적으로 적절한 때가 있습니다. 지금은 그중 하나가 아닙니다. 동일한 행과 함께 T-SQL Scalar 함수도 절차적일뿐 아니라 쿼리 최적화 프로그램에서 값을 캐시하고 출력이 예상과 다르게 반복되도록하는 경우도 있습니다.
  • T-SQL 인라인 TVF (일명 iTVF)는 설정 기반이기 때문에 okey-dokey이며 [ CROSS | OUTER ] APPLY, 위에서 사용하는 것과 동일 합니다.
  • 쿼리를 반복해서 실행하면 이전 실행과 다른 결과가 나타납니다.
  • 설명 업데이트 1 : 최종 결과 집합은 Level1에서 시작하여 전체 경로를 갖는 Level3의 각 개별 노드에 대해 하나의 행을 갖는 것으로 표현되어야합니다. 이는 단일 Level3 노드 만 포함하는 단일 Level2 노드 만있는 경우를 제외하고 Level1 및 Level2 값이 하나 이상의 행에서 반드시 반복됨을 의미합니다.
  • 설명 업데이트 2 : 숫자뿐만 아니라 이름이나 레이블이있는 각 노드에 대해 매우 강력한 환경 설정이 있습니다. 이를 통해 결과 테스트 데이터가보다 의미 있고 사실적 일 수 있습니다.

이 추가 정보가 중요한지 확실하지 않지만 컨텍스트를 갖는 데 도움이되는 경우 테스트 데이터는이 질문에 대한 내 대답과 관련이 있습니다.

XML 파일을 SQL Server 2012로 가져 오기

이 시점에서는 관련이 없지만이 계층 구조 생성의 최종 목표는 재귀 파일 시스템 메소드를 테스트하기위한 디렉토리 구조를 작성하는 것입니다. 레벨 1과 2는 디렉토리가되고 레벨 3은 파일 이름이됩니다. 나는 (여기에서 Google을 통해) 주변을 검색했으며 무작위 계층 구조 생성에 대한 참조를 하나만 찾았습니다.

Linux : 임의의 디렉토리 / 파일 계층 구조 생성

이 질문 (StackOverflow)은 실제로 원하는 결과 측면에서 매우 가깝습니다. 테스트를위한 디렉토리 구조를 만들기도하기 때문입니다. 그러나이 질문과 답변은 Linux / Unix 쉘 스크립팅에 초점을 맞추고 있으며 우리가 살고있는 세트 기반 세계는 아닙니다.

이제 임의의 데이터를 생성하는 방법을 알고 있으며 파일의 내용을 만들어 변형을 표시 할 수 있습니다. 여기서 까다로운 부분은 각 세트 내의 요소 수가 특정 필드가 아니라 임의적이라는 것입니다. 그리고 각 노드 내의 요소 수는 동일한 수준의 다른 노드와 무작위 여야합니다.

계층 구조 예

     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

위의 계층을 설명하는 결과 집합 예

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

답변:


9

( OP의 참고 : 선호하는 솔루션은 4 번째 / 최종 코드 블록입니다)

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 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()가 각 노드 에 대해 서로 다른 값을 사용 하게하는 방법은 하위 쿼리를 서로 관련시키는 것입니다. N1.N > 0그리고 N2.N > 0.

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

그리고 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;

상관 관계 N1.N > 0와는 N2.N > 0여전히 중요하다.

정수 대신 20 개의 이름을 가진 테이블을 사용하는 버전.

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
나는 새 버전을 더 좋아한다. 첫 번째 시도에서 생각해 낸 것과 거의 동일하지만 어떤 이유로 든 TOP(n)2 CROSS APPLY초에 제대로 작동 하지 못했습니다 . 다른 일을하면 코드를 제거 한 후 다르게 / 잘못한 일이 확실하지 않습니다. 이 업데이트를 제공 했으므로 곧 게시하겠습니다. 그리고 위의 의견을 대부분 정리했습니다.
Solomon Rutzky

방금 내 버전을 게시했습니다. 주요 차이점은 다음과 같습니다 : 1) 나는 일에 TOP (N)를 얻을 수 없기 때문에, 나는 점점 갔다 nWHERE 조건을 통해 요소를, 그리고 2) 나는이 name더 무작위 디렉토리 및 / 또는 파일 이름보다 제어 구성 요소를 .
Solomon Rutzky

너무 오래 떨어져서 미안하지만 바빠서 바빴어요 아직도, 나는 이것에 대해 생각하고 있으며 내 대답과 비 XML 버전 사이에서 결정할 수 없습니다. 나는 당신의 단순성과 유연성을 좋아하지만 폴더 구조를 만드는 데 사용할 이름을 반환 할 수 있어야합니다. 그런 다음 Vlad가 조회 테이블을 갖도록 업데이트하고 이상적인 출력을 제공하도록 조인했습니다. 부적절하지 않은 경우 동일한 조회를 포함하도록 업데이트 할 수 있습니까? 그런 다음 세 가지 답변 모두 동등한 결과를 제공하고 (3 가지를 모두 비교하는 데 이상적) 귀하의 답변을 수락합니다. 그 확인은?
Solomon Rutzky

1
@ srutzky 답변을 업데이트했습니다. 얼마 전에 내가 옳았 으면 좋겠다. 물론 @Elemets각 레벨마다 선택할 수있는 다른 이름 세트를 얻기 위해 레벨 열을 추가 할 수 있습니다 .
Mikael Eriksson

1
@srutzky 걱정하지 마십시오. 답변이 도움이되어 다행입니다.
Mikael Eriksson 2016 년

6

재미있었습니다.

내 목표는 적절하게 연결된 계층 구조에서 각 수준마다 임의의 자식 행 수로 지정된 수의 수준을 생성하는 것이 었습니다. 이 구조가 준비되면 파일 및 폴더 이름과 같은 추가 정보를 쉽게 추가 할 수 있습니다.

그래서 트리를 저장하기 위해 클래식 테이블을 생성하고 싶었습니다.

ID int NOT NULL
ParentID int NULL
Lvl int NOT NULL

우리는 재귀를 다루기 때문에 재귀 적 CTE는 자연스러운 선택입니다.

나는 숫자 테이블 이 필요 합니다 . 표의 숫자는 1부터 시작해야합니다. 표에는 20 개 이상의 숫자가 있어야합니다 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;

데이터 생성을위한 매개 변수는 테이블에 저장해야합니다.

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

쿼리는 매우 유연하며 모든 매개 변수가 한 곳으로 분리됩니다. 필요한 경우 더 많은 레벨을 추가하고 추가 행을 추가하면됩니다.

이러한 동적 생성을 가능하게하려면 다음 레벨의 임의의 행 수를 기억해야하므로 추가 열이 ChildRowCount있습니다.

고유 한 생성 IDs도 다소 까다 롭습니다. IDs반복하지 않도록 부모 행 1 개당 자식 행 100 개를 하드 코딩했습니다 . 이것이 바로 그 일입니다 POWER(100, CTE.Lvl). 결과적으로에 큰 차이가 IDs있습니다. 그 숫자는 일 수 MAX(LvlMax)있지만 단순성을 위해 쿼리에 상수 100을 넣습니다. 레벨 수는 하드 코딩되지 않지만에 의해 결정됩니다 @Intervals.

이 공식

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

범위 내에서 임의의 부동 소수점 숫자를 생성 한 [0..1)다음 필요한 간격으로 조정됩니다.

쿼리 로직은 간단합니다. 재귀 적입니다. 첫 번째 단계는 첫 번째 레벨의 행 세트를 생성합니다. 행 수는의 난수로 결정됩니다 TOP. 또한 각 행에 대해 별도의 임의의 수의 하위 행이 저장됩니다 ChildRowCount.

재귀 부분은 CROSS APPLY각 부모 행당 주어진 수의 자식 행을 생성 하는 데 사용 됩니다. CTE의 재귀 부분에서는 허용되지 않기 때문에 WHERE Numbers.Number <= CTE.ChildRowCount대신 대신 사용해야 했습니다 . 이전에 SQL Server의 이러한 제한에 대해 몰랐습니다.TOP(CTE.ChildRowCount)TOP

WHERE CTE.ChildRowCount IS NOT NULL 재귀를 중지합니다.

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;

결과 (운이 좋으면 최대 20 + 20 * 10 + 200 * 5 = 1220 행이있을 수 있음)

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

연결된 계층 구조 대신 전체 경로 생성

우리는 단지 전체 경로에 관심이 있다면 N깊은 수준, 우리는 생략 할 수 있습니다 IDParentIDCTE에에서. 보충 테이블에 가능한 이름 목록이 있으면 NamesCTE의이 테이블에서 쉽게 선택할 수 있습니다. Names테이블은 각 레벨에 충분한 열을가한다 : (20)를 레벨 1, 레벨 10에 대한 3 레벨 2, 5; 총 20 + 10 + 5 = 35 각 수준마다 다른 행 집합을 가질 필요는 없지만 올바르게 설정하기가 쉽기 때문에 그렇게했습니다.

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 다음은 최종 쿼리입니다. 나는 분할 FullPathFilePath하고 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;

결과

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

재미있는 접근법 :). 나는 그것을 좋아한다. 완벽을 기하기 위해 SQL 테이블에서 Numbers 테이블을 채우는 쿼리를 추가하거나 CTE의 일부로 인라인을 포함시킬 수 있습니까? 그런 다음 누군가 복사하여 붙여 넣기가 더 쉽습니다. 이 답을 위해, 각 출력이 모든 레벨 3 값에 대해 레벨 1에서 레벨 3까지의 전체 경로 인 최종 출력을 표현할 수 있습니까? 나는 INNER JOIN최종 2 초 정도 걸릴 것이라고 생각합니다 SELECT. 마지막으로, 이름 / 라벨을 각 노드에 할당하여 숫자가 아닌가? 이 두 가지 사항을 명확히하기 위해 질문을 업데이트하겠습니다.
Solomon Rutzky 2016

이 이름 / 라벨은 어디에서 왔습니까? 20 개의 행이 있고 이름을 선택하는 '이름'테이블이 있어야합니까? 따라서 각 레벨에 동일한 이름 세트가 나타납니다. 또는 각 레벨마다 고유 한 이름 세트가 있어야합니까?
Vladimir Baranov

이름은 CTE의 일부로 테이블 (temp, real 또는 variable) 또는 인라인에서 올 수 있다고 생각합니다. 원래 CTE에 넣은 다음 쿼리의 주요 부분을 더 읽기 쉽게 로컬 임시 테이블로 옮겼습니다. 나는 당신이 가진 구조로 레벨별로 분리하기가 쉽다고 생각합니다. 그러나 20 개 중 한 세트만으로도 충분하다면 테스트 데이터의 편차가 약간 줄어 듭니다. 유일한 진정한 요구 사항은 디렉토리 또는 파일을 만들려고 할 때 오류가 발생하므로 노드 내에서 이름이 반복되지 않아야한다는 것입니다. :).
Solomon Rutzky

1
@ srutzky, 나는 두 번째 변형을 추가했습니다.
Vladimir Baranov 5

1
@srutzky, 나는 분할 FullPathFilePathFileName.
Vladimir Baranov

4

그래서 여기에 내가 생각해 낸 것이 있습니다. 디렉토리 구조를 만들기 위해 디렉토리와 파일에 사용할 수있는 "이름"을 찾고있었습니다. 내가 얻을 수 없기 때문에 TOP(n)에서 작업을 CROSS APPLY(내가이 같은 부모에서 값을 사용하여 쿼리의 상관 관계를하려고 생각의 n에서 TOP(n)하지만 그것은 임의 아니었다), I는 "숫자"의 유형을 만들기로 결정 INNER JOINor 또는 WHEREcondition이 n단순히 숫자를 무작위 화하고로 지정하여 요소 집합을 생성 할 수 있도록하는 표 WHERE table.Level = random_number. 트릭은 Level1에 대해 1 행, Level2에 대해 2 행, Level3에 대해 3 행 등이 있다는 것입니다. 따라서를 사용 WHERE LevelID = 3하면 3 행이 표시되고 각 행에는 디렉토리 이름으로 사용할 수있는 값이 있습니다.

설정

이 부분은 원래 CTE의 일부로 인라인으로 지정되었습니다. 그러나 가독성을 위해 ( INSERT실제 쿼리의 몇 줄에 도달하기 위해 많은 명령문 을 스크롤 할 필요가 없도록 ) 로컬 임시 테이블로 분리했습니다.

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;

메인 쿼리

레벨 1의 경우 항상 많은 행이 있으므로 [name]값을 가져 sys.objects왔습니다. 그러나 이름을 더 세밀하게 제어해야하는 경우 #Elements추가 수준을 포함 하도록 테이블을 확장 할 수 있습니다.

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

각 파일의 경로, 이름 및 목차를 생성하기 위해 적용된 쿼리

파일과 파일 내용에 대한 전체 경로를 생성하기 위해 CTE의 기본 SELECT를 다른 CTE로 만들고 파일로 이동 해야하는 적절한 출력을 제공하는 새로운 기본 SELECT를 추가했습니다.

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;

추가 신용

질문에 언급 된 요구 사항의 일부는 아니지만, 목표는 재귀 파일 시스템 기능을 테스트 할 파일을 작성하는 것이 었습니다. 그렇다면이 경로 이름, 파일 이름 및 파일 내용의 결과 집합을 어떻게 취하고 어떻게해야합니까? 하나는 폴더를 작성하고 다른 하나는 파일을 작성하는 두 가지 SQLCLR 기능이 필요합니다.

이 데이터를 기능적으로 사용하기 위해 SELECT직접 위에 표시된 CTE 의 기본 을 다음과 같이 수정했습니다 .

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;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.