SELECT ROUND(column_name,decimals) FROM table_name;
-- 급여가 1500부터 3000사이의 사람은 급여의 15%를 월회비로 지불 -- 출력양식은 이름, 급여, 회비(10원 단위는 반올림 처리) 정보를 출력 SQL> select ename, sal, round((sal*0.15),-2) 회비 from emp where sal between 1500 and 3000; 회비 = sal * 0.15 정수 2번째 자리에서 반올림 : 100 단위로 계산
Trunc(숫자, 원하는 자릿수) : 주어진 숫자를 버림한 후 출력함
오라클에서는 trunc 로 하면 되는데 MySQL 에서는 truncate 로 해야 한다.
-- 30번(영업부) 부서원의 연봉을 계산하여 이름, 부서번호, 급여, 연봉
정보를 연봉이 큰 순서데로 출력하라.
-- 연말 특별 보너스 150%, 연봉은 천단위 미만 절삭처리
SQL> select ename, deptno, sal ,trunc(((sal * 12) + (sal * 1.5)),-3) 연봉 from emp where deptno =30 order by 연봉 desc;
-- 급여(sal)가 2000 이상인 모든 사람은 급여의 5%를 경조비로 내기로 하였다 . -- 이름, 급여, 수당(소수점이하 절삭 처리) 정보를 출력하라. SQL> select ename as 이름, sal as 급여 , trunc((sal*0.05),0) 경조비 from emp where sal >= 2000;
MOD(숫자, 나누기할 수) : 주어진 숫자를 나누기 한 후 나머지 값 출력함
CEIL(숫자) : 주어진 숫자와 가장 근접한 큰 정수를 출력함
SQL> select ceil(10.7) from dual;
FLOOR(숫자) : 주어진 숫자와 가장 근접한 작은 정수를 출력함
SQL> select floor(10.7) from dual;
POWER : 제곱하여 출력함
SQL> select sign(1000), sign(0), sign(-22) from dual;
MySQL은 첫 번째 열부터 전체 테이블에 걸쳐서 연관된 열을 검색하기 때문에 테이블이 크면 클수록 검색속도가 엄청나게 느려진다.
SQL은 테이블에 있는 행(record)를 접근하는 방법은 순차적 접근(sequential access) 방법이고, 다른 하나는 직접 접근(direct access) 이다.
테이블이 많은 행을 가지고 있을 때 오직 하나의 행만 찾는다면 많은 시간을 소비하고 비효율적이다.
MySQL 전문(full-text) 검색은 작은 데이터 집합에서는 빠르지만 데이터의 크기가 커지면 성능이 나빠진다.
레코드가 100만개 있는 경우나 Index 된 텍스트의 크기가 기가바이트 단위인 경우 Query 수행 시간은 1초 ~ 10분 사이를 왔다갔다 하게 되므로 고성능 웹 응용 프로그램에서는 사용할 수가 없다.
MySQL 은 적절한 스키마와 최적화된 Query가 있고, WHERE절에 너무 많은 칼럼이 들어 있지 않은 한 잘 동작한다. 하지만 칼럼수가 늘어나고, 가능한 모든 경우에 대한 검색 기능을 지원하려고 한다면 필요한 Index 수가 기하급수적으로 늘어난다.
Index 를 추가하더라도 해당 칼럼이 절반정도가 선택되는 경우라면 Index 가 별로 도움이 안되어 Full Scan 을 사용한다.
MySQL 은 Index Scan 을 사용할지 Full Table Scan을 사용할지를 자동적으로 결정한다.
MySQL 은 Index 를 사용해서 매치되는 행을 찾고, 디스크에 무작위 순서로 접근하면서 레코드들을 하나하나 읽어낸 뒤 Sort 버퍼에 집어넣는다. 그런 다음 파일 정렬을 통해 값을 정렬하고, 정렬된 값들 중 대부분을 버리게 된다. 이 과정에서 LIMIT 절에 상관없이 전체 결과를 임시로 저장해서 처리한다. 만약 결과 set 이 Sort 버퍼에 다 들어갈 수 없다면 결과 set 은 디스크에 저장되어야 하므로 디스크 I/O까지도 많이 발생시키게 된다.
- MySQL 데이터가 기록되는 폴더를 통째로 압축해서 백업한다. (속도가 빠르며 작업이 단순)
- 복구할 때는 MySQL 데몬을 정지시키고 해당 폴더에 압축을 푼다.
ㅇ 논리적 백업
- 리눅스에서 기본 제공하는 mysqldump를 이용하는 방법
- phpmyadmin 을 이용하는 방법
- 기타 툴을 이용하는 방법
등이 있다.
논리적 백업을 하면 문제 발생시 원인 파악및 해결하기가 수월한데 복구 시간이 상당 소요될 수 있다.
1. 리눅스 상에서 mysqldump를 이용한 백업
mysqldump 로 SQL문을 갖는 텍스트 파일을 생성하는 것이다. ※ 설정한 패스워드에 따라서 -p 다음에 바로 패스워드를 입력하면 적용되지 않는 경우가 있다. 그래서 -p 만 입력하고 실행하면 패스워드를 물어보고 패스워드 입력하면 백업이 잘 된다. # mysqldump -u [사용자아이디] -p DB명 [테이블명] > 저장될 파일명
예) mysqldump -u root -p mydatabase > kimsqrb.sql // DB(mydatabase)를 몽땅 덤프를 뜨게된다. mydatabase 는 실서버에 존재하는 데이터베이스 이름이어야 한다. # mysqldump -u [userId] -p --all-databases > dump.sql // 서버에 있는 모든 것의 논리 백업 생성 2. 복구하기
백업용으로 저장한 SQL 파일을 가지고 복구를 하는 방법도 간단하다.
데이터 량이 많을 경우 백업하는데 속도가 엄청나게 오래 걸린다. # mysql -u [사용자아이디] -p DB명<저장된 SQL 파일명
예) mysql -u jsk005 -p mydatabase< kisqrb.sql
# mysql -u root -p mysql > passwd : 접속비밀번호 입력 mysql > use 해당DB명 // DB를 선택하지 않으면 에러가 발생함 mysql > source dump.sql 로 명령을 실행해도 복구된다. ※ 반드시 pwd 로 현재 폴더의 경로를 확인하고, dump.sql 파일이 올려진 폴더에서 mysql -uroot -p 를 해야 한다.
4만개 정도되는 데이터를 넣었더니 순식간에 DB에 저장되었다.
phpmyadmin 에서 Web 업로드를 하면 Lock 이 걸리고 너무 느려서 도저히 ㅠㅠㅠ
3. phpmyadmin 상에서 백업
phpmyadmin 을 이용하면 명령어를 몰라도 쉽게 백업을 할 수 있다.
자료를 백업하는데에는 시간 별로 걸리지 않아서 자주 백업해 두어야 문제가 생길 때 복구가 가능하다.
4. phpmyadmin 으로 복구
용량이 작은 것은 phpmyadmin 에서 복구하면 편리한데 용량이 좀 큰 것은 작업하다보면 Lock 이 걸려버려서
mysql > use mysql; // mysql database 선택 mysql > select host, user, password from user; // user 테이블 살펴보기
사용자 추가 (권한추가) mysql > create user 사용자ID; // 사용자 추가
mysql > create user userid@localhost identified by '비밀번호';
// 사용자(user)를 추가하면서 패스워드까지 설정
기존에 사용하던 계정에 외부 접근 권한을 부여하려면, Host를 '%' 로 하여 똑같은 계정을 추가한다
mysql > create user 'userid'@'%' identified by '비밀번호'; // '%' 의 의미는 외부에서의 접근을 허용
다른 방법으로는
mysql > USE mysql; // mysql database 선택 mysql > INSERT INTO user (Host, User, Password) VALUES ('localhost', '계정아이디', password('비밀번호')); mysql > INSERT INTO user (Host, User, Password) VALUES ('%', '계정아이디', password('비밀번호')); mysql > FLUSH privileges;
mysql > drop user '사용자ID'@localhost; // 사용자 삭제
mysql > select * from user; // 등록된 모든 사용자 ID 조회 mysql > delete from user where user = '사용자ID';// 사용자 삭제
계정이 생성되었다면, 그 계정이 접근할 수 있는 데이터베이스를 생성하고 권한을 부여해야 한다
데이터베이스 생성
mysql > show databases;// DB 목록 확인
msyql > create database DB명;// 데이터베이스 생성
mysql >create database sampledb default character set utf8mb4 COLLATE = utf8mb4_unicode_ci;
msyql > create schema DB명 default character set utf8; -- 둘중에 하나를 입력하면 DB 생성됨
mysql > create database DB명 default character set utf8;
mysql > create databaseDB명default character set utf8 COLLATE utf8_general_ci;
mysql > CREATE DATABASE IF NOT EXISTS DB명 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
// default character set을 지정하지 않으면 한글이 깨져서 나오므로 주의해야 한다.
// default character set 변경
msyql > ALTER DATABASE DB명 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
msyql > drop database DB명;// 데이터베이스 삭제
사용자에게 데이터베이스 사용권한 부여
MySQL은 사용자 이름, 비밀번호, 접속 호스트로 여러분을 인증한다.
MySQL은 로그인을 시도하는 위치가 어디인가 하는 것도 인증의 일부로 간주한다.
MySQL 에서 사용자 계정을 추가하고 권한을 추가하거나 제거하는 데 GRANT 와 REVOKE 명령을 사용하기를 권장한다.
사용자에게 허가된 것을 확인하려면 SHOW GRANTS 를 사용한다.
IDENTIFIED BY '비밀번호'; 는 권한부여를 하면서 비밀번호까지 변경하고자 하는 경우
이므로 비밀번호는 변경하지 않으려면 이 부분을 빼면 된다.
mysql > GRANT ALL PRIVILEGES ON DB명.테이블 TO 계정아이디@host IDENTIFIED BY '비밀번호';
// 계정이 이미 존재 하는데 'identified by '비밀번호' 부분을 추가하면 비밀번호가 변경된다
mysql> GRANT ALL privileges ON DB명.* TO 계정아이디@locahost IDENTIFIED BY '비밀번호'; mysql> GRANT ALL privileges ON DB명.* TO 계정아이디@'%' IDENTIFIED BY '비밀번호';
mysql > grant all privileges on DB명.* to userid@'%' identified by '비밀번호' ; //모든 원격지에서 접속 권한 추가
host에 '200.100.%' 로 하면 IP주소가 200.100.X.X 로 시작되는 모든 IP에서 원격 접속을 허용한다는 의미
host에 '200.100.100.50' 으로 하면 IP주소가 200.100.100.50 인 곳에서만 원격 접속을 허용한다는 의미
mysql > grant all privileges on test.* to userid@localhost identified by '비밀번호';// user 에게 test 데이터베이스 모든 테이블에 대한 권한 부여
mysql> grant select, insert, update on test.* to user@localhost identified by '비밀번호';
// user 에게 test 데이터베이스 모든 테이블에 select, insert, update 권한 부여
mysql> grant select, insert, update on test.* to user@localhost; -- 패스워드는 변경없이 권한만 부여하는 경우
// user 에게 test 데이터베이스 모든 테이블에 select, insert, update 권한 부여
mysql> grant all privileges on *.* to user@localhost identified by '비밀번호' with grant option;
// user 에게 모든 데이터베이스 모든 테이블에 권한 부여// 전역 권한은 모두 광범위한 보안문제가 수반되므로 권한을 허용하는 경우 신중해야 함
mysql > flush privileges; // 변경된 내용을 반영(권한 적용)
사용자에게 부여된 권한 확인
mysql > SHOW GRANTS FOR test@localhost; -- userid 와 host명까지 붙여서 검색해야 함
mysql > SHOW GRANTS FOR test@'%';
mysql > SHOW GRANTS FOR test@'200.100.100.50';
사용자에게 데이터베이스 사용권한 제거
revoke all on DB명.테이블명 from 사용자ID;// 모든 권한을 삭제
이제 다시 show grants 로 정보를 확인해보면
user 정보는 남아 있는데, 권한부여 정보는 삭제되고 없는 것이 보인다.
사용자 계정마저 삭제하고 권한 설정 정보를 확인하려고 하면 Error 가 발생하는 걸 확인할 수 있다.
사용자 계정 삭제
mysql > drop user userid@'%';
mysql > drop user userid@localhost;
위에 있는 것과 비교해서 host 가 % 로 된 것이 삭제되었다.
비밀번호 보안
MySQL 비밀번호가 일반 텍스트로 저장되지 않는다고 해서 비밀번호를 간단하게 만들어서는 안된다. MySQL 서버에 접속 가능한 사람은 누구든지 무차별 대입공격(brute-force) 방식으로 비밀번호를 알아내려고 시도해 볼 수 있으며, MySQL 은 유닉스 비밀번호에서처럼 이런 공격을 감지하고 막아낼 방도가 없다.
DB 데이터가 잘못된 것이 있어서 엑셀로 내보내기를 한 다음 엑셀에서 작업을 한 후 수정된 부분만 다시 DB에 업데이트를 하고 싶다.
어떤 방법을 택하면 편할까 하는 생각을 했지만 내가 아는 수준이 미약한지라 아주 허접한 방법으로 시도를 하기로 했다.
먼저 엑셀에서 필요한 부분만 남기고 나머지는 모두 삭제한다.
이 데이터를 아래 VBA 코드를 이용하여 내보내기를 한다.
Sub TextExport() '// Export Each Sheet As Text File Dim rng As Range Dim iRow As Long, iCol As Integer Dim sTxt As String, sPath As String Dim ff As Integer
ff = FreeFile sPath = ThisWorkbook.Path & "\" Open sPath & ActiveSheet.Name & ".csv" For Output As #ff Set rng = ActiveSheet.UsedRange
deLimiter = ";" '// 구분자
For iRow = 2 To rng.Rows.Count '// 2행부터 마지막 행까지 For iCol = 1 To rng.Columns.Count '// 1열부터 오른쪽 최대 열까지 sTxt = sTxt & ActiveSheet.Cells(iRow, iCol).Value & deLimiter Next iCol Print #ff, Left(sTxt, Len(sTxt) - 1)
sTxt = vbNullString Next iRow Close #ff '// 작업을 마치고 파일을 닫는다 MsgBox "내보내기 완료" End Sub
그러면 파일에 2번째 행부터 마지막 행까지 내보내기가 된다.
파일 내보내기가 완료되었으므로 이제 서버의 MYSQL 로 데이터를 업데이트 하기 위한 과정이 필요하다.
include_once '/_var/db.info.php'; include_once '/_core/function/db.mysql.func.php'; $DB_CONNECT = isConnectDb($DB); ########### DB 연동 정보 가져오기 끝 ########### $tblName = data; // 테이블명
$file=fopen("data.csv","r"); // 엑셀로 내보낸 파일명을 적어준다 if(!$file) { echo("Failed to open the file"); exit; }
$total_line = 0; while($line = fgetcsv($file,1000, ";")) { // 구분자는 ; 로 지정, 한줄씩 읽어드린 값을 1000 라인까지 계속하라. // 조건에 맞는 것만 필드 업데이트 하기 $result = mysql_query("Update $tblName SET subject = '$line[1]' Where uid = '$line[0]'",$DB_CONNECT); $total_line++; }
echo("총 $total_line Update"); fclose ($file); ?>
바로 위 PHP 소스코드와 data.csv 파일을 서버에 업로드한다음에 실행하면 업데이트가 된다.
PHP 소스코드는 DB를 연동하고 fopen 으로 파일을 열어서 while 문으로 업데이트한다.
아래 방법은 테이블A 에서 테이블B로 테이블 구조를 생성하고 데이터까지 복사하는 방법이다.
그러나 primary key 등은 생성하지 못한다.
<?php defined('__KIMS__'); session_start();
// 테이블이 생성되기 전에 데이터 베이스 연결하기 // 데이터베이스는 mysql_select_db () 함수를 사용하여 선택 include_once 'db.info.php'; require '../_core/function/db.mysql.func.php'; require '../_core/function/lib/getContent.lib.php'; $DB_CONNECT = isConnectDb($DB); // 데이터베이스 연결하기 완료
$A_TABLE = Sample; // 원본 테이블 $B_TABLE = Sample_copy; // 복사할 테이블 $result = mysql_query("SELECT COUNT(*) from $B_TABLE", $DB_CONNECT); if ( !$result ) { $result = "CREATE TABLE $B_TABLE as select * from $A_TABLE"; mysql_query($result, $DB_CONNECT); echo "테이블 Copy 완료!!"; } else { echo "테이블이 이미 있어요"; }
// 테이블이 생성되기 전에 데이터 베이스 연결하기 // 데이터베이스는 mysql_select_db () 함수를 사용하여 선택 include_once 'db.info.php'; require '../_core/function/db.mysql.func.php'; require '../_core/function/lib/getContent.lib.php'; $DB_CONNECT = isConnectDb($DB);
// 데이터베이스 연결하기 완료
$A_TABLE = Sample; // 원본 테이블 $B_TABLE = Sample_copy; // 복사 또는 신규 생성할 테이블 $result = mysql_query("SELECT COUNT(*) from $B_TABLE", $DB_CONNECT); if ( !$result ) { $result = "CREATE TABLE `$B_TABLE` ( `uid` int(10) unsigned NOT NULL auto_increment, `user_id` varchar(20) NOT NULL default '', `user_name` varchar(16) NOT NULL default '', `Cate1` varchar(12) default NULL, `Cate2` varchar(12) default NULL, `subject` varchar(200) NOT NULL default '', `explain` varchar(200) default NULL, `direct` varchar(200) default NULL, `comment` text, `ABC` char(2) default NULL, `date` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`uid`) ) TYPE=MyISAM AUTO_INCREMENT=0 ";
** 아래 방법은 테이블 생성 및 데이터 복사는 잘 되는데 primary key 설정이 안됨
CREATE TABLE B_TABLE as select * from A_TABLE;
또는
CREATE TABLE B_TABLE select * from A_TABLE;
// 완전히 다른 테이블을 생성하고자 할 때
CREATE TABLE[테이블명]
( [필드명] [필드타입](크기), ...);
예제
CREATE TABLEmember( id varchar(16) not
null, passwd varchar(20) not null, name varchar(20) not null, sex char(1), age varchar(3), address varchar(100) );
2. 복사할 테이블이 존재하는 경우
// A_TABLE 라는 테이블의 특정한 조건에 해당되는 데이터를 B_TABLE 라는 테이블로 전부 옮길 때
INSERT INTO B_TABLE SELECT * FROM A_TABLE;
// A_TABLE 라는 테이블의 특정한 조건에 해당되는 데이터를 B_TABLE 라는 테이블로 옮길 때 INSERT INTO B_TABLE (필드1, 필드2, 필드3, 필드4) SELECT 필드1, 필드2, 필드3, 필드4 FROM A_TABLE where 조건;