docker run --name some-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql
mysql에 로그인해서 northwind 데이터베이스를 만든다.
$ mysql -u root -p -h 127.0.0.1
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.4.0 MySQL Community Server - GPL
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> create database northwind;
Query OK, 1 row affected (0.01 sec)
다운로드한 sql 파일을 이용해서 데이터셋을 적재한다.
mysql -u root -p northwind -h 127.0.0.1 < northwindmysql.sql
Text2SQL은 자연어를 SQL 쿼리로 변환하는 시스템이다. Llama3.1 로 테스트를 했다.
Input
You are an assistant who creates SQL queries. Please create the sentence below as an SQL query.
What is the product sales volume in South Korea in 2024?
Output
Here is the SQL query:
SELECTSUM(sales_volume)AS total_sales_volume
FROM
sales_data
WHERE
country ='South Korea'ANDyear=2024;
Note: This assumes that you have a table named sales_data with columns for sales_volume, country, and year. You may need to modify the query depending on your actual database schema.
잘 만들어주기는 하지만 실제 환경에서는 테이블 이름, 필드 이름 그리고 각종 코드 값들을 알고 있어야 한다. 예를 들어 country는 "kr", "South korea", "korea", "82"등이 될 수 있다. 시간 양식도 일치해야 한다.
따라서 반드시 테이블 스키마를 학습 시켜야 한다.
Text2SQL 예제 테스트
📌 예제 Input에 사용하는 DDL은 일부분 생략을 했습니다.
간단한 SELECT
Input
You are an assistant chatbot that creates SQL queries. Please refer to DDL and create the sentence below as a SQL query.
모든 고객의 수를 알려주세요.
### DDL
CREATE TABLE customers (
CustomerID varchar(5) NOT NULL,
CompanyName varchar(40) NOT NULL,
ContactName varchar(30) DEFAULT NULL,
Address varchar(60) DEFAULT NULL,
City varchar(15) DEFAULT NULL,
Region varchar(15) DEFAULT NULL,
Country varchar(15) DEFAULT NULL,
)
Output
모든 고객의 수를 구하는 SQL 쿼리는 다음과 같습니다:
SELECTCOUNT(*)AS total_customers
FROM customers;
이 쿼리는 customers 테이블에서 모든 고객의 수를 계산하고, 그 결과를 total_customers라는 별칭으로 반환합니다.
테스트
성공
mysql> SELECT COUNT(*) AS total_customers
-> FROM customers;
+-----------------+
| total_customers |
+-----------------+
| 91 |
+-----------------+
1 row in set (0.00 sec)
예제: Where 절
Input
London에 살고 있는 모든 고객의 ID, 고객이름, 전화번호를 알려주세요.
Output
Here is the SQL query that responds to "London에 살고 있는 모든 고객의 ID, 고객이름, 전화번호를 알려주세요." which translates to "Tell me the ID, customer name and phone number of all customers living in London":
SELECT CustomerID, ContactName, Phone
FROM customers
WHERE City ='London';
This query selects the CustomerID, ContactName, and Phone columns from the customers table where the value in the City column is exactly 'London'. The result will be a list of customer information living in London.
테스트
성공
mysql> SELECT CustomerID, ContactName, Phone
-> FROM customers
-> WHERE City = 'London';
+------------+-------------------+----------------+
| CustomerID | ContactName | Phone |
+------------+-------------------+----------------+
| AROUT | Thomas Hardy | (171) 555-7788 |
| BSBEV | Victoria Ashworth | (171) 555-1212 |
| CONSH | Elizabeth Brown | (171) 555-2282 |
| EASTC | Ann Devon | (171) 555-0297 |
| NORTS | Simon Crowther | (171) 555-7733 |
| SEVES | Hari Kumar | (171) 555-1717 |
+------------+-------------------+----------------+
6 rows in set (0.00 sec)
Group By
Input
각 국가별 고객수 통계를 내주세요. SQL query만 출력해주세요.
Output
SELECT Country,COUNT(*)as CustomerCount
FROM customers
GROUPBY Country
ORDERBY CustomerCount DESC;
테스트
성공
mysql> SELECT Country, COUNT(*) as CustomerCount
-> FROM customers
-> GROUP BY Country
-> ORDER BY CustomerCount DESC;
+-------------+---------------+
| Country | CustomerCount |
+-------------+---------------+
| USA | 13 |
| France | 11 |
| Germany | 11 |
| Brazil | 9 |
| UK | 7 |
| Mexico | 5 |
Join
Northwind 에는 Order(주문)테이블과 Shippers(선적사)테이블을 가지고 있다. 이 두 개의 테이블을 JOIN해서 주문 정보를 조회해 보자. 배송업체별 총 주문 금액을 알려달라고 요청했다.
Input
You are an assistant chatbot that creates SQL queries. Please create the following sentences as SQL queries by referring to the orders table and shippers table below.
Please tell me the total order amount by shipper.
### orders table
CREATE TABLE `orders` (
`OrderID` int(11) NOT NULL AUTO_INCREMENT,
`CustomerID` varchar(5) DEFAULT NULL,
`EmployeeID` int(11) DEFAULT NULL,
`OrderDate` datetime DEFAULT NULL,
`RequiredDate` datetime DEFAULT NULL,
`ShipRegion` varchar(15) DEFAULT NULL,
`ShipPostalCode` varchar(10) DEFAULT NULL,
`ShipCountry` varchar(15) DEFAULT NULL,
PRIMARY KEY (`OrderID`),
KEY `CustomerID` (`CustomerID`),
KEY `EmployeeID` (`EmployeeID`),
KEY `ShipPostalCode` (`ShipPostalCode`)
)
### shippers table
CREATE TABLE `shippers` (
`ShipperID` int(11) NOT NULL AUTO_INCREMENT,
`CompanyName` varchar(40) NOT NULL,
`Phone` varchar(24) DEFAULT NULL,
PRIMARY KEY (`ShipperID`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
Output
To get the total order amount by shipper, we can use a SQL query that groups the orders by the ShipVia column (which represents the shipper ID), and then calculates the sum of the Freight column for each group.
SELECT s.CompanyName,SUM(o.Freight)AS TotalOrderAmount
FROM orders o
JOIN shippers s ON o.ShipVia = s.ShipperID
GROUPBY s.CompanyName;
This query joins the orders table with the shippers table on the ShipVia and ShipperID columns. Then, it groups the results by the CompanyName of the shipper and calculates the sum of the Freight column for each group, which gives us the total order amount for each shipper.
When you run this query, you should get a result set with two columns: CompanyName and TotalOrderAmount. The CompanyName column will list all the unique company names from the shippers table, and the TotalOrderAmount column will show the sum of the freight costs for each company.
테스트
성공
mysql> SELECT s.CompanyName, SUM(o.Freight) AS TotalOrderAmount
-> FROM orders o
-> JOIN shippers s ON o.ShipVia = s.ShipperID
-> GROUP BY s.CompanyName;
+------------------+------------------+
| CompanyName | TotalOrderAmount |
+------------------+------------------+
| Federal Shipping | 20512.5100 |
| Speedy Express | 16185.3300 |
| United Package | 28244.8500 |
+------------------+------------------+
Please tell me the order statistics by shipper company.
Output
각 물류 회사의 주문 통계를 알려드리겠습니다.
SELECT s.CompanyName,COUNT(o.OrderID)AS TotalOrders,SUM(o.Freight)AS TotalFreight,AVG(o.Freight)AS AverageFreight,MIN(o.Freight)AS MinFreight,MAX(o.Freight)AS MaxFreight
FROM orders o
JOIN shippers s ON o.ShipVia = s.ShipperID
GROUPBY s.CompanyName;
이 쿼리는 각 물류 회사에 대한 총 주문 수, 총 비용, 평균 비용, 최소 비용 및 최대 비용을 표시합니다.
테스트
SELECT s.CompanyName,
-> COUNT(o.OrderID) AS TotalOrders,
-> SUM(o.Freight) AS TotalFreight,
-> AVG(o.Freight) AS AverageFreight,
-> MIN(o.Freight) AS MinFreight,
-> MAX(o.Freight) AS MaxFreight
-> FROM orders o
-> JOIN shippers s ON o.ShipVia = s.ShipperID
-> GROUP BY s.CompanyName;
+------------------+-------------+--------------+----------------+------------+------------+
| CompanyName | TotalOrders | TotalFreight | AverageFreight | MinFreight | MaxFreight |
+------------------+-------------+--------------+----------------+------------+------------+
| Federal Shipping | 255 | 20512.5100 | 80.44121569 | 0.4000 | 1007.6400 |
| Speedy Express | 249 | 16185.3300 | 65.00132530 | 0.1200 | 458.7800 |
| United Package | 326 | 28244.8500 | 86.64064417 | 0.0200 | 890.7800 |
+------------------+-------------+--------------+----------------+------------+------------+
예제: AND, OR, NOT 연산
categories 테이블에는 제품 분류 정보, products 테이블에는 제품 정보, suppliers 테이블에는 제품제공 회사정보가 저장되어 있다.
미국에 있는 회사 목록을 확인하고 특정 회사가 취급하는 제품목록을 확인해 보자. AND 연산 그리고 JOIN이 들어가는 (나름)복잡한 예제다.
예제가 너무 길어져서 테이블 DDL은 생략했다.
Input
You are an assistant chatbot that creates SQL queries. Please create the following sentences as SQL queries by referring to the suppliers table and products table and categories table below.
Please tell me about products sold in the "Condiments" category by "Grandma Kelly's Homestead" company.
### suppliers table
// 생략
### products table
// 생략
### categories table
// 생략
Output
다음과 같은 SQL 쿼리가 판매된 제품에 대한 자세한 정보를 제공합니다:
SELECT p.ProductName, c.CategoryName, s.CompanyName,
p.QuantityPerUnit, p.UnitPrice, p.UnitsInStock, p.Discontinued
FROM products p
JOIN categories c ON p.CategoryID = c.CategoryID
JOIN suppliers s ON p.SupplierID = s.SupplierID
WHERE c.CategoryName ='Condiments'AND s.CompanyName ='Grandma Kelly''s Homestead';
이 쿼리는 products 테이블을 categories와 suppliers 테이블과 연결하여 'Condiments' 카테고리 내의 '그랜드 켈리의 하우스' 회사에서 판매된 제품에 대한 정보를 선택합니다.
제품 이름
카테고리 이름
회사의 이름
단위당량
단위가액
재고 수
취소 여부
테스트
성공. 잘 나왔다 직접 테스트해보자.
Having
employees 테이블에는 직원 정보가 들어있다. 직원의 성과 평가를 위해서 10개 이상의 주문을 등록한 직원을 살펴보는 쿼리를 만들어보자.
Input
You are an assistant chatbot that creates SQL queries. Please create the following sentences as SQL queries by referring to the orders table and employees table below.
Please let me know if you have any employees who have processed more than 10 orders.
### orders table
CREATE TABLE `orders` (
`OrderID` int(11) NOT NULL AUTO_INCREMENT,
`CustomerID` varchar(5) DEFAULT NULL,
`EmployeeID` int(11) DEFAULT NULL,
`ShipAddress` varchar(60) DEFAULT NULL,
`ShipRegion` varchar(15) DEFAULT NULL,
`ShipPostalCode` varchar(10) DEFAULT NULL,
`ShipCountry` varchar(15) DEFAULT NULL,
)
### employees table
CREATE TABLE `employees` (
`EmployeeID` int(11) NOT NULL AUTO_INCREMENT,
`LastName` varchar(20) NOT NULL,
`FirstName` varchar(10) NOT NULL,
`Title` varchar(30) DEFAULT NULL,
`HomePhone` varchar(24) DEFAULT NULL,
`Extension` varchar(4) DEFAULT NULL,
`Photo` longblob,
`Notes` longtext,
`ReportsTo` int(11) DEFAULT NULL,
PRIMARY KEY (`EmployeeID`),
) ENGINE=MyISAM AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
Output
Here is the SQL query that checks if there are any employees who have processed more than 10 orders:
SELECT e.LastName, e.FirstName,COUNT(o.OrderID)as TotalOrders
FROM employees e
JOIN orders o ON e.EmployeeID = o.EmployeeID
GROUPBY e.EmployeeID
HAVINGCOUNT(o.OrderID)>10;
테스트
성공
+-----------+-----------+-------------+
| LastName | FirstName | TotalOrders |
+-----------+-----------+-------------+
| Davolio | Nancy | 123 |
| Fuller | Andrew | 96 |
| Leverling | Janet | 127 |
| Peacock | Margaret | 156 |
| Buchanan | Steven | 42 |
| Suyama | Michael | 67 |
| King | Robert | 72 |
| Callahan | Laura | 104 |
| Dodsworth | Anne | 43 |
+-----------+-----------+-------------+
Between
가격이 10에서 20 사이의 제품 목록을 가져와보자.
Input
You are an assistant chatbot that creates SQL queries. Please create the following sentences as SQL queries by referring to the products table below.
Please give me a list of products that are priced between 15 and 20.
### products table
CREATE TABLE `products` (
`ProductID` int(11) NOT NULL AUTO_INCREMENT,
`ProductName` varchar(40) NOT NULL,
`SupplierID` int(11) DEFAULT NULL,
`Discontinued` tinyint(1) DEFAULT '0',
PRIMARY KEY (`ProductID`),
KEY `CategoryID` (`CategoryID`),
KEY `ProductName` (`ProductName`),
KEY `SupplierID` (`SupplierID`)
) ENGINE=MyISAM AUTO_INCREMENT=78 DEFAULT CHARSET=utf8;
Output
Here is the SQL query that gives you a list of products priced between 15 and 20:
SELECT ProductName, UnitPrice
FROM products
WHERE UnitPrice BETWEEN15.0000AND20.0000;
This query selects the ProductName and UnitPrice from the products table where the UnitPrice is greater than or equal to 15.0000 and less than or equal to 20.0000.
Note: As before, the BETWEEN operator includes both the start and end values in its search, so this query will return products with prices exactly equal to 15 or 20. If you want to exclude these products, you can use a greater-than-or-equal-to (>=) and less-than-or-equal-to (<=) combination instead:
DDL을 훈련시키는 것으로 복잡한 쿼리까지 만들 수 있음을 확인했다. 여기에서는 수작업으로 테이블 정보를 모델에 넘겼는데, LLM App이 자연어로 부터 테이블 이름을 추출할 수 있도록 하면 될 것이다. 굳이 테이블 이름을 추출하는 과정을 거치지 않고 모든 테이블 정보를 프롬프트로 넘겨도 되겠지만 테이블이 수십/수백개가 넘어가면 프롬프트가 쓸데없이 커지는 문제가 있다.
Input
You are an assistant chatbot that creates SQL queries. Please refer to the table name in the table information and tell me the table name needed to create the SQL query.
Please give me a list of products that are priced between 15 and 20.
### Table information
| table name | description |
| ---------- | ------------------------------------------------------ |
| products | 상품가격, 상품 이름등의 정보를 가지고 있습니다. |
| orders | 주문 상품, 주문 잘짜 등의 정보를 가지고 있습니다. |
| customers | 고객이름, 주소, 전화 번호 등의 정보를 가지고 있습니다. |
Output
To find the list of products priced between 15 and 20, I'll need to refer to:
products: This table contains information about the products themselves.
I can help you craft a query that will give you the list of products with prices within this range!
Would you like me to assist with crafting the SQL query?
Text2SQL 아키텍처
Assistant Model
지금 까지의 테스트 내용을 토대로 위 이미지 형태를 가지는 Assistant Model를 제안 할 수 있다.
사용자가 자연어를 입력하면 Assistant는 Database meta data 의 정보를 읽어서 프롬프트를 만들어서 LLM에 전송한다.
LLM은 추론능력을 발휘해서 자연어와 테이블 이름을 매핑한다.
테이블 이름을 알아냈다면, DDL 정보와 함께 LLM 에게 SQL query를 만들어 줄 것을 요청한다.
자연어로 부터 SQL query를 생성했다면, 데이터베이스 쿼리를 하고 그 결과를 분석/요약해서 사용자에게 응답하면 된다. 이때 query 결과와 함께 컨텍스트를 함께 넘겨야 할 것이다. 프롬프트는 대략 아래의 구성이 될 것이다.
사용자 요청: 자연어
테이블 이름과 테이블에 대한 설명
DDL
쿼리 결과
이 과정을 수작업으로 진행해봤다.
1 단계: 자연어로 부터 테이블 추출하기
Input
You are an assistant chatbot that creates SQL queries. Please refer to the table name in the table information and tell me the table name needed to create the SQL query. Please only tell me the table name.
Please give me a list of products that are priced between 15 and 20.
### Table information
| table name | description |
| ---------- | ------------------------------------------------------ |
| products | 상품가격, 상품 이름등의 정보를 가지고 있습니다. |
| orders | 주문 상품, 주문 잘짜 등의 정보를 가지고 있습니다. |
| customers | 고객이름, 주소, 전화 번호 등의 정보를 가지고 있습니다. |
Output
products
사용자 요청을 처리하기 위해서는 "products table"을 조회해야 된다는 정보를 얻었다.
2 단계: products table DDL 정보로 부터 SQL query 생성
Input
You are an assistant chatbot that creates SQL queries. Please create the following sentences as SQL queries by referring to the products table table below.
Please give me a list of products that are priced between 15 and 20.
### products table
CREATE TABLE `products` (
`ProductID` int(11) NOT NULL AUTO_INCREMENT,
`ProductName` varchar(40) NOT NULL,
`SupplierID` int(11) DEFAULT NULL,
`ReorderLevel` int(11) DEFAULT '0',
`Discontinued` tinyint(1) DEFAULT '0',
PRIMARY KEY (`ProductID`),
KEY `CategoryID` (`CategoryID`),
KEY `ProductName` (`ProductName`),
KEY `SupplierID` (`SupplierID`)
) ENGINE=MyISAM AUTO_INCREMENT=78 DEFAULT CHARSET=utf8;
Output
SELECT * FROM products WHERE UnitPrice BETWEEN 15.0000 AND 20.0000
더 다양하고 복잡한 쿼리로 테스트를 해봐야 겠으나 로컬에서 실행 가능한 경량 LLM인 Llama3.1-8B로 매우 인상적인 결과가 나왔다.
LLM의 성능이 크게 향상되면서, 과거에 복잡한 NLP(Natural Language Processing)기술을 사용해야 했던 작업들이 이제는 더 간단하고 효율적으로 처리할 수 있게 된 것이 사실이다. LLM을 이용하면 단순함, 범용성, 적응성, 빠른 프로토타이핑 속도 등 많은 장점을 가진다. 물론 LLM의 특성상 예측이 부정확하거나 비일관성, 비용 등의 단점 등이 있지만 LLM 그리고 오픈소스 LLM의 성장속도를 본다면 LLM을 이용한 솔루션이 더 큰 장점을 가질 것으로 보인다.
Text2SQL에 대하여
LLM의 주요 사용 사례로 "자연어를 기반으로 하는 데이터 분석"이 늘어나고 있다. 현재 많은 기업들이 RDBMS, 웨어하우스, 데이터 마트를 이용해서 데이터를 분석하여 데이터 기반 의사결정을 위한 시스템을 구축하고 있다.
하지만 데이터에서 필요한 정보/인사이트를 얻기 위해서는 복잡한 과정을 거쳐야 하는데 데이터 기반 의사결정 환경을 만들기 위한 장애물로 작동하고 있다.
기술적 장벽
SQL 지식 필요: 데이터베이스에서 원하는 정보를 추출하려면 SQL 쿼리 작성 능력이 필요하다. 하지만 많은 데이터 분석가, (특히)비즈니스 사용자는 SQL에 익숙하지 않아서 데이터에 대한 접근이 제한된다.
복잡한 쿼리 작성: 복잡한 분석 작업이나 대규모 데이터 세트에서의 집계 연산은 매우 복잡한 SQL 작업을 요구한다. 이를 작성하는 데 많은 시간이 소요되며, 오류 발생 가능성도 높다.
데이터베이스에 대한 이해: 데이터 웨어하우스, 데이터 마트, RDBMS 등에 수십개의 테이블들이 산개되어 있다. 데이터베이스에서 원하는 정보를 추출하려면 이들 테이블의 목적, 사용 방법을 이해하고 있어야 한다.
느린 분석 속도
수동 쿼리 작성: 많은 분석 작업이 시간 소모적이고 비효율적인 수동 쿼리 작업으로 진행된다. 단순한 답을 얻기 위해서도 상당한 시간이 걸릴 수 있다.
반복 작업: 동일하거나 유사한 쿼리를 반복적으로 작성해야 하는 경우가 많아 생산성이 저하된다.
의사소통의 어려움
비기술자와 기술자간의 격차: 비즈니스 조직이 데이터를 요청할 때, 데이터 팀은 이 요구를 SQL 쿼리로 변환해서 실행해야 한다. 요구사항이 잘못 전달되거나 추가적인 설명과 수정이 필요하며, 보통 많은 시간이 소모된다.
결과 해석의 문제: 기술 보고서나 분석 결과를 이해하는데 어려움을 겪는 비기술자들은 데이터를 제대로 활용하지 못하는 경우가 많다.
데이터 접근성 문제
제한된 데이터 접근: 비기술 사용자는 데이터베이스의 접근과 추출이 제한된다. 이로 인해 데이터 의존도가 높아지고 데이터 접근성이 제한된다.
데이터 사일로: 데이터가 여러 조직에 분산되어 있고, 이를 통합하여 분석하는데에는 많은 시간과 어려움이 따른다.
보고서 생성의 어려움: 데이터 분석 결과를 시각화 하고 보고서를 작성하는 과정이 수작업으로 이루어져서 효율성이 떨어진다.
Text2SQL을 이용하면 자연어를 기반으로 데이터 작업을 할 수 있기 때문에 데이터 분석과 레포팅 관련된 문제들을 해결 할 수 있다.
테스트 환경
Ubuntu 24.04
LLM: Llama3.1-8B
MySQL Database
Open-Webui
테스트 데이터베이스 구축
MySQL & SQL 스터디 준비 문서를 참고해서 데이터베이스를 준비하자. Northwind MySQL Sample Database 에서 sql 파일을 다운로드 하고 압축을 푼다.
docker로 mysql을 설치한다.
mysql에 로그인해서 northwind 데이터베이스를 만든다.
다운로드한 sql 파일을 이용해서 데이터셋을 적재한다.
아래 이미지는 데이터셋의 ERD다.

테스트에 사용할 SQL 쿼리 예제는 SQL study with mysql 에서 찾을 수 있다.
Text2SQL 매커니즘
Text2SQL은 자연어를 SQL 쿼리로 변환하는 시스템이다. Llama3.1 로 테스트를 했다.
Input
Output
Here is the SQL query:
Note: This assumes that you have a table named
sales_data
with columns forsales_volume
,country
, andyear
. You may need to modify the query depending on your actual database schema.잘 만들어주기는 하지만 실제 환경에서는 테이블 이름, 필드 이름 그리고 각종 코드 값들을 알고 있어야 한다. 예를 들어 country는 "kr", "South korea", "korea", "82"등이 될 수 있다. 시간 양식도 일치해야 한다.
따라서 반드시 테이블 스키마를 학습 시켜야 한다.
Text2SQL 예제 테스트
📌 예제 Input에 사용하는 DDL은 일부분 생략을 했습니다.
간단한 SELECT
Input
Output
모든 고객의 수를 구하는 SQL 쿼리는 다음과 같습니다:
이 쿼리는
customers
테이블에서 모든 고객의 수를 계산하고, 그 결과를total_customers
라는 별칭으로 반환합니다.테스트
성공
예제: Where 절
Input
Output
Here is the SQL query that responds to "London에 살고 있는 모든 고객의 ID, 고객이름, 전화번호를 알려주세요." which translates to "Tell me the ID, customer name and phone number of all customers living in London":
This query selects the
CustomerID
,ContactName
, andPhone
columns from thecustomers
table where the value in theCity
column is exactly'London'
. The result will be a list of customer information living in London.테스트
성공
Group By
Input
Output
테스트
성공
Join
Northwind 에는 Order(주문)테이블과 Shippers(선적사)테이블을 가지고 있다. 이 두 개의 테이블을 JOIN해서 주문 정보를 조회해 보자. 배송업체별 총 주문 금액을 알려달라고 요청했다.
Input
Output
To get the total order amount by shipper, we can use a SQL query that groups the orders by the ShipVia column (which represents the shipper ID), and then calculates the sum of the Freight column for each group.
This query joins the orders table with the shippers table on the ShipVia and ShipperID columns. Then, it groups the results by the CompanyName of the shipper and calculates the sum of the Freight column for each group, which gives us the total order amount for each shipper.
When you run this query, you should get a result set with two columns: CompanyName and TotalOrderAmount. The CompanyName column will list all the unique company names from the shippers table, and the TotalOrderAmount column will show the sum of the freight costs for each company.
테스트
성공
쿼리는 잘 실행됐다. 검증을 위해서 shippers 목록을 요청했다.
Input
Output
테스트
각 물류 회사의 주문 통계를 요청해보자.
Input
Output
각 물류 회사의 주문 통계를 알려드리겠습니다.
이 쿼리는 각 물류 회사에 대한 총 주문 수, 총 비용, 평균 비용, 최소 비용 및 최대 비용을 표시합니다.
테스트
예제: AND, OR, NOT 연산
categories 테이블에는 제품 분류 정보, products 테이블에는 제품 정보, suppliers 테이블에는 제품제공 회사정보가 저장되어 있다.
미국에 있는 회사 목록을 확인하고 특정 회사가 취급하는 제품목록을 확인해 보자. AND 연산 그리고 JOIN이 들어가는 (나름)복잡한 예제다.
예제가 너무 길어져서 테이블 DDL은 생략했다.
Input
Output
다음과 같은 SQL 쿼리가 판매된 제품에 대한 자세한 정보를 제공합니다:
이 쿼리는
products
테이블을categories
와suppliers
테이블과 연결하여 'Condiments' 카테고리 내의 '그랜드 켈리의 하우스' 회사에서 판매된 제품에 대한 정보를 선택합니다.제품 이름
카테고리 이름
회사의 이름
단위당량
단위가액
재고 수
취소 여부
테스트
성공. 잘 나왔다 직접 테스트해보자.
Having
employees 테이블에는 직원 정보가 들어있다. 직원의 성과 평가를 위해서 10개 이상의 주문을 등록한 직원을 살펴보는 쿼리를 만들어보자.
Input
Output
Here is the SQL query that checks if there are any employees who have processed more than 10 orders:
테스트
성공
Between
가격이 10에서 20 사이의 제품 목록을 가져와보자.
Input
Output
Here is the SQL query that gives you a list of products priced between 15 and 20:
This query selects the
ProductName
andUnitPrice
from theproducts
table where theUnitPrice
is greater than or equal to 15.0000 and less than or equal to 20.0000.Note: As before, the BETWEEN operator includes both the start and end values in its search, so this query will return products with prices exactly equal to 15 or 20. If you want to exclude these products, you can use a greater-than-or-equal-to (>=) and less-than-or-equal-to (<=) combination instead:
테스트
테이블 이름 추출
DDL을 훈련시키는 것으로 복잡한 쿼리까지 만들 수 있음을 확인했다. 여기에서는 수작업으로 테이블 정보를 모델에 넘겼는데, LLM App이 자연어로 부터 테이블 이름을 추출할 수 있도록 하면 될 것이다. 굳이 테이블 이름을 추출하는 과정을 거치지 않고 모든 테이블 정보를 프롬프트로 넘겨도 되겠지만 테이블이 수십/수백개가 넘어가면 프롬프트가 쓸데없이 커지는 문제가 있다.
Input
Output
To find the list of products priced between 15 and 20, I'll need to refer to:
products: This table contains information about the products themselves.
I can help you craft a query that will give you the list of products with prices within this range!
Would you like me to assist with crafting the SQL query?
Text2SQL 아키텍처
Assistant Model
지금 까지의 테스트 내용을 토대로 위 이미지 형태를 가지는 Assistant Model를 제안 할 수 있다.
사용자가 자연어를 입력하면 Assistant는 Database meta data 의 정보를 읽어서 프롬프트를 만들어서 LLM에 전송한다.
LLM은 추론능력을 발휘해서 자연어와 테이블 이름을 매핑한다.
테이블 이름을 알아냈다면, DDL 정보와 함께 LLM 에게 SQL query를 만들어 줄 것을 요청한다.
자연어로 부터 SQL query를 생성했다면, 데이터베이스 쿼리를 하고 그 결과를 분석/요약해서 사용자에게 응답하면 된다. 이때 query 결과와 함께 컨텍스트를 함께 넘겨야 할 것이다. 프롬프트는 대략 아래의 구성이 될 것이다.
사용자 요청: 자연어
테이블 이름과 테이블에 대한 설명
DDL
쿼리 결과
이 과정을 수작업으로 진행해봤다.
1 단계: 자연어로 부터 테이블 추출하기
Input
Output
사용자 요청을 처리하기 위해서는 "products table"을 조회해야 된다는 정보를 얻었다.
2 단계: products table DDL 정보로 부터 SQL query 생성
Input
Output
이제 이 Query를 실행하고 LLM에게 요약 해달라고 요청하면 된다.
3 단계: Query 실행 결과 요약
Input
Output

정리
더 다양하고 복잡한 쿼리로 테스트를 해봐야 겠으나 로컬에서 실행 가능한 경량 LLM인 Llama3.1-8B로 매우 인상적인 결과가 나왔다.
LLM의 성능이 크게 향상되면서, 과거에 복잡한 NLP(Natural Language Processing)기술을 사용해야 했던 작업들이 이제는 더 간단하고 효율적으로 처리할 수 있게 된 것이 사실이다. LLM을 이용하면 단순함, 범용성, 적응성, 빠른 프로토타이핑 속도 등 많은 장점을 가진다. 물론 LLM의 특성상 예측이 부정확하거나 비일관성, 비용 등의 단점 등이 있지만 LLM 그리고 오픈소스 LLM의 성장속도를 본다면 LLM을 이용한 솔루션이 더 큰 장점을 가질 것으로 보인다.
Recent Posts
Archive Posts
Tags