MySQL Workbench 8.0 CE

MySQL Workbench 8.0 CE는 MySQL 데이터베이스를 시각적으로 관리하고 데이터베이스 개발 및 관리 작업을 수행하는 오픈 소스의 통합 개발 환경(IDE)이다. "CE"는 Community Edition을 의미하며, 무료로 사용할 수 있는 버전이다.

 

 

주요 기능과 특징
  • 시각적 데이터베이스 설계 : MySQL Workbench는 시각적으로 데이터베이스를 설계하고 모델링할 수 있는 기능을 제공한다. 테이블, 관계, 인덱스 등을 그래픽 인터페이스를 통해 설계하고 수정할 수 있다.
  • 쿼리 에디터 : SQL 쿼리를 작성하고 실행할 수 있는 쿼리 에디터를 제공한다. 쿼리 결과를 테이블 형식으로 출력하며, 실행 계획과 성능 통계 정보를 확인할 수 있다.
  • 서버 관리 : MySQL 서버에 접속하여 데이터베이스와 사용자 계정을 관리할 수 있다. 데이터베이스의 백업과 복원도 가능하다.
  • 스키마 동기화 : 개발 환경과 운영 환경의 데이터베이스 스키마를 비교하여 동기화할 수 있다. 변경 사항을 스크립트로 생성하거나 직접 적용할 수 있다.

 

 

설치

google에서 mysql download를 검색해서 해당 웹에 접속하고 빨간 네모를 클릭

 

 

클릭

 

 

클릭

 

 

Full로 테스트

 

 

root의 비밀번호는 설정

 

 

비밀번호 쓰고 Check

 

 

실행화면

 

 

사용화면

번개표시는 SQL문을 실행하고, 화살표는 적용된 SQL문을 반영하여 새로고침한다

 

 

GUI로도 가능

 

 

우하단 Apply를 클릭하면 적용

 

 

DB 제거가 간단하다

 

 

테이블 생성이 간단

 

 

구문으로 데이터값 입력 가능

 

 

조회도 간단

 

 

속성 변경도 직관적으로!

 

 

뷰 생성도 가능

 

 

뷰 조회도 간단

 

 

유저에 대한 기능도 GUI로 가능

 

 

connection 생성 후 user1로 접속 가능

 

 

일반유저에게 권한을 주면 조회도 가능

 

 

windows cmd 창에서 mySQL의 실행

'C:\Program Files\MySQL\MySQL Server 8.0\bin'에서 cmd 실행

 

 

명령어 입력하면 접속!

 

'SQL' 카테고리의 다른 글

SQL 총연습  (0) 2023.08.03
SQL 기타  (0) 2023.08.02
JOIN  (0) 2023.08.02
SQL 연습  (0) 2023.08.02
SQL 기본  (0) 2023.08.01

https://www.w3schools.com/mysql/trymysql.asp?filename=trysql_select_all

위 링크에서 SQL문 총연습을 했다.
 

https://dev.mysql.com/doc/refman/8.0/en/string-functions.html

더 많은 문자열 함수를 참고할 수 있는 웹페이지이다.

 

각 유형에 대해 여러 SQL문을 직접 실행했다. 궁금한 것은 chat gpt의 도움을 받기도 했다. 간단한 문제가 중간마다 있는데 답은  한 줄 띄고 바로 밑에 적어봤다.

패딩
SELECT
LPAD('ABC', 5, '-'),
RPAD('ABC', 5, '-');
Products 테이블에서 SupplierIDPrice의 값이 다음과 같은 단위로 출력되도록 하세요
SELECT LPAD(SupplierID,3,'0') as SupplierID, Price from Products;
치환
SELECT REPLACE('맥도날드에서 맥도날드 햄버거를 먹었다.', '맥도날드', '버거킹');
SELECT
REPLACE(Description, ', ', ' and ')
FROM Categories;
콤마를 and로 변경하려고 했는데, and and가 되었다. 이를 해결하시오


SELECT
REPLACE(REPLACE(Description,', and',','),',',' and ')
FROM Categories;


SELECT
REPLACE(REPLACE(Description, ', ', ' and '),'and and',' and ')
FROM Categories;

위치검색
INSTR(S, s) Ss의 첫 위치 반환, 없을 시 0
SELECT
INSTR('ABCDE', 'ABC'),
INSTR('ABCDE', 'BCDE'),
INSTR('ABCDE', 'C'),
INSTR('ABCDE', 'DE'),
INSTR('ABCDE', 'F');
Customers 테이블에서 CustomerNamefirst name5글자 이하인 사람의 이름을 출력하시오
hint. first name' ' full name의 첫 스페이스 앞에 있다


SELECT CustomerName FROM Customers where INSTR(CustomerName,' ') between 1 and 6;
자료형 변환
CAST(A AS T) AT 자료형으로 변환 CONVERT(A, T) AT 자료형으로 변환
SELECT
'01' = '1',
CAST('01' AS DECIMAL) = CAST('1' AS DECIMAL);
SELECT
'01' = '1',
CONVERT('01', DECIMAL) = CONVERT('1', DECIMAL);
시간 관련 함수
CURRENT_DATE, CURDATE 현재 날짜 반환
CURRENT_TIME, CURTIME 현재 시간 반환
CURRENT_TIMESTAMP, NOW 현재 시간과 날짜 반환
SELECT CURDATE(), CURTIME(), NOW();
문자열에 따른 시간 생성 함수
DATE 문자열에 따라 날짜 생성
TIME 문자열에 따라 시간 생성
SELECT
'2021-6-1' = '2021-06-01',
DATE('2021-6-1') = DATE('2021-06-01'),
'1:2:3' = '01:02:03',
TIME('1:2:3') = TIME('01:02:03');
SELECT
'2021-6-1 1:2:3' = '2021-06-01 01:02:03',
DATE('2021-6-1 1:2:3') = DATE('2021-06-01 01:02:03'),
TIME('2021-6-1 1:2:3') = TIME('2021-06-01 01:02:03'),
DATE('2021-6-1 1:2:3') = TIME('2021-06-01 01:02:03'),
DATE('2021-6-1') = DATE('2021-06-01 01:02:03'),
TIME('2021-6-1 1:2:3') = TIME('01:02:03');
Orders 테이블에서 OrderDate1997-1-1에서 1997-1-31 사이의 데이터를 가져오시오


SELECT * FROM Orders where OrderDate between DATE('1997-1-1') and DATE('1997-1-31');
시간 반환 함수
YEAR 주어진 DATETIME값의 년도 반환
MONTHNAME 주어진 DATETIME값의 월(영문) 반환
MONTH 주어진 DATETIME값의 월 반환
WEEKDAY 주어진 DATETIME값의 요일값 반환(월요일: 0) 숫자로 반환
DAYNAME 주어진 DATETIME값의 요일명 반환
DAYOFMONTH, DAY 주어진 DATETIME값의 날짜() 반환
SELECT OrderDate, YEAR(OrderDate) AS YEAR, MONTHNAME(OrderDate) AS MONTHNAME, MONTH(OrderDate) AS MONTH, WEEKDAY(OrderDate) AS WEEKDAY, DAYNAME(OrderDate) AS DAYNAME, DAY(OrderDate) AS DAY FROM Orders;
SELECT OrderDate, CONCAT(CONCAT_WS('/', YEAR(OrderDate), MONTH(OrderDate), DAY(OrderDate)),
' ', UPPER(LEFT(DAYNAME(OrderDate), 3))) FROM Orders;
Orders 테이블에서 월요일만 추출해보세요 [hint OrderDate0 이면 월요일]


SELECT * FROM Orders where WEEKDAY(OrderDate)=0;
시분초 반환 함수
HOUR 주어진 DATETIME의 시 반환
MINUTE 주어진 DATETIME의 분 반환
SECOND 주어진 DATETIME의 초 반환
SELECT
HOUR(NOW()), MINUTE(NOW()), SECOND(NOW());
날짜 연산 함수
ADDDATE, DATE_ADD 시간/날짜 더하기
SUBDATE, DATE_SUB 시간/날짜 빼기
SELECT
ADDDATE('2021-06-20', INTERVAL 1 YEAR),
ADDDATE('2021-06-20', INTERVAL -2 MONTH),
ADDDATE('2021-06-20', INTERVAL 3 WEEK),
ADDDATE('2021-06-20', INTERVAL -4 DAY),
ADDDATE('2021-06-20', INTERVAL -5 MINUTE), -
ADDDATE('2021-06-20 13:01:12', INTERVAL 6 SECOND);
Orders 테이블의 OrderDate에 있는 날짜를 위에서 제시된 조건에 맞춰 출력하시오


SELECT
ADDDATE(OrderDate, INTERVAL 1 YEAR),
ADDDATE(OrderDate, INTERVAL -2 MONTH),
ADDDATE(OrderDate, INTERVAL 3 WEEK),
ADDDATE(OrderDate, INTERVAL -4 DAY),
ADDDATE(OrderDate, INTERVAL -5 MINUTE),
ADDDATE(OrderDate, INTERVAL 6 SECOND)
FROM Orders;
시간차 계산 함수
DATEDIFF 두 시간/날짜 간 일수차
TIMEDIFF 두 시간/날짜 간 시간차
SELECT
OrderDate,
NOW(),
DATEDIFF(OrderDate, NOW())
FROM Orders;
SELECT
TIMEDIFF('2021-06-21 15:20:35', '2021-06-21 16:34:41');
Orders 테이블에서 OrderDate19961010일을 기준으로 5일 미만 차이가 나는 날짜를 출력하시오


SELECT OrderDate FROM Orders where ABS(DATEDIFF('1996-10-10',OrderDate))<5;
마지막 날짜 계산 함수
LAST_DAY 해당 달의 마지막 날짜
SELECT
OrderDate,
LAST_DAY(OrderDate),
DAY(LAST_DAY(OrderDate)),
DATEDIFF(LAST_DAY(OrderDate), OrderDate)
FROM Orders;
시간 포맷 함수
DATE_FORMAT 시간/날짜를 지정한 형식으로 반환
%Y 년도 4자리
%y 년도 2자리 -> 끝의 2자리만 표시
%M 월 영문
%m 월 숫자
%D 일 영문(1st, 2nd, 3rd...)
%d, %e 일 숫자 (01 ~ 31)
%T hh:mm:ss
%r hh:mm:ss AM/PM
%H, %k (~23)
%h, %l (~12)
%i
%S, %s
%p AM/PM
SELECT
DATE_FORMAT(NOW(), '%M %D, %Y %T'),
DATE_FORMAT(NOW(), '%y-%m-%d %h:%i:%s %p'),
DATE_FORMAT(NOW(), '%Y%m%d%p %h%i%s');
현재 시간을 YmdAM/PM his초로 출력하시오
위에서 출력한 날짜에서 AM은 오전으로 PM은 오후로 자동 변경되어 출력되게 하시오 [hint replace함수]


SELECT DATE_FORMAT(NOW(), '%Y%m%d%p %h%i%s');
SELECT REPLACE(REPLACE(DATE_FORMAT(NOW(), '%Y%m%d%p %h%i%s'),'AM','오전'),'PM','오후');
진위함수
IF(조건, T, F) 조건이 참이라면 T, 거짓이면 F 반환
SELECT IF (1 > 2, '12보다 크다.', '12보다 작다.');
SELECT
CASE
WHEN -1 > 0 THEN '-1은 양수다.'
WHEN -1 = 0 THEN '-10이다.'
ELSE '-1은 음수다.'
END;
Products 테이블에서 Price30보다 크면 Expensive 나머지는 Cheap으로 출력하는 열을 따로 만들어서
Price20 미만이면 저가, 2030 사이이면 일반, 그 외는 고가로 출력하시오


SELECT
Price,
IF (Price>30, 'Expensive', 'Cheap') as '비교',
CASE
WHEN Price < 20 THEN '저가'
WHEN Price between 20 and 30 THEN '일반'
ELSE '고가'
END AS '분류'
FROM Products;
NULL 관련 함수
IFNULL(A, B) ANULL일 시 B 출력
SELECT
IFNULL('A', 'B'),
IFNULL(NULL, 'B');
집계함수: null값은 집계하지 않는다
MAX 가장 큰 값
MIN 가장 작은 값
COUNT 갯수 (NULL값 제외)
SUM 총합
AVG 평균 값
select Country from Customers group by Country;
SELECT CategoryID FROM Products GROUP BY CategoryID;
SELECT Country, City, CONCAT_WS(', ', City, Country) FROM Customers GROUP BY Country, City;
Orders 테이블에서 group byOrderDate를 묶은 다음, 동일 OrderDate의 갯수를 출력하시오.


SELECT COUNT(*), OrderDate
FROM Orders
group by OrderDate;
SELECT
ProductID,
SUM(Quantity) AS QuantitySum
FROM OrderDetails
GROUP BY ProductID
ORDER BY QuantitySum DESC;
SELECT
CategoryID,
MAX(Price) AS MaxPrice,
MIN(Price) AS MinPrice,
TRUNCATE((MAX(Price) + MIN(Price)) / 2, 2) AS MedianPrice,
TRUNCATE(AVG(Price), 2) AS AveragePrice
FROM Products
GROUP BY CategoryID;
Customers 테이블에서 CountryCity를 콤마(,)로 묶고 CustomersID 수를 적으세요
hint] count 함수


SELECT CONCAT_WS(',',Country,City) as Location,COUNT(CustomerID) as Numbers FROM Customers group by Location;
ROLLUP
SELECT Country, COUNT(*) FROM Suppliers GROUP BY Country WITH ROLLUP;
SELECT
CategoryID,
MAX(Price) AS MaxPrice,
MIN(Price) AS MinPrice,
TRUNCATE((MAX(Price) + MIN(Price)) / 2, 2) AS MedianPrice,
TRUNCATE(AVG(Price), 2) AS AveragePrice
FROM Products
GROUP BY CategoryID
with rollup;
위에서 출력했던 쿼리문 맨 뒤에
with rollup; 을 추가하면
각 항목의 총합을 알 수 있다
HAVING
HAVING - 그룹화된 데이터 걸러내기
SELECT Country, COUNT(*) AS Count FROM Suppliers GROUP BY Country HAVING Count >= 3;
SELECT
COUNT(*) AS Count, OrderDate
FROM Orders
WHERE OrderDate > DATE('1996-12-31')
GROUP BY OrderDate
HAVING Count > 2;
WHERE는 그룹하기 전 데이터, HAVING은 그룹 후 집계에 사용한다.
SELECT CategoryID,MAX(Price) as MaxPrice,Min(Price) as MinPrice,truncate((MAX(Price)+Min(Price))/2,2) as MedianPrice, truncate(avg(Price),2) as AveragePrice FROM Products group by CategoryID HAVING CategoryID in (4,5,8);
Products 테이블에서 CategoryID를 가져오는데, MaxPrice이름으로 Price 최대값과 MinPrice이름으로 Price최소값을 가져오고, MedianPrice이름으로 중간값을 계산해서 가져오고, AveragePrice이름으로 평균값 계산하기
이때, CategoryID2보다 큰 값이고, AveragePrice 값은 2030사이인 것을 출력


SELECT CategoryID,MAX(Price) as MaxPrice,Min(Price) as MinPrice,truncate((MAX(Price)+Min(Price))/2,2) as MedianPrice, truncate(avg(Price),2) as AveragePrice FROM Products group by CategoryID HAVING CategoryID>2 and AveragePrice between 20 and 30;
DISTINCT
DISTINCT - 중복된 값들을 제거합니다. select 문에서 사용한다.
SELECT DISTINCT CategoryID
FROM Products;
SELECT DISTINCT Country FROM Customers ORDER BY Country;
SELECT DISTINCT Country, City FROM Customers ORDER BY Country;
Customers 테이블에서 Country를 가져오는데, County마다 겹치지 않는 도시는 몇 개인지 출력하기
출력 시 Country기준으로 알파벳 정렬


SELECT Country,COUNT(DISTINCT City) as CityNum FROM Customers GROUP BY Country order by Country;
서브쿼리
SELECT
CategoryID, CategoryName, Description,
(SELECT ProductName FROM Products WHERE ProductID = 1)
FROM Categories;
SELECT * FROM Products
WHERE Price < (SELECT AVG(Price) FROM Products);
Categories 테이블에서 CategoryID, CategoryName, Description을 가져온다
이때 (가져올때 조건, 서브쿼리 내용은)
Products 테이블에서 Price50 초과인 CategoryID중에서 CategoryID를 가져온다
[CategoryIDPrice50 초과인 것들 중에서 가져온다. hint : IN 함수 ~중에서 가져오기]


SELECT CategoryID,CategoryName,Description FROM Categories WHERE CategoryID in (select CategoryID from Products where Price>50);
서브쿼리 조건
~ ALL 서브쿼리의 모든 결과에 대해 ~하다
~ ANY 서브쿼리의 하나 이상의 결과에 대해 ~하다
SELECT * FROM Products WHERE Price > ALL (SELECT Price FROM Products WHERE CategoryID = 2);
Categories 테이블에서 CategoryID, CategoryName, Description을 가져오는데
서브쿼리 내용 : CategoryIDProducts 테이블에서 Price50 초과인 CategorytID에 해당되는
[hint : any 하나 이상에 해당된다 = 어떤 값에 해당된다 = ..중에 하나에 해당된다]
여기에서는 IN을 사용해도 결과는 동일하다


SELECT CategoryID,CategoryName,Description FROM Categories where CategoryID=any(select CategoryID from Products where Price>50);
상관 서브쿼리
SELECT ProductID, ProductName, (SELECT CategoryName FROM Categories C WHERE C.CategoryID = P.CategoryID) AS CategoryName FROM Products P;
SELECT SupplierName, Country, City,
(SELECT COUNT(*) FROM Customers C WHERE C.Country = S.Country)
AS CustomersInTheCountry,
(SELECT COUNT(*) FROM Customers C WHERE C.Country = S.Country AND C.City = S.City)
AS CustomersInTheCity
FROM Suppliers S;
Categories 테이블에서 CategoryIDCategoryName을 가져온다
서브쿼리1. Products 테이블의 CategoryIDCategories 테이블의 CategoryID가 같은 Produects 테이블에서의 최대(MAX) PriceMaximumPrice 라는 이름으로 출력
서브쿼리2. Products 테이블의 CategoryIDCategories 테이블의 CategoryID가 같은 Produects 테이블에서의 평균(AVG) PriceAveragePrice 라는 이름으로 출력


SELECT CategoryID,CategoryName,
(select MAX(Price) from Products P where P.CategoryID=C.CategoryID) as MaximumPrice,
(select AVG(Price) from Products P where P.CategoryID=C.CategoryID) as AveragePrice
FROM Categories C;
조인
JOIN(INNER JOIN) - 내부 조인
관계형 데이터베이스는 데이터의 중복을 피하기 위해서 테이블을 나눈다.
join은 나눠진 테이블들에서 정보를 가져오는 작업
- 조인은 두 개의 테이블을 서로 묶어서 하나의 결과를 만들어 내는 것을 말한다.
- INNER JOIN(내부 조인)은 두 테이블을 조인할 때, 두 테이블에 모두 지정한 열의 데이터가 있어야 한다.
- OUTER JOIN(외부 조인)은 두 테이블을 조인할 때, 1개의 테이블에만 데이터가 있어도 결과가 나온다.
- CROSS JOIN(상호 조인)은 한쪽 테이블의 모든 행과 다른 쪽 테이블의 모든 행을 조인하는 기능이다.
- SELF JOIN(자체 조인)은 자신이 자신과 조인한다는 의미로, 1개의 테이블을 사용한다.
SELECT * FROM Categories C JOIN Products P ON C.CategoryID = P.CategoryID;
그냥 join이라고 쓰면 내부조인인 된다
SELECT C.CategoryID, C.CategoryName, P.ProductName FROM Categories C
JOIN Products P ON C.CategoryID = P.CategoryID;
Products 테이블과 Suppliers 테이블을 JOIN,
Products테이블의 SupplierIDSuppliers테이블의 SupplierID가 같고
Products테이블에서 ProductName을 가져오고, Suppliers테이블에서 SupplierName을 가져와서 ‘by'로 연결하고
컬럼이름은 Product로 한다.
Suppliers테이블에서 Phone을 가져오고, Products테이블에서 Price를 가져온다
Price50초과를 가져오고, ProductName으로 order by 한다 [order by default값은 asc 오름차순]


SELECT CONCAT(P.ProductName,'by',S.SupplierName) as Product, S.Phone, P.Price FROM Products P Join Suppliers S on P.SupplierID=S.SupplierID where P.Price>50 order by P.ProductName;
2개가 아닌 여러 테이블 join하기
SELECT C.CategoryID, C.CategoryName, P.ProductName, O.OrderDate, D.Quantity
FROM Categories C
JOIN Products P ON C.CategoryID = P.CategoryID
JOIN OrderDetails D ON P.ProductID = D.ProductID
JOIN Orders O ON O.OrderID = D.OrderID;
조인 후 그룹핑하기
SELECT C.CategoryID, C.CategoryName, MIN(O.OrderDate) AS FirstOrder, MAX(O.OrderDate) AS LastOrder, SUM(D.Quantity) AS TotalQuantity FROM Categories C
JOIN Products P ON C.CategoryID = P.CategoryID
JOIN OrderDetails D ON P.ProductID = D.ProductID
JOIN Orders O ON O.OrderID = D.OrderID
GROUP BY C.CategoryID;
SELECT C.CategoryID, P.ProductID, C.CategoryName, MIN(O.OrderDate) AS FirstOrder, MAX(O.OrderDate) AS LastOrder, SUM(D.Quantity) AS TotalQuantity FROM Categories C
JOIN Products P ON C.CategoryID = P.CategoryID
JOIN OrderDetails D ON P.ProductID = D.ProductID
JOIN Orders O ON O.OrderID = D.OrderID
GROUP BY C.CategoryID, P.ProductID;
self Join 같은 테이블끼리 조인하기
SELECT
E1.EmployeeID, CONCAT_WS(' ', E1.FirstName, E1.LastName) AS Employee,
E2.EmployeeID, CONCAT_WS(' ', E2.FirstName, E2.LastName) AS NextEmployee
FROM Employees E1 JOIN Employees E2 ON E1.EmployeeID + 1 = E2.EmployeeID;
LEFT/RIGHT OUTER JOIN - 외부 조인 [둘 중에 한쪽에만 있어도 가져오는 조인]
SELECT
E1.EmployeeID, CONCAT_WS(' ', E1.FirstName, E1.LastName) AS Employee,
ifnull(E2.EmployeeID,'N'), CONCAT_WS(' ', E2.FirstName, E2.LastName) AS NextEmployee
FROM Employees E1
LEFT JOIN Employees E2 ON E1.EmployeeID + 1 = E2.EmployeeID ORDER BY E1.EmployeeID;
Customers 테이블에 Suppliers 테이블을 조인하라
조인조건: Customers.City=Suppliers.City and Customers.Country=Suppliers.Country
출력되는 컬럼명
Customers테이블의 CustomerName, City, Country
Suppliers 테이블의 SupplierName
Customers 테이블에는 있는데 Suppliers 테이블에는 없어도 출력시켜라 -> left or right join


SELECT C.CustomerName,S.SupplierName,C.City,C.Country FROM Customers C Left join Suppliers S on C.City=S.city and C.Country=S.Country;
반대로 Suppliers 테이블에는 있는데 Customers테이블에는 없어도 출력시켜라 -> left or right join


SELECT C.CustomerName,S.SupplierName,C.City,C.Country FROM Customers C Right join Suppliers S on C.City=S.city and C.Country=S.Country;
위의 쿼리문에서 left join이나 right join을 할 때
CustomerName이 없는 경우에는 No Customer 라고 출력되고,
SupplierName이 없는 경우에는 No Supplier 가 출력되도록 하라


SELECT ifnull(C.CustomerName,'--NO CUSTOMER--') as CustomerName,S.SupplierName,C.City,C.Country FROM Customers C Right join Suppliers S on C.City=S.city and C.Country=S.Country;


SELECT C.CustomerName,ifnull(S.SupplierName,'--NO SUPPLIER--') as SupplierName,C.City,C.Country FROM Customers C Left join Suppliers S on C.City=S.city and C.Country=S.Country;
CROSS JOIN - 교차 조인 : 조건 없이 모든 조합 반환(A * B)
join을 할 때 on으로 조건을 붙이지 않고, 모든 조합을 하는 경우. A테이블의 행수*B테이블의 행수
SELECT E1.LastName, E2.FirstName FROM Employees E1
CROSS JOIN Employees E2 ORDER BY E1.EmployeeID;
Orders 테이블과 OrderDetails 테이블을 CROSS JOIN하라
Orders 테이블의 CustomerIDOrderDetails 테이블의 ProductID를 가져와라
Orders 테이블의 OrderIDorder by 하라


SELECT O.CustomerID,D.ProductID FROM Orders O CROSS JOIN OrderDetails D order by O.OrderID;
UNION 중복을 제거한 집합
UNION ALL 중복을 제거하지 않은 집합
SELECT CustomerName AS Name, 'CUSTOMER' FROM Customers
UNION
SELECT SupplierName AS Name, 'SUPPLIER' FROM Suppliers
ORDER BY Name;
SELECT CustomerName AS NAME,City,Country,'CUSTOMER' FROM Customers
UNION
SELECT SupplierName AS NAME,City,Country,'SUPPLIER' FROM Suppliers
ORDER BY NAME;
 

많은 시간이 걸렸지만 다양한 예제를 접할수록 안목이 깊어지는 것 같다. 좀 더 힘내보자.

'SQL' 카테고리의 다른 글

MySQL Workbench 8.0 CE  (0) 2023.08.04
SQL 기타  (0) 2023.08.02
JOIN  (0) 2023.08.02
SQL 연습  (0) 2023.08.02
SQL 기본  (0) 2023.08.01

https://www.w3schools.com/mysql/trymysql.asp?filename=trysql_select_all

위 링크에서 그 밖의 SQL문을 알아보자.
수학 연산식과 여러 가지 함수들이 잔뜩 있는 SQL문을 아래와 같이 정리하였다.
복사 붙여넣기를 통해 각 함수들과 연산이 어떻게 적용되는지 직관적으로 파악하면
앞으로 SQL문을 다룰 때 무리 없을 것이라 예상된다.
 

https://dev.mysql.com/doc/refman/8.0/en/numeric-functions.html

위 링크에서 여러 가지함수에 대한 설명들이 적혀있으니 참고해도 좋다.
 

 

연습
사칙연산
SELECT 1 + 2;
SELECT 10 % 3;
SELECT 5 - 2.5 AS DIFFERENCE;
SELECT 3 * (2 + 4) / 2, 'Hello';
SELECT 3 * (2 + 4) / 2 as number, 'Hello' as Test;
SELECT 'ABC' + 3;
SELECT 'ABC' * 3;
SELECT '1' + '002' * 3;
SELECT OrderID + ProductID FROM OrderDetails;
SELECT OrderID, ProductID, OrderID + ProductID AS SUM FROM OrderDetails;
SELECT ProductName, Price / 2 AS HalfPrice FROM Products;
SELECT ProductName, Price, Price / 2 AS HalfPrice FROM Products;
SELECT ProductName, Price, Price / 2 AS HalfPrice, Price * 2 AS doubleprice FROM Products;
SELECT ProductName, Price, Price / 2 AS HalfPrice, Price * 2 AS doubleprice, Price * 0.75 AS SalePrice FROM Products;
, 거짓
SELECT TRUE, FALSE;
SELECT !TRUE, NOT 1, !FALSE, NOT FALSE;
SELECT 0 = TRUE, 1 = TRUE, 0 = FALSE, 1 = FALSE;
SELECT * FROM Customers WHERE TRUE;
SELECT * FROM Customers WHERE FALSE;
select * from Customers where City = 'Berlin';
SELECT TRUE IS TRUE;
SELECT TRUE IS NOT FALSE;
SELECT (TRUE IS FALSE) IS NOT TRUE;
사전식 배열
SELECT 5 BETWEEN 1 AND 10;
SELECT 'banana' not BETWEEN 'Apple' AND 'camera';
SELECT * FROM OrderDetails WHERE ProductID BETWEEN 1 AND 4;
SELECT * FROM Customers WHERE CustomerName BETWEEN 'b' AND 'c';
SELECT * FROM Customers WHERE CustomerName BETWEEN 'B' AND 'C';
멤버 연산
SELECT 1 + 2 IN (2, 3, 4);
SELECT 'Hello' IN (1, TRUE, 'hello');
SELECT * FROM Customers WHERE City IN ('Torino', 'Paris', 'Portland', 'Madrid')
검색
SELECT
'HELLO' LIKE 'hel%',
'HELLO' LIKE 'H%',
'HELLO' LIKE 'H%O',
'HELLO' LIKE '%O',
'HELLO' LIKE '%HELLO%',
'HELLO' LIKE '%H',
'HELLO' LIKE 'L%'
SELECT
'HELLO' LIKE 'HEL__',
'HELLO' LIKE 'h___O',
'HELLO' LIKE 'HE_LO',
'HELLO' LIKE '_____',
'HELLO' LIKE '_HELLO',
'HELLO' LIKE 'HEL_',
'HELLO' LIKE 'H_O'
SELECT * FROM Employees WHERE Notes LIKE '%economics%'
수학적 표현
SELECT ROUND(0.5), CEIL(0.4), FLOOR(0.6); 반올림, 올림, 내림 ceiling
SELECT Price, ROUND(price), CEIL(price), FLOOR(price) FROM Products;
SELECT ABS(1), ABS(-1), ABS(3 - 10);
SELECT * FROM OrderDetails WHERE ABS(Quantity - 10) < 5;
SELECT GREATEST(1, 2, 3), LEAST(1, 2, 3, 4, 5);
SELECT OrderDetailID, ProductID, Quantity, GREATEST(OrderDetailID, ProductID, Quantity) FROM OrderDetails;
select LEAST(OrderDetailID, ProductID, Quantity) FROM OrderDetails;
SELECT OrderDetailID, ProductID, Quantity, GREATEST(OrderDetailID, ProductID, Quantity), LEAST(OrderDetailID, ProductID, Quantity) FROM OrderDetails;
SELECT MAX(Quantity), MIN(Quantity), COUNT(Quantity), SUM(Quantity), AVG(Quantity)
FROM OrderDetails;
SELECT MAX(Quantity), MIN(Quantity), COUNT(Quantity), SUM(Quantity), AVG(Quantity)
FROM OrderDetails WHERE OrderDetailID BETWEEN 20 AND 30;
select pow(2,3), power(5,2), sqrt(16);
SELECT Price, pow(Price, 1/2) FROM Products where sqrt(Price)<4;
잘라내기
select truncate(1234.5678,1), truncate(1234.5678,2), truncate(1234.5678,3), truncate(1234.5678,-1), truncate(1234.5678,-2), truncate(1234.5678,-3);
select ProductID,Price from Products where truncate(Price, 0) = 12;
대소문자
SELECT UPPER('abcDEF'), LOWER('abcDEF');
SELECT UCASE(CustomerName), LCASE(ContactName) FROM Customers;
연접함수
SELECT CONCAT('HELLO', ' ', 'THIS IS ', 2023)
SELECT CONCAT_WS('-', 2021, 8, 15, 'AM')
SELECT CONCAT('O-ID: ', OrderID) FROM Orders;
Employees 테이블에서 fullname이라는 컬럼으로 first namelast name을 사이 한칸 띄우고 출력하시오
ex) Nancy Davolio


SELECT concat(firstname,' ',lastname) as fullname from Employees;
select CONCAT_WS(' ',firstname,lastname) as fullname from Employees;
슬라이싱
SELECT
SUBSTR('ABCDEFG', 3),
SUBSTR('ABCDEFG', 3, 2),
SUBSTR('ABCDEFG', -4),
SUBSTR('ABCDEFG', -4, 2);
SELECT
LEFT('ABCDEFG', 3),
RIGHT('ABCDEFG', 3);
SELECT Orderdate,substr(Orderdate,1,4) as Year,substr(Orderdate,6,2) as Month,substr(Orderdate,9,2) as Day FROM Orders;
길이함수
SELECT
LENGTH('ABCDE'),
CHAR_LENGTH('ABCDE'),
CHARACTER_LENGTH('ABCDE');
-- w3wchool 사이트에서는 한글이 제대로 동작하지 않는다
SELECT
LENGTH('안녕하세요'), -- 15
CHAR_LENGTH('안녕하세요'), -- 5
CHARACTER_LENGTH('안녕하세요'); -- 5
공백 제거 함수
SELECT CONCAT('|', ' HELLO ', '|'), CONCAT('|', LTRIM(' HELLO '), '|'), CONCAT('|', RTRIM(' HELLO '), '|'), CONCAT('|', TRIM(' HELLO '), '|');
trim 양쪽 공백 제거, ltrim 왼쪽 공백 제거, rtrim 오른쪽 공백 제거
사용자가 CategoryName 테이블에서 Beverages를 검색을 할 때, 앞뒤에 스페이스를 주고 검색을 하면, 내용이 출력되지 않는다. 예를 들어 앞에 한칸 띄우고 ' Beverages'로 검색하거나 앞뒤로 한칸씩 띄우고 검색하면 ‘ Beverages '
사용자가 앞뒤 빈공간을 두고 [스페이스를 두고] 검색하더라도 원하는 Beverages 결과가 출력되도록 하시오


SELECT * FROM Categories where CategoryName=trim(' Beverages ');

 

모두 테스트 해본 결과 열의 검색에는 대소문자 구분이 없었지만, 데이터 값에는 대소문자 구분이 있었다.

많은 함수들이 있지만 파이썬에서 겹치는 것도 있고 여러번 사용하면 자연스럽게 익혀지니 너무 부담은 가지지 말자.

'SQL' 카테고리의 다른 글

MySQL Workbench 8.0 CE  (0) 2023.08.04
SQL 총연습  (0) 2023.08.03
JOIN  (0) 2023.08.02
SQL 연습  (0) 2023.08.02
SQL 기본  (0) 2023.08.01

JOIN은 두 테이블을 합칠 때 사용한다.

네 가지 유형이며 아래와 같이 형식을 나타낼 수 있다.

 

INNER JOIN 형식
SELECT <열 목록>
FROM <첫 번째 테이블>
    INNER JOIN <두 번째 테이블>
    ON <조인 조건>
[WHERE 검색 조건]

두 테이블을 조인할 때, 두 테이블에 공통의 열이 있어야 한다.

 

 

OUTER JOIN
SELECT <열 목록>
FROM <첫 번째 테이블(LEFT 테이블)>
    <LEFT | RIGHT | FULL> OUTER JOIN <두 번째 테이블(RIGHT 테이블)>
     ON <조인 조건>
[WHERE 검색 조건]

두 테이블을 조인할 때, 1개의 테이블에만 데이터가 있어도 결과가 나온다. 집합으로 볼 때 차집합과 같은 결과가 나오는데이때 left 조인은 왼쪽 테이블의 데이터를 기준으로 하고, right 조인은 오른쪽 테이블의 데이터를 기준으로 한다. full은 대칭 차집합과 같이 데이터를 추출된다. 참고로 데이터 값이 없을 때는 null로 표기된다.

 

 

CROSS JOIN
SELECT *
FROM <첫 번째 테이블>
    CROSS JOIN <두 번째 테이블>

한쪽 테이블의 모든 행과 다른 쪽 테이블의 모든 행을 하나씩 모두 조합하여 출력한다.

 

 

SELF JOIN
SELECT <열 목록>
FROM <테이블> 별칭A
    INNER JOIN <테이블> 별칭B
[WHERE 검색 조건]

자신이 자신과 조인한다는 의미로, 1개의 테이블을 사용한다.

 

 

 

아래와 같이 연습을 해보았다.

연습은 아래 링크에 들어가 저장되 있는 DB를 사용하였다.

 
 
연습
Customers테이블과 Orders테이블을 Inner join해서 추출하고, 이 중에 국적이 Mexico인 고객 정보만 출력하시오


SELECT *
FROM Customers c
INNER JOIN Orders o ON c.CustomerID=o.CustomerID
WHERE c.Country='Mexico';
orders 테이블과 orderDetails 테이블을 inner join하고 Quantitiy50개 이상인 row만 오름차순으로 추출하시오


SELECT * FROM Orders o inner join orderDetails d on o.orderid=d.orderid where d.Quantity>=50 order by d.Quantity;

order 테이블과 orderDetails 테이블을 inner join하고 customerid별로 구매수량(Quantity)의 합계를 구하시오
출력 컬럼명은 QuantitySum이고, 오름차순으로 정렬해서 출력시키기.


select customerid,sum(quantity) as QuantitySum from orders o inner join orderdetails od on o.orderid=od.orderid group by customerid order by QuantitySum;
customers 테이블과 orders 테이블을 left join 하고 customerid, orderdate, orderid, customername 정보를 추출하세요. 1996년도 7월에 주문된 건만 추출하세요. 날짜는 내림차순으로


select c.customerid, orderdate, orderid, customername from customers c left join orders o on c.customerid = o.customerid where o.orderdate between '1996-07-01' and '1996-07-31' order by orderdate desc;

 

'SQL' 카테고리의 다른 글

MySQL Workbench 8.0 CE  (0) 2023.08.04
SQL 총연습  (0) 2023.08.03
SQL 기타  (0) 2023.08.02
SQL 연습  (0) 2023.08.02
SQL 기본  (0) 2023.08.01

기본적인 SQL 문법들을 익혔다면 이제 여러 예문에 해당하는 SQL 구문을 쓸 줄 알아야 한다.

연습만이 살 길이다!!!

 

아래 링크를 통해 미리 생성된 DB를 활용할 수 있다.

설치하기 어려운 환경 혹은 간단히 select문을 연습할 때 유용한 것 같다

https://www.w3schools.com/sql/trysql.asp?filename=trysql_select_all

 

아래 표는 연습했던 여러 예제와 해당하는 SQL문을 적었다.

연습해본 결과 group by를 잘 사용해야 익숙하게 SQL문을 다룰 수 있을 것 같다.

정처기에서도 group by 예문은 정말 잘 나오더라..

제일 마지막 조건문 형태의 SQL문은 정말 당황스러웠다. 

참고로 알아두고 필요할 때 사용하면 되겠다!

 

연습
Customers에서 회원id(CustomerID), 거주도시(city), 거주국가(country)를 출력하시오


select CustomerID,city,country from Customers;
주문정보(Orders)중에서 건별ID, 주문고객ID, 주문일자(OrderDate)10건만 출력하시오


select OrderID,CustomerID,OrderDate from Orders limit 10;
Customers 테이블에서 Mexico에 사는 사람들 정보를 추출하시요 [홑따음표 쌍따음표 무관]


select * from Customers where Country='Mexico';
Customers 테이블에서 Mexico에 살지 않는 회원들의 정보를 추출하시오


select * from Customers where Country not in ('Mexico');
select * from Customers where Country != 'Mexico';
국가 이름이 'S'로 시작하는 국가에 거주하는 사람들 정보를 모두 추출하시오


select * from Customers where Country like 'S%';
국가 이름이 'A'로 끝나는 국가에 거주하는 사람들 정보를 모두 추출하시오


select * from Customers where Country like '%A';
국가 이름이 ‘S’로 시작하지 않는 국가에 거주하는 사람들 정보를 추출하시오


select * from Customers where Country not in ('S%');
Mexico에 거주 중인 사람과 이름(Contact Name)Yang Wang인 사람을 추출하시오


select * from Customers where Country='Mexico' or ContactName='Yang Wang';
Mexico에 사는 사람과 Sweden에 사는 사람들의 거주 정보 출력하기


select Address,City,Country from Customers where Country='Mexico' or Country='Sweden';
Mexico에 사는 사람, Sweden에 사는 사람, USA에 사는 사람 정보 출력하기 [in 사용해서 추출하기]


select * from Customers where Country in ('Mexico','Sweden','USA');
회원정보 테이블(Customers)에서 모든 컬럼 정보를 나라이름이 알파벳순으로 정렬 출력하시요. 역순도 출력하시오


select * from Customers order by Country;
select * from Customers order by Country desc;
회원정보 테이블(Customers)에서 모든 컬럼 정보를 5번째 컬럼이 알파벳순이 되도록 정렬 출력하시오.
역순도 출력하시오


select * from Customers order by 5;
select * from Customers order by 5 desc;
제품정보(Products) 테이블에서 가격이 높은 순서부터 모든 컬럼값이 출력되도록 하시오


SELECT * FROM Products order by Price desc;
Customers 테이블에서 나라별로 몇 명이 가입했는지 집계하시오


SELECT Country,count(Country) FROM Customers group by Country;
위에서 추출한 결과를 많이 가입한 나라 순서대로 정렬하시오


SELECT Country,count(Country) FROM Customers group by Country order by count(Country) desc;
위에서 추출한 결과의 컬럼명을 count(*)에서 cntID로 변경하시오


SELECT Country,count(Country) as cntID FROM Customers group by Country order by count(Country) desc;
위에서 추출한 결과에서 나라별 가입한 사람이 5명 이상인 경우만 추출하시오


SELECT Country,count(Country) as cntID FROM Customers group by Country having cntID>=5 order by count(Country) desc;
당사가 가지고 있는 모든 제품들의 가격을 합하면 얼마인지 계산하시오(Products, price)


SELECT sum(Price) FROM Products;
productID30번 이하인 제품들의 평균가격을 추출하시오.
(추출될 컬럼명은 avgPrice)


SELECT avg(Price) as avgPrice FROM Products where ProductID<=30
employee들의 생일을 연도를 구분한 월별로 내림차순 정렬하고, 연도를 구분한 월별로 생일이 각각 몇명이 있는지 출력하시오.
(연도를 구분한 월별 컬럼명은 Month)(인원수의 컬럼명은 cnt)
BirthDate데이터에서 7번째까지 데이터를 가져오면 년,월을 가져오게 된다. 1968-12 / 내림차순 정리


SELECT substr(BirthDate,1,7) as Month,count(*) as cnt FROM Employees group by Month order by Month desc;
위 문제에서 연도별로 내림차순으로 출력하세요. (생일의 해 컬럼명은 Year)


SELECT substr(BirthDate,1,4) as Year,substr(BirthDate,1,7) as Month,count(*) as cnt FROM Employees group by Month order by Year desc;
제품의 공급자별로 판매가격의 평균을 구해주세요.
(Products 테이블에서 SupplierID를 가지고)(컬럼명은 avgPrice)


SELECT SupplierID,avg(Price) as avgPrice FROM Products group by SupplierID;
productID20번 이상인 제품들 중 가격이 가장 비싼 제품의 가격을 알려주세요
(products 테이블에서)(출력할 컬럼명은 maxPrice)


SELECT Max(Price) FROM Products where ProductID>=20;
전체 제품 중 가격이 가장 낮은 제품 정보를 출력하시오


SELECT * FROM Products where price=(select min(price) from Products);
전체 제품 중 가격이 가장 높은 제품 정보를 출력하시오


SELECT * FROM Products where price=(select max(price) from Products);
연도, 월과 상관없이 일별(orderdate) 주문 건수를 집계하시오. , 정렬순서는 Date를 기준으로 오름차순하시오.
(substras를 함께 사용하시요)(orders 테이블)(컬럼명은 cnt)(일별 컬럼명은 Date)


SELECT substr(OrderDate,9,2) as Date,count(*) as cnt FROM Orders group by Date order by Date;
연도와 상관없이 월별 주문 건수를 집계하세요. 정렬순서는 Month를 기준으로 내림차순하시오.
(컬럼명은 Monthcnt)


SELECT substr(OrderDate,6,2) as Month,count(*) as cnt FROM Orders group by Month order by Month desc;
가입한 고객들의 나라별 중복되지 않는 도시 갯수를 각각 집계하여 추출하시오. 나라별로 도시가 몇 개씩 나오는지 집계하기. (도시 개수의 컬럼명은 cityNum)


SELECT country, COUNT(DISTINCT city) AS cityNum FROM customers GROUP BY country;
products 테이블에서 카테고리ID3이하인 제품을 소비재4-5인 제품을 사치재, 그리고 그 외 모든 제품을 'etc'로 분류되게 하여 카테고리ID와 분류된 정보를 출력하시오. (분류된 정보의 컬럼명은 분류)


SELECT ProductName,CategoryID,
CASE
WHEN CategoryID <= 3 THEN '소비재'
WHEN CategoryID BETWEEN 4 AND 5 THEN '사치재'
ELSE 'etc'
END AS 분류
FROM products;

 

참고

CASE 조건 WHEN 결과1 THEN 출력1

                   [WHEN 결과2 THEN 출력2]

                   ELSE 출력3
END "컬럼명"

'SQL' 카테고리의 다른 글

MySQL Workbench 8.0 CE  (0) 2023.08.04
SQL 총연습  (0) 2023.08.03
SQL 기타  (0) 2023.08.02
JOIN  (0) 2023.08.02
SQL 기본  (0) 2023.08.01
DB 준비

apt -y update

apt dist-upgrade -y

apt install mariadb-server mariadb-client -y

 

 

DB 확인

root@ubuntu:~# mysql
MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.001 sec)

 

DB 사용

MariaDB [(none)]> use testdb;
Database changed

 

 

사용 중인 DB 확인

MariaDB [testdb]> select database();
+------------+
| database() |
+------------+
| testdb     |
+------------+
1 row in set (0.000 sec)

 

 

DB의 기본적인 정보 확인

mysql의 버전, 등 여러 정보를 확인할 수 있다



Data Definition Language

DB에 대한 간단한 조작법들(create, alter, drop)에 대해 알아보자.

DB 생성 및 확인

 

DB제거 및 확인

 

 

DB가 준비됐다면 table을 본격적으로 다뤄보자.

테이블 생성 이때 각 열들의 속성들을 구체적으로 적어줘야 한다

 

테이블의 스키마를 확인

 

테이블 삭제

 

테이블명 바꾸기

 

테이블에서 열 추가

 

테이블 컬럼 삭제

 

컬럼의 속성 및 이름 수정

 

동일 이름도 가능하다

 

modify를 이용한 컬럼 속성의 수정

 

 

Data Manipulation Language

앞에서 간단하게 DDL에 대해 알아봤다. 이번에는 select, insert, update, delete와 같은 DML에 대해 알아보자.

 

테이블의 스키마르 확인 후 각 데이터를 기입한다. 문자와 숫자를 잘 구별하자

 

모든 것을 나타낼 때는 * 을 사용한다

 

필요한 열만 볼 수 있고, where을 사용하면 제한적으로 출력할 수 있다

 

데이터를 수정할 때는 update&nbsp; set&nbsp; where&nbsp; 구문을 기억하자

 

데이터 삭제 시에는 delete from 구문을 사용

 

출력되는 컬럼을 제한할 때 limit을 사용

 

 

좀 더 상세한 명령어들을 알아보기 위해 아래와 같이 테이블을 준비하자.

 

열의 중복을 제거할 때 distinct를 사용, 이때 기준이 되는 것이 여러 개라면 기준이 하나일 때와 다르다

 

패턴 검색 시에는 like 사용,&nbsp;%d: d로 끝나는 것을 검색 d%: d로 시작하는 것을 검색 %d%: d가 들어있는 것을 검색

 

데이터가 null이 아닌 것은 is not null

 

연산이나 and, or을 사용하여 조건을 줄 수도 있다

 

등호도 가능

 

정렬 시에는 order by 기준되는 열, asc은 오름차순, desc은 내림차순이다. 이때 default는 asc

 

출력되는 것을 as 이후의 명칭으로 변경이 가능하다

 

열을 임의로 추가도 가능

 

위에서 배운 것을 이와 같이 응용할 수 있다

 

컴럼에 직접 사칙연산도 가능

 

 

이제 집계함수에 대해서도 알아보자.

count는 데이터의 개수를 세고, sum은 합을 나타낸다

 

avg는 평균

 

최댓값은 max, 최솟값은 min

 

같이 데이터끼리 묶을 때는 group by를 사용한고, 이때 group by를 사용하면 그룹별로 집계함수가 적용된다

 

group by에 조건을 추가할 때는 where이 아닌 having을 사용한다

 

between A and B 고등학교 때 자주 배운 영어 형태도 나온다ㅎㅎ 이때, A 이상 B 이하임을 주의

 

파이썬에서와 비슷하게 in은 멤버 연산이 가능하다

 

데이터의 일부만을 추출할 때는 subsrting을 사용한다 사용한 DB는 mariaDB인데 oracle에서는 substr로 쓰는 것 같다

 

offset 기능으로 일부만 사용할 때는 'limit 첫째번숫자, 열거할숫자'로 출력이 가능하다

 

 

연습문제
nameaaa인 레코드를 출력하시요
nameaaa인 레코드의 email을 출력하시요
nameaaa인 레코드의 emailage를 출력하시요
nameaaa 또는 bbb인 레코드를 출력하시요
nameaaa , bbb가 아닌 레코드를 출력하시요
uid2이상 5미만인 레코드
uid1 또는 3 또는 5 인 레코드
named로 시작하는 레코드
name:사용자명(이름) 형식으로 나이와 함께 출력하시요 [concat 함수 사용]
save 기준으로 내림차순 정렬 후 4번째 이후 레코드만 출력하기
해당 문제들을 고민해서 데이터를 조회해보자.
답안은 아래 스크린 샷으로 첨부했다!

 

 

 
 
 
 

'SQL' 카테고리의 다른 글

MySQL Workbench 8.0 CE  (0) 2023.08.04
SQL 총연습  (0) 2023.08.03
SQL 기타  (0) 2023.08.02
JOIN  (0) 2023.08.02
SQL 연습  (0) 2023.08.02

+ Recent posts