Skip to content

Commit 0cddebe

Browse files
committed
동적 변수 타입 기능 개선
1 parent 4d28e73 commit 0cddebe

File tree

6 files changed

+209
-189
lines changed

6 files changed

+209
-189
lines changed

CHANGELOG.md

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,48 @@
22

33
## v1.2.2 - 동적 변수 시스템 추가 (2025-08-20)
44

5-
### ✨ 새로운 기능
6-
- **🔄 동적 변수 시스템**: 데이터베이스에서 실시간으로 값을 조회하여 동적 쿼리 생성
7-
- **📊 3가지 동적 변수 타입**: `column_identified`, `key_value_pairs`, 기본 타입 지원
8-
- **🔗 시각 함수 통합**: 동적 변수에서 `CURRENT_TIMESTAMP`, `CURRENT_DATE` 등 시각 함수 사용 가능
9-
- **🌐 환경 변수 지원**: 동적 변수에서 환경 변수 사용 가능
10-
- **🐛 디버그 모드**: `DEBUG_VARIABLES=true` 환경 변수로 변수 치환 과정 상세 로깅
11-
12-
### 🔄 동적 변수 타입별 기능
13-
14-
#### 1. column_identified 타입
15-
- 각 컬럼별로 배열 생성
16-
- `${변수명.컬럼명}` 형태로 특정 컬럼의 값들만 사용
17-
- 예시: `${customerData.CustomerID}`, `${customerData.Region}`
18-
19-
#### 2. key_value_pairs 타입
20-
- 첫 번째 컬럼을 키로, 두 번째 컬럼을 값으로 생성
21-
- `${변수명.키명}` 형태로 키 값들만 사용
22-
- 예시: `${productPrices.ProductID}`
23-
24-
#### 3. 기본 타입
25-
- 첫 번째 컬럼의 값들을 배열로 생성
26-
- `${변수명}` 형태로 전체 배열 사용
27-
- 예시: `${activeCategories}`
5+
### ✨ 새로운 기능
6+
- **🔄 동적 변수 시스템**: 데이터베이스에서 실시간으로 값을 조회하여 동적 쿼리 생성
7+
- **📊 2가지 동적 변수 타입**: 기본 타입(`column_identified` 동작), `key_value_pairs` 타입 지원
8+
- **🎯 기본 타입 개선**: `type` 속성 생략 시 자동으로 `column_identified` 타입으로 처리
9+
- **🔗 시각 함수 통합**: 동적 변수에서 `CURRENT_TIMESTAMP`, `CURRENT_DATE` 등 시각 함수 사용 가능
10+
- **🌐 환경 변수 지원**: 동적 변수에서 환경 변수 사용 가능
11+
- **🐛 디버그 모드**: `DEBUG_VARIABLES=true` 환경 변수로 변수 치환 과정 상세 로깅
12+
13+
### 🔄 동적 변수 타입별 기능
14+
15+
#### 1. 기본 타입 (column_identified 동작)
16+
- `type` 속성 생략 시 기본값
17+
- 각 컬럼별로 배열 생성
18+
- `${변수명.컬럼명}` 형태로 특정 컬럼의 값들만 사용
19+
- 예시: `${customerData.CustomerID}`, `${customerData.Region}`
20+
21+
#### 2. key_value_pairs 타입
22+
- 명시적으로 `type="key_value_pairs"` 지정 필요
23+
- 첫 번째 컬럼을 키로, 두 번째 컬럼을 값으로 생성
24+
- `${변수명.키명}` 형태로 키 값들만 사용
25+
- 예시: `${productPrices.ProductID}`
2826

2927
### 📝 사용 예시
3028
```xml
31-
<!-- 동적 변수 정의 -->
32-
<dynamicVars>
33-
<dynamicVar name="customerData" type="column_identified" description="고객 데이터 컬럼별 분류">
34-
<![CDATA[
35-
SELECT CustomerID, CustomerName, City, Region
36-
FROM Customers WHERE IsActive = 1
37-
]]>
38-
</dynamicVar>
39-
40-
<dynamicVar name="productPrices" type="key_value_pairs" description="상품별 가격 정보">
41-
<![CDATA[
42-
SELECT ProductID, UnitPrice
43-
FROM Products WHERE Discontinued = 0
44-
]]>
45-
</dynamicVar>
46-
</dynamicVars>
29+
<!-- 동적 변수 정의 -->
30+
<dynamicVars>
31+
<!-- 기본 타입: type 속성 생략 -->
32+
<dynamicVar name="customerData" description="고객 데이터 컬럼별 분류">
33+
<![CDATA[
34+
SELECT CustomerID, CustomerName, City, Region
35+
FROM Customers WHERE IsActive = 1
36+
]]>
37+
</dynamicVar>
38+
39+
<!-- key_value_pairs 타입: 명시적 지정 -->
40+
<dynamicVar name="productPrices" type="key_value_pairs" description="상품별 가격 정보">
41+
<![CDATA[
42+
SELECT ProductID, UnitPrice
43+
FROM Products WHERE Discontinued = 0
44+
]]>
45+
</dynamicVar>
46+
</dynamicVars>
4747

4848
<!-- 동적 변수 사용 -->
4949
<sheet name="고객주문분석">
@@ -56,11 +56,12 @@
5656
</sheet>
5757
```
5858

59-
### 🔧 개선사항
60-
- **변수 치환 우선순위**: 동적 변수 > 일반 변수 > 시각 함수 > 환경 변수 순서로 처리
61-
- **SQL 인젝션 방지**: 모든 변수 값에 대해 적절한 이스케이핑 처리
62-
- **오류 처리 강화**: 동적 변수 처리 중 오류 발생 시 빈 배열로 대체하여 안전성 확보
63-
- **성능 최적화**: 동적 변수는 DB 연결 후, 시트 처리 전에 한 번만 실행
59+
### 🔧 개선사항
60+
- **기본 타입 간소화**: `type` 속성 생략 시 자동으로 `column_identified` 타입으로 처리하여 사용 편의성 향상
61+
- **변수 치환 우선순위**: 동적 변수 > 일반 변수 > 시각 함수 > 환경 변수 순서로 처리
62+
- **SQL 인젝션 방지**: 모든 변수 값에 대해 적절한 이스케이핑 처리
63+
- **오류 처리 강화**: 동적 변수 처리 중 오류 발생 시 빈 배열로 대체하여 안전성 확보
64+
- **성능 최적화**: 동적 변수는 DB 연결 후, 시트 처리 전에 한 번만 실행
6465

6566
### 📚 문서화
6667
- **README.md 업데이트**: 동적 변수 기능 소개 및 예시 추가

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,15 @@ node src/excel-cli.js help
9696
<var name="endDate">2024-12-31</var>
9797
</vars>
9898

99-
<!-- 동적 변수 -->
100-
<dynamicVars>
101-
<dynamicVar name="activeCustomers" type="column_identified" description="활성 고객 목록">
102-
<![CDATA[
103-
SELECT CustomerID, CustomerName, Region
104-
FROM Customers WHERE IsActive = 1
105-
]]>
106-
</dynamicVar>
107-
</dynamicVars>
99+
<!-- 동적 변수 -->
100+
<dynamicVars>
101+
<dynamicVar name="activeCustomers" description="활성 고객 목록">
102+
<![CDATA[
103+
SELECT CustomerID, CustomerName, Region
104+
FROM Customers WHERE IsActive = 1
105+
]]>
106+
</dynamicVar>
107+
</dynamicVars>
108108

109109
<sheet name="월별매출" use="true" aggregateColumn="Month">
110110
<![CDATA[

USER_MANUAL.md

Lines changed: 77 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -385,81 +385,89 @@ node src/excel-cli.js export --xml queries.xml --var "startDate=2024-06-01" --va
385385

386386
### 7. 동적 변수 시스템
387387

388-
#### 동적 변수 정의
389-
동적 변수는 데이터베이스에서 실시간으로 값을 조회하여 쿼리에 사용할 수 있는 고급 변수 시스템입니다.
390-
391-
```xml
392-
<!-- 동적 변수 정의 -->
393-
<dynamicVars>
394-
<!-- column_identified 타입: 각 컬럼별로 배열 생성 -->
395-
<dynamicVar name="customerData" type="column_identified" description="고객 데이터 컬럼별 분류">
396-
<![CDATA[
397-
SELECT CustomerID, CustomerName, City, Region
398-
FROM Customers WHERE IsActive = 1
399-
]]>
400-
</dynamicVar>
401-
402-
<!-- key_value_pairs 타입: 첫 번째 컬럼을 키로, 두 번째 컬럼을 값으로 -->
403-
<dynamicVar name="productPrices" type="key_value_pairs" description="상품별 가격 정보">
404-
<![CDATA[
405-
SELECT ProductID, UnitPrice
406-
FROM Products WHERE Discontinued = 0
407-
]]>
408-
</dynamicVar>
409-
410-
<!-- 기본 타입: 첫 번째 컬럼의 값들을 배열로 -->
411-
<dynamicVar name="activeCategories" description="활성 카테고리 목록">
412-
<![CDATA[
413-
SELECT CategoryID FROM Categories WHERE IsActive = 1
414-
]]>
415-
</dynamicVar>
416-
</dynamicVars>
417-
```
388+
#### 동적 변수 정의
389+
동적 변수는 데이터베이스에서 실시간으로 값을 조회하여 쿼리에 사용할 수 있는 고급 변수 시스템입니다.
390+
391+
```xml
392+
<!-- 동적 변수 정의 -->
393+
<dynamicVars>
394+
<!-- 기본 타입 (column_identified): type 속성 생략 시 기본값 -->
395+
<dynamicVar name="customerData" description="고객 데이터 컬럼별 분류">
396+
<![CDATA[
397+
SELECT CustomerID, CustomerName, City, Region
398+
FROM Customers WHERE IsActive = 1
399+
]]>
400+
</dynamicVar>
401+
402+
<!-- key_value_pairs 타입: 명시적으로 지정 필요 -->
403+
<dynamicVar name="productPrices" type="key_value_pairs" description="상품별 가격 정보">
404+
<![CDATA[
405+
SELECT ProductID, UnitPrice
406+
FROM Products WHERE Discontinued = 0
407+
]]>
408+
</dynamicVar>
409+
410+
<!-- 기본 타입 (column_identified): 각 컬럼별로 배열 생성 -->
411+
<dynamicVar name="activeCategories" description="활성 카테고리 목록">
412+
<![CDATA[
413+
SELECT CategoryID, CategoryName FROM Categories WHERE IsActive = 1
414+
]]>
415+
</dynamicVar>
416+
</dynamicVars>
417+
```
418418

419419
#### 동적 변수 사용 방법
420420

421-
**1. column_identified 타입 사용**
422-
```sql
423-
-- ${customerData.CustomerID} 형태로 특정 컬럼의 값들만 사용
424-
SELECT * FROM Orders
425-
WHERE CustomerID IN (${customerData.CustomerID})
426-
AND Region IN (${customerData.Region})
427-
```
428-
429-
**2. key_value_pairs 타입 사용**
430-
```sql
431-
-- ${productPrices.ProductID} 형태로 키 값들만 사용
432-
SELECT * FROM OrderDetails
433-
WHERE ProductID IN (${productPrices.ProductID})
434-
```
435-
436-
**3. 기본 타입 사용**
437-
```sql
438-
-- ${activeCategories} 형태로 전체 배열 사용
439-
SELECT * FROM Products
440-
WHERE CategoryID IN (${activeCategories})
441-
```
421+
**1. 기본 타입 (column_identified) 사용**
422+
```sql
423+
-- ${customerData.CustomerID} 형태로 특정 컬럼의 값들만 사용
424+
SELECT * FROM Orders
425+
WHERE CustomerID IN (${customerData.CustomerID})
426+
AND Region IN (${customerData.Region})
427+
428+
-- ${activeCategories.CategoryID} 형태로 특정 컬럼 사용
429+
SELECT * FROM Products
430+
WHERE CategoryID IN (${activeCategories.CategoryID})
431+
```
432+
433+
**2. key_value_pairs 타입 사용**
434+
```sql
435+
-- ${productPrices.ProductID} 형태로 키 값들만 사용
436+
SELECT * FROM OrderDetails
437+
WHERE ProductID IN (${productPrices.ProductID})
438+
```
442439

443440
#### 동적 변수 타입별 특징
444441

445-
| 타입 | 설명 | 사용법 | 예시 |
446-
|------|------|--------|------|
447-
| `column_identified` | 각 컬럼별로 배열 생성 | `${변수명.컬럼명}` | `${customerData.CustomerID}` |
448-
| `key_value_pairs` | 키-값 쌍으로 생성 | `${변수명.키명}` | `${productPrices.ProductID}` |
449-
| 기본 (없음) | 첫 번째 컬럼의 값들을 배열로 | `${변수명}` | `${activeCategories}` |
450-
451-
#### 시각 함수와 조합 사용
452-
```xml
453-
<dynamicVar name="recentOrders" description="최근 주문 정보">
454-
<![CDATA[
455-
SELECT OrderID, OrderNumber
456-
FROM Orders
457-
WHERE OrderDate >= '${startDate}'
458-
AND OrderDate <= '${endDate}'
459-
AND OrderDate >= DATEADD(day, -30, '${CURRENT_DATE}')
460-
]]>
461-
</dynamicVar>
462-
```
442+
| 타입 | 설명 | 사용법 | 예시 |
443+
|------|------|--------|------|
444+
| 기본 (없음) | 각 컬럼별로 배열 생성 (column_identified 동작) | `${변수명.컬럼명}` | `${customerData.CustomerID}` |
445+
| `key_value_pairs` | 키-값 쌍으로 생성 (명시적 지정 필요) | `${변수명.키명}` | `${productPrices.ProductID}` |
446+
447+
#### 시각 함수와 조합 사용
448+
```xml
449+
<!-- 기본 타입으로 다중 컬럼 동적 변수 -->
450+
<dynamicVar name="recentOrders" description="최근 주문 정보">
451+
<![CDATA[
452+
SELECT OrderID, OrderNumber, OrderDate
453+
FROM Orders
454+
WHERE OrderDate >= '${startDate}'
455+
AND OrderDate <= '${endDate}'
456+
AND OrderDate >= DATEADD(day, -30, '${CURRENT_DATE}')
457+
]]>
458+
</dynamicVar>
459+
```
460+
461+
**사용 예시:**
462+
```sql
463+
-- 최근 주문 ID들로 필터링
464+
SELECT * FROM OrderDetails
465+
WHERE OrderID IN (${recentOrders.OrderID})
466+
467+
-- 최근 주문 번호들로 검색
468+
SELECT * FROM Shipments
469+
WHERE OrderNumber IN (${recentOrders.OrderNumber})
470+
```
463471

464472
## 📋 CLI 명령어 참조
465473

queries/queries-with-dynamic-variables.json

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,27 @@
1616
"maxRows": 1000
1717
},
1818
"dynamicVars": [
19-
{
20-
"name": "customerData",
21-
"type": "column_identified",
22-
"description": "고객 데이터 컬럼별 분류",
23-
"query": "SELECT CustomerID, CustomerName, City, Region, CustomerType FROM SampleDB.dbo.Customers WHERE IsActive = 1 ORDER BY CustomerID"
24-
},
19+
{
20+
"name": "customerData",
21+
"description": "고객 데이터 컬럼별 분류",
22+
"query": "SELECT CustomerID, CustomerName, City, Region, CustomerType FROM SampleDB.dbo.Customers WHERE IsActive = 1 ORDER BY CustomerID"
23+
},
2524
{
2625
"name": "orderDetails",
2726
"type": "key_value_pairs",
2827
"description": "주문상세 정보",
2928
"query": "SELECT OrderID, OrderDetailID FROM SampleDB.dbo.OrderDetails ORDER BY OrderID"
3029
},
31-
{
32-
"name": "activeOrders",
33-
"description": "활성 주문 목록",
34-
"query": "SELECT OrderID FROM SampleDB.dbo.Orders WHERE OrderStatus = 'Pending' ORDER BY OrderID"
35-
},
36-
{
37-
"name": "recentOrders",
38-
"description": "최근 주문 정보",
39-
"query": "SELECT OrderID, OrderNumber, OrderDate FROM SampleDB.dbo.Orders WHERE OrderDate >= '${startDate}' AND OrderDate <= '${endDate}' AND OrderDate >= DATEADD(day, -30, '${CURRENT_DATE}') ORDER BY OrderDate DESC"
40-
}
30+
{
31+
"name": "activeOrders",
32+
"description": "활성 주문 목록",
33+
"query": "SELECT OrderID FROM SampleDB.dbo.Orders WHERE OrderStatus = 'Pending' ORDER BY OrderID"
34+
},
35+
{
36+
"name": "recentOrders",
37+
"description": "최근 주문 정보",
38+
"query": "SELECT OrderID, OrderNumber, OrderDate FROM SampleDB.dbo.Orders WHERE OrderDate >= '${startDate}' AND OrderDate <= '${endDate}' AND OrderDate >= DATEADD(day, -30, '${CURRENT_DATE}') ORDER BY OrderDate DESC"
39+
}
4140
],
4241
"sheets": [
4342
{
@@ -52,7 +51,7 @@
5251
"name": "주문상세_동적변수_테스트2",
5352
"use": true,
5453
"aggregateColumn": "주문상태",
55-
"query": "SELECT o.OrderID as 주문ID, o.OrderNumber as 주문번호, o.OrderStatus as 주문상태, od.OrderDetailID as 상세ID, FORMAT(o.TotalAmount, 'N0') as 총금액 FROM SampleDB.dbo.Orders o INNER JOIN SampleDB.dbo.OrderDetails od ON o.OrderID = od.OrderID WHERE o.OrderID IN (${orderDetails.OrderID}) AND o.OrderID IN (${activeOrders}) ORDER BY o.OrderID DESC"
54+
"query": "SELECT o.OrderID as 주문ID, o.OrderNumber as 주문번호, o.OrderStatus as 주문상태, od.OrderDetailID as 상세ID, FORMAT(o.TotalAmount, 'N0') as 총금액 FROM SampleDB.dbo.Orders o INNER JOIN SampleDB.dbo.OrderDetails od ON o.OrderID = od.OrderID WHERE o.OrderID IN (${orderDetails.OrderID}) AND o.OrderID IN (${activeOrders.OrderID}) ORDER BY o.OrderID DESC"
5655
},
5756
{
5857
"name": "주문상세_동적변수_테스트",
@@ -63,7 +62,7 @@
6362
{
6463
"name": "복합_동적변수_테스트",
6564
"use": true,
66-
"query": "SELECT c.CustomerName as 고객명, c.Region as 지역, COUNT(o.OrderID) as 주문건수, FORMAT(SUM(o.TotalAmount), 'N0') as 총주문금액 FROM SampleDB.dbo.Customers c INNER JOIN SampleDB.dbo.Orders o ON c.CustomerID = o.CustomerID WHERE c.CustomerID IN (${customerData.CustomerID}) AND c.Region IN (${customerData.Region}) AND o.OrderID IN (${activeOrders}) AND o.OrderDate >= '${startDate}' AND o.OrderDate <= '${endDate}' GROUP BY c.CustomerName, c.Region ORDER BY 총주문금액 DESC"
65+
"query": "SELECT c.CustomerName as 고객명, c.Region as 지역, COUNT(o.OrderID) as 주문건수, FORMAT(SUM(o.TotalAmount), 'N0') as 총주문금액 FROM SampleDB.dbo.Customers c INNER JOIN SampleDB.dbo.Orders o ON c.CustomerID = o.CustomerID WHERE c.CustomerID IN (${customerData.CustomerID}) AND c.Region IN (${customerData.Region}) AND o.OrderID IN (${activeOrders.OrderID}) AND o.OrderDate >= '${startDate}' AND o.OrderDate <= '${endDate}' GROUP BY c.CustomerName, c.Region ORDER BY 총주문금액 DESC"
6766
},
6867
{
6968
"name": "시각함수_동적변수_테스트",

0 commit comments

Comments
 (0)