레이블이 [mysql]인 게시물을 표시합니다. 모든 게시물 표시
레이블이 [mysql]인 게시물을 표시합니다. 모든 게시물 표시

2020년 2월 18일 화요일

[mysql]계층형 테이블: 하위 그룹 조회 쿼리

WITH RECURSIVE CTE AS (
  SELECT
    COMPANY_NAME,
    COMPANY_ID,
    PARENT_ID,
    GROUP_ORDER,
    COMPANY_DEPT,
    USE_YN
  FROM
    COMPANY
  WHERE
    COMPANY_ID = #{companyId}
  UNION ALL
  SELECT
    T1.COMPANY_NAME,
    T1.COMPANY_ID,
    T1.PARENT_ID,
    T1.GROUP_ORDER,
    T1.COMPANY_DEPT,
    T1.USE_YN
  FROM
    COMPANY T1
    INNER JOIN CTE T2 ON T1.PARENT_ID = T2.COMPANY_ID
)
SELECT
  COMPANY_NAME,
  COMPANY_ID,
  PARENT_ID,
  GROUP_ORDER,
  COMPANY_DEPT,
  USE_YN
FROM
  CTE
WHERE
  1 = 1

COMPANY 계층형 테이블의 하위 그룹 검색

[mysql] 계층형 쿼리: 상위 그룹 아이디 가져오기

SELECT
  T1.C_ID AS COMPANY_ID
FROM
  (
    SELECT
      @r AS C_ID,
      (
        SELECT
          @r := PARENT_ID
        FROM
          COMPANY
        WHERE
          COMPANY_ID = C_ID
      ) AS parent
    FROM
      (
        SELECT
          @r := 317
      ) vars,
      COMPANY H
    WHERE
      @r <> 0
  ) T1
WHERE
  1 = 1
AND T1.C_ID <> 317   -- 자기자신은 제외



COMPANY  란 테이블이 있고 PARENT_ID 컬럼이 있는 계층형 테이블이다.
계층형 테이블의 특정 로우의 상위 그룹 시퀀스 값을 가져올수 있다.


2019년 5월 7일 화요일

2019년 2월 20일 수요일

[mysql] global 변수 값 가져오기, 모니터링 기본 공식


상태 값 가져오기
show status WHERE Variable_name LIKE '%connect%' OR Variable_name LIKE '%thread%' OR Variable_name LIKE '%clients%'


커넥션 설정 정보 가져오기
show variables like '%max_connection%';



위 쿼리로 가져온 값을 공식에 대입하여 모니터링용 값을 구한다.

//Cache Miss Rate(%) = Threads_created / Connections * 100
//Connection Miss Rate(%) = Aborted_connects / Connections * 100
//Connection Usage(%) = Threads_connected / max_connections * 100


어디선가 퍼온내용...

* Connection Usage(%)가 100% 라면 max_connections 수를 증가시켜 주십시요. Connection 수가 부족할 경우 Too Many Connection Error 가 발생합니다.
* DB 서버의 접속이 많은 경우는 wait_timeout 을 최대한 적게 (10~20 정도를 추천) 설정하여 불필요한 연결을 빨리 정리하는 것이 좋습니다. 그러나 Connection Miss Rate(%) 가 1% 이상이 된다면 wait_timeout 을 좀 더 길게 잡는 것이 좋습니다.
* Cache Miss Rate(%) 가 높다면 thread_cache_size를 기본값인 8 보다 높게 설정하는 것이 좋습니다. 일반적으로 threads_connected 가 Peak-time 시 보다 약간 낮은 수치로 설정하는 것이 좋습니다.



커넥션 설정 정보 변경하기 (바로 적용됨) 재시작시는 기본설정으로 돌아감.
set global max_connections=10000






2017년 10월 25일 수요일

[mysql]윈도우 mysql 백업 및 복원

mysql 설치된 경로 bin로 이동한다.


1) 백업
mysqldump -u root -p 디비명 > 파일명.확장자

확장자는 .dump 나 .sql 로 생성

주의사항
C: 드라이브의 경우 mysql server 권한으로 파일을 생성 할수 없을수도 있다.




2) 복원
mysql -u root -p 디비명 < 파일명.확장자

주의사항
프로시저는 복원이 되지 않는다. 트리거는 됨.



2017년 10월 24일 화요일

[mysql]웹서버 보안관련 mysql 계정 권한 설정.

웹서버에서 injection 공격에 의해서 의도치 않는 데이터 위변조를 막기위해서

서버측 에서 접속하는 mysql 계정에 select 권한만 주고 데이터 변경 로직은 프로시저로

처리 하기 위한 권한 설정.

use mysql;

-- 계정 확인
select host,user from user;

1.
-- 이미 존재할 경우만 계정 삭제
DROP USER 'client'@'%'; -- client 라는 계정 생성 하고 myschema 스키마 에 모든 테이블에 모든 원격접속을 허용하고 패스워드를 설정.
grant usage on myschema.* to 'client'@'%' identified by 'password'

-- myschema 스키마에 모든 테이블에 모든 권한 부여
grant all privileges on myschema.* to 'client'@'%' identified by 'password' with grant option;

-- myschema 스키마에 모든 테이블에 추가,삭제,변경 권한 삭제.
revoke DELETE,UPDATE,INSERT on myschema.* from 'client'@'%';

-- 적용
flush privileges;


-- 기타
-- 특정 권한주기
grant select on myschema.* to 'client'@'%' identified by 'password';

-- 프로 시저 실행 권한 주기.
grant execute on procedure myschema.* to 'client'@'%' identified by 'password'; -- 프로시저 실행 권한 추가.

2017년 3월 28일 화요일

[mysql] SQL GATE 2010...에는 rollback 기능이 없다?

검색해보니 롤백기능이 없더라
관련 개발자 답변은 2월 에 업데이트 예정이라고 하는데 몇년도 2월인지는 모르겟다
어쨋든 꽁짜로 쓰고 있기때문에 sql 을 직접 날려서 설정 하는 수밖에...


아래와 같이 기본 쿼리를 날려서 셋팅해서 사용하면된다.

set autocommit=0;    -- 1은 autoCommit 활성 상태 0 은 해제



select @@session.autocommit; -- 현제 접속 계정에 따라 설정된 값 확인 쿼리


재접속 했을때 변경된 설정 값이 유지되는지는 테스트 해보지 않았다.

업데이트나 삭제 쿼리 날리기전엔 항상

set autocommit=0;

설정후

해당 쿼리 날린후

데이터 확인후

commit 을 할것을 추천한다.

2017년 3월 23일 목요일

[mysql] rank 값 출력 하기

oracle 과 달리 mysql 에서는 랭크 값을 구할수 있는 함수가 따로 존재 하지 않는다.

따라서 SELECT 된 컬럼값을 스칼라 변수에 할당하고 초기화하길 반복 하면서 랭크값을

구해야한다.



EVENT라는 테이블이 있다고 가정하고

JOIN_COUNT: 참여 회수 , RIGHT_COUNT: 적중 회수 , MEMBER_ID: 회원번호(유니크)

라는 컬럼이 있다고 가정하자

일단 적중회수가 같을 경우 참여회수가 많은 것을 우선 출력한다 가정할경우에 쿼리는

SELECT
         T.*
         ,@ROWNUM:= @ROWNUM + 1  AS ROWNUM
FROM (
       SELECT
                 JOIN_COUNT
                 ,RIGHT_COUNT
                 ,MEMBER_ID
       FROM EVENT
       WHERE 1=1
       ORDER BY RIGHT_COUNT DESC, JOIN_COUNT DESC
) T ,(SELECT @ROWNUM:=0) R

이렇게 할경우 적중수 우선 정렬후 참여수가 많은 순으로 정렬되면서 행번호가 매겨져서
랭킹을 구할수 있다 하지만 문제점이 동일 적중에 참여수도 동일일 경우에는 랭킹이 동등 하게 나오지가 않는다.

따라서 위 쿼리는 사용불가

SELECT
         T.*
       
FROM (
       SELECT
                 JOIN_COUNT
                 ,RIGHT_COUNT
                 ,MEMBER_ID
       FROM EVENT
       WHERE 1=1
       ORDER BY RIGHT_COUNT DESC, JOIN_COUNT DESC
) T ,(SELECT
           @RANK:=1
           ,@PREV_RIGHT_COUNT:=0
           ,@PREV_JOIN_COUNT:=0
           ,@SAME_COUNT:=1) R

일단 랭크값을 1위 부터 증가 하므로 RANK 에 기본값 1을 할당한다.
그리고 이전 적중수,참여수를 저장하기 위한 변수 PREV_RIGHT_COUNT,PREV_JOIN_COUNT
에 기본 0 값을 할당한다. SAME_COUNT RANK 의 증가량을 저장하기위한변수로 기본 1씩 증가 하기때문에 1로 할당한다

위 쿼리를 변형.

SELECT
         T.*
                        -- 이전 로우보다 적중카운트가 작을경우 순위 증가
         ,@RANK:= CASE WHEN T.RIGHT_COUNT< @PREV_RIGHT_COUNT
                                THEN @RANK + @SAME_COUNT
                        -- 이전 로우랑 적중 카운트는 같으나 참여 회수가 적을경우 순위 증가
                                WHEN (T.RIGHT_COUNT  =  @PREV_RIGHT_COUNT AND
                                          T.JOIN_COUNT < @PREV_JOIN_COUNT)
                                THEN @RANK + @SAME_COUNT
                        -- 이전 로우랑 적중 ,참여회수가 모두 동일할경우 같은 순위로 처리
                                WHEN  WHEN (T.RIGHT_COUNT   = @PREV_RIGHT_COUNT
                                           AND T.JOIN_COUNT = @PREV_JOIN_COUNT)
                                THEN @RANK
                                ELSE @RANK
                         END AS RANK
           -- RANK 라는 이름을 붙혀주고 경우에따라 저장될 값을 초기화한다.
         
           -- 랭크중복 로우가 아니면  SAME_COUNT 1로 초기화거나
           -- 랭크가 중복되는 만큼 랭크증가량은 은 늘어난다.
           ,@SAME_COUNT := IF(
                                         (T.RIGHT_COUNT  = @PREV_RIGHT_COUNT  
                                         AND T.JOIN_COUNT = @PREV_JOIN_COUNT ),                                                        @SAME_COUNT+1, 1)
           -- 현재 적중수와 참여수를 다음 로우에서 참고하기위해 값을 넣어준다.
           ,@PREV_RIGHT_COUNT:=T.RIGHT_COUNT
           ,@PREV_JOIN_COUNT:=T.JOIN_COUNT


FROM (
       SELECT
                 JOIN_COUNT
                 ,RIGHT_COUNT
                 ,MEMBER_ID
       FROM EVENT
       WHERE 1=1
       ORDER BY RIGHT_COUNT DESC, JOIN_COUNT DESC
) T ,(SELECT
           @RANK:=1
           ,@PREV_RIGHT_COUNT:=0
           ,@PREV_JOIN_COUNT:=0
           ,@SAME_COUNT:=1) R


거의 완성 됐다 최종본은 위 쿼리를 FROM 절에서 한번더 묵어서 필요한 컬럼만 SELECT 하면 됨.
-- 필요한것만 SELECT
SELECT
    T2.RANK
    ,T2.RIGHT_COUNT
    ,T2.JOIN_COUNT
    ,T2.MEMBER_ID
FROM (
SELECT
         T.*
                        -- 이전 로우보다 적중카운트가 작을경우 순위 증가
         ,@RANK:= CASE WHEN T.RIGHT_COUNT< @PREV_RIGHT_COUNT
                                THEN @RANK + @SAME_COUNT
                        -- 이전 로우랑 적중 카운트는 같으나 참여 회수가 적을경우 순위 증가
                                WHEN (T.RIGHT_COUNT  =  @PREV_RIGHT_COUNT AND
                                          T.JOIN_COUNT < @PREV_JOIN_COUNT)
                                THEN @RANK + @SAME_COUNT
                        -- 이전 로우랑 적중 ,참여회수가 모두 동일할경우 같은 순위로 처리
                                WHEN  WHEN (T.RIGHT_COUNT   = @PREV_RIGHT_COUNT
                                           AND T.JOIN_COUNT = @PREV_JOIN_COUNT)
                                THEN @RANK
                                ELSE @RANK
                         END AS RANK
           -- RANK 라는 이름을 붙혀주고 경우에따라 저장될 값을 초기화한다.
         
           -- 랭크중복 로우가 아니면  SAME_COUNT 1로 초기화거나
           -- 랭크가 중복되는 만큼 랭크증가량은 은 늘어난다.
           ,@SAME_COUNT := IF(
                                         (T.RIGHT_COUNT  = @PREV_RIGHT_COUNT  
                                         AND T.JOIN_COUNT = @PREV_JOIN_COUNT ),                                                        @SAME_COUNT+1, 1)
           -- 현재 적중수와 참여수를 다음 로우에서 참고하기위해 값을 넣어준다.
           ,@PREV_RIGHT_COUNT:=T.RIGHT_COUNT
           ,@PREV_JOIN_COUNT:=T.JOIN_COUNT


FROM (
       SELECT
                 JOIN_COUNT
                 ,RIGHT_COUNT
                 ,MEMBER_ID
       FROM EVENT
       WHERE 1=1
       ORDER BY RIGHT_COUNT DESC, JOIN_COUNT DESC
) T ,(SELECT
           @RANK:=1
           ,@PREV_RIGHT_COUNT:=0
           ,@PREV_JOIN_COUNT:=0
           ,@SAME_COUNT:=1) R

) T2
WHERE
1=1

-- 이미 정렬후 RANK 만 붙혔기때문에 따로 ORDER BY 를 해줄 필요가 없다.



퍼가실땐 댓글~~~~~






2016년 12월 28일 수요일

[mysql] multiple PRIMARY KEY 추가 하기( 기존 pk auto_increment 일때)

1.ALTER TABLE `테이블` MODIFY COLUMN `autoincrement pk컬럼명` INT NOT NULL;
2.ALTER TABLE `테이블` DROP PRIMARY KEY;
3.ALTER TABLE `테이블` ADD PRIMARY KEY (pk할컬럼1, pk할컬럼2, pk할컬럼3 , ...);
4.ALTER TABLE `테이블` MODIFY `autoincrement pk컬럼명` INT NOT NULL AUTO_INCREMENT;

기존에 자동증가 값으로 설정된 pk (mysql의 경우 오토인크리먼트 칼럼은 자동으로 pk 지정되는거로 알고 있음) 가 존재 할경우 ADD PRIMARY KEY 를통해서 멀티플 PK 지정이 불가능 하다.
따라서

1. autoincrement pk컬럼명 을 일반 INT NOT NULL 컬럼으로 MODIFY 를 먼저하고
2. 해당 테이블에 PK 를 드랍시킨후
3. 멀티플 PK를 새로 지정한후
4. 원레 오토 인크리먼트로 지정됐던 컬럼을 다시 오토 인크리먼트로 설정.

결과 증가값은 그대로 유지 하면서 멀티플 PK 가 추가되었다.


%%%주의%%%


기존 데이터가 존재 할경우
멀티플 칼럼에 대한 중복된 데이터를 삭제해야만 3번 쿼리가 실행될수 있다.



2016년 11월 16일 수요일

[mysql] 이벤트 사용하기

주기적으로 데이터베이스의 공통된 작업을 해야할경우 클라이언트단 에서 주기적 요청을 통한 데이터 변경은 바람직하지 않다 데이터 베이스 스스로 처리하게 셋팅 해야한다.

예) 하루에 한번 특정 이벤트의 날짜를 수정 하여 재등록 할경우

/*(CURRENT_TIMESTAMP 는 현재시간 년월일시 리터럴)*/
DELIMITER $ /*SQL 종료문을 $로 대체하겟다는 선언*/
CREATE EVENT EVENTTEST /*이벤트이름 유니크여야함,64글자 제한,대소문자 구분 X*/
ON SCHEDULE
/*특정시간에 한번 실행 경우*/
/*
AT '2016-11-17 11:35:00' 처럼 특정시간 지정 가능(미래의 시간만 지정 가능)
또는
AT CURRENT_TIMESTAMP +  INTERVAL 5 MINUTE +  INTERVAL 30 SECOND 식으로
현재시간 에서 5분 30초 이후에 실행하게뜸 지정 가능
MINUTE 니 SECOND 말고도
YEAR|QUARTER|MONTH|DAY|HOUR|MINUTE|WEEK|SECOND|YEAR_MONTH|DAY|HOUR|MINUTE|WEEK| SECOND | YEAR_MONTH|DAY_HOUR|DAY_MINUTE| DAY_SECOND| HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND
등등 키워드를 넣어 설정할수 있고 + 를 통해 연결 가능 하다. 각각의 키워드에대해선 알아서 찾아보길.
*/

/*일적주기마다 반복 경우*/
EVERY 2 MINUTE /*2분 마다 실행, 다른 키워드 사용가능*/
STARTS '2016-11-17 11:35:00' + INTERVAL 0 MINUTE /*시작 시간을 설정하고  + 를 사용해서 인터벌을 줄수도 있다.*/
ENDS '2016-11-17 12:14:00' /*종료시간 셋팅 미입력시 무한반복*/
ON COMPLETION PRESERVE /*이벤트가 종료된후 이벤트를 남겨둘지에 대한 여부 없을경우 기본 삭제됨.*/

DO
/*실행구문*/
BEGIN
 
  /*변수 할당 SELECT 되는 컬럼 타입과 동일하게 선언*/
  DECLARE P_EVT_SEQ bigint(20);
  DECLARE P_EVT_TYPE varchar(2);
  DECLARE P_EVT_TITLE varchar(300);
  DECLARE P_EVT_CONTENT_PC text;
  DECLARE P_EVT_CONTENT_MO text;
  DECLARE P_EVT_IMG_PATH_PC varchar(200);
  DECLARE P_EVT_IMG_PATH_MO varchar(200);
  DECLARE P_EVT_START_DT varchar(8);
  DECLARE P_EVT_END_DT varchar(8);
  DECLARE P_EVT_AGENT varchar(50);
  DECLARE P_EVT_URL varchar(200);

  /*트랜잭션 시작*/
  START TRANSACTION;
 
  /*주의  :  SELECT 해온 결과를 INTO 로 변수에 할당할때 SELECT COLUMN 값이 NULL 일경우 에러발생*/
  SELECT
    EVT_SEQ
    ,EVT_TYPE
    ,EVT_TITLE
    ,EVT_CONTENT_PC
    ,EVT_CONTENT_MO
    ,EVT_IMG_PATH_PC
    ,EVT_IMG_PATH_MO
    ,DATE_FORMAT(DATE_ADD(DATE_FORMAT(EVT_START_DT,'%Y%m%d'),INTERVAL 1 DAY),'%Y%m%d') EVT_START_DT /*날짜 선택해서 하루 더하는 부분*/
    ,DATE_FORMAT(DATE_ADD(DATE_FORMAT(EVT_END_DT,'%Y%m%d'),INTERVAL 1 DAY),'%Y%m%d') EVT_END_DT /*날짜 선택해서 하루 더하는 부분*/
    ,EVT_AGENT
    ,EVT_URL
    INTO /*변수에 할당*/
    P_EVT_SEQ
    ,P_EVT_TYPE
    ,P_EVT_TITLE
    ,P_EVT_CONTENT_PC
    ,P_EVT_CONTENT_MO
    ,P_EVT_IMG_PATH_PC
    ,P_EVT_IMG_PATH_MO
    ,P_EVT_START_DT
    ,P_EVT_END_DT
    ,P_EVT_AGENT
    ,P_EVT_URL
       
  FROM ONL_EVENT
  WHERE EVT_SEQ = (SELECT EVT_SEQ FROM ONL_EVENT WHERE EVT_TYPE = 'A'           ORDER BY EVT_CREATE_DT DESC LIMIT 1);
 
  /*기존 데이터 변경*/
  UPDATE ONL_EVENT
  SET EVT_STATUS = 3
  WHERE EVT_SEQ = P_EVT_SEQ;
 
  /*새로운 데이터 추가*/
  INSERT INTO ONL_EVENT(
     EVT_TYPE
    ,EVT_TITLE
    ,EVT_CONTENT_PC
    ,EVT_CONTENT_MO
    ,EVT_IMG_PATH_PC
    ,EVT_IMG_PATH_MO
    ,EVT_START_DT
    ,EVT_END_DT
    ,EVT_STATUS
    ,EVT_AGENT
    ,EVT_URL
    ,EVT_CREATE_DT
  )VALUES(
     P_EVT_TYPE
    ,P_EVT_TITLE
    ,P_EVT_CONTENT_PC
    ,P_EVT_CONTENT_MO
    ,P_EVT_IMG_PATH_PC
    ,P_EVT_IMG_PATH_MO
    ,P_EVT_START_DT
    ,P_EVT_END_DT
    ,'2'
    ,P_EVT_AGENT
    ,P_EVT_URL
    ,NOW()
  );
 
COMMIT; /*트랜잭션 종료*/
END /*실행 구문 끝*/
$ DELIMITER ; /*SQL 종료 구분자 변경*/

/*밑에껀 보너스*/

/*이벤트 목록 보기*/
SHOW EVENTS;

/*이벤트 삭제*/
DROP EVENT EVENTTEST;

/*등록된 특정 이벤트 내용보기*/
SHOW CREATE EVENT EVENTTEST;

/*이벤트를 사용하기 위한 MYSQL 셋팅 (서버가 동작중일때)*/
/*-EVENT 사용하기 */

SET GLOBAL event_scheduler = ON;
SET @@global.event_scheduler = ON;
SET GLOBAL event_scheduler = 1;
SET @@global.event_scheduler = 1;


/*-EVENT 사용하지 않기-=*/
SET GLOBAL event_scheduler = OFF;
SET @@global.event_scheduler = OFF;
SET GLOBAL event_scheduler = 0;
SET @@global.event_scheduler = 0;


2016년 11월 10일 목요일

[mysql] date_sub 특정 시간 사이에서 랜덤하게 시간 추출하기.

각종 메크로를 만들다보면 채팅 또는 게시판 글, 댓글이  같은 시간에 입력이 되어 티가 나는 경우가 있다. 그럴때 실제 유저가 한거 처럼 시간을 정해서 처리할 수 있는데

현재의 경우는 특정 게시글, 또는 댓글에 좋아요 를 메크로로 작동하기 에서
메크로 작동시간을 게시글 또는 댓글이 게시된 시간 이후로 현재 시간까지의 시간중 랜덤으로 시간을 랜덤으로 추출하는 쿼리이다.

SELECT 절에 서 서브 쿼리로 추출하기.

SELECT
   COL1,
   COL2,
   COL3,
   .
   .
   .
  ,(SELECT DATE_SUB(NOW(), INTERVAL FLOOR( 1 + RAND() * (TIME_TO_SEC(TIMEDIFF( NOW(), (SELECT C.CMT_CREATE_DT FROM CMT_COMMENT C WHERE C.CMT_COMMENT_SEQ = ${cmt_seq}   <<   특정시간 ))) -1 ) ) SECOND) FROM DUAL)


최대한 보기 좋게 썼는데도 가독성이 너무 떨어진다..
빨간색이 특정 게시물 시간 과 현재시간의 차이를 초로 환산한거다.

즉 값 빨간색 쿼리의 값이 3600 이나왔다고 가정하면

  ,(SELECT DATE_SUB(NOW(), INTERVAL FLOOR( 1 + RAND() * (3600 -1 ) ) SECOND) FROM DUAL)

이제 부터 좀 쉬어보이는듯

범위 랜덤 을 구하려면

(최소값 + RAND() * (최대값 - 최소값)) 이므로

1초부터 3600초 사이를 랜덤하게 뽑은후

FLOOR로 정수화 시킨담에

DATE_SUB(NOW, INTERVAL 값 SECOND) 를 통해 이전시간을 구한다. SECOND 대신

HOUR DATE 등 사용이 가능할꺼다.


정리하면

현재 시간  -  ( (현재 시간 - 특정 게시물 작성시간) >> 랜덤 추출 )

더이상의 자세한 설명은 생략한다.






2016년 10월 24일 월요일

[mysql]CURSOR 사용하기

MYSQL 은 함수 또는 프로시저 내에서 CURSOR 를 제공한다.

CURSOR 루프를 통해 선택된 열 에 특정컬럼에 접근하여 로직을 수행할수 있다.

EX) 특정 팀의 특정 시즌 최근 연승또는 연패 기록을 구하는 경우



DROP FUNCTION IF EXISTS `스키마`.`함수명`;
CREATE FUNCTION `스키마`.`함수명`
--파라미터 셋팅 (팀코드,리그코드,시즌코드,시리즈코드)
(P_T_ID VARCHAR(5) , P_LE_ID INT(11), P_SEASON_ID INT(11), P_SR_ID INT(11)) 
--리턴 타입을 정의한다.

RETURNS varchar(50) CHARSET utf8
BEGIN

   --루프를 다돌았을때 핸들러에서 초기화 해주는변수
   DECLARE done INT DEFAULT FALSE;
   --승패 여부를 담기위한 변수
   DECLARE result  INT DEFAULT 1;
   --이전 승패를 담기위한 변수 0 패 1 승 가 승이기때문에 2로 기본값 셋팅
   DECLARE resultTmp  INT DEFAULT 2;
   --연승인지 연패인지를 담는 문자열변수
   DECLARE winOrLose varchar(5) DEFAULT '';
   --연승 또는 연패 카운트 수
   DECLARE cnt INT DEFAULT 0;
   --현재 이함수가 리턴 해야할 문자열
   DECLARE resultStr varchar(50) DEFAULT '';
   
   -- 선택된 값을 cur 에 셋팅하게끔 정의
   DECLARE cur CURSOR FOR
      
      -- 커서루프에서 셀렉트할 컬럼명 또는 데이터 
      -- 스케줄이 있는 게임테이블에서 
      -- 스코어와 리그,시리즈,시즌아이디 키로 조인하고
      -- 스코어에는 홈팀 원정팀 아이디에 따른 스코어가 있다.
      
      -- 해당팀이 홈일때 홈스코어가 크면 1 원정일때 원정스코어가 크면 1을 셀렉트하는
      -- 구문 요약하면  이겻을 경우 1 지면 0 이 셀렉트됨.
      SELECT 
               IF(B.H_T_ID = P_T_ID,IF(B.H_SCORE > B.V_SCORE ,1,0),IF(B.V_SCORE >                 B.H_SCORE ,1,0))  
      FROM 
      GAME A --게임의 스케줄이 있는 테이블 게임키가 있다.
      INNER JOIN LIVESCORE B ON  A.G_ID = B.G_ID AND B.STATE_SC = 3 --게임키에따         른 스코어 정보 테이블 
      WHERE
      1=1
      AND A.LE_ID = P_LE_ID
      AND A.SR_ID = P_SR_ID
      AND A.SEASON_ID = P_SEASON_ID 
      --파라미터로 받은 P_T_ID 가 홈팀 또는 원정일 때 조건 추가
      AND (A.H_T_ID = P_T_ID OR A.A_T_ID = P_T_ID)
      --최근경기부터 정렬하여 루프를 돌려야한다. 최근 연승 연패 기록이기때문.
      ORDER BY A.G_DT_KR DESC;

   --이부분은 그냥 검색에서 가따씀. 아마도 핸들러에서 로우를 못찾는 익셉션이 일어났을경우 Set 되는거 같음
   DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    
   --커서 열기
   OPEN cur;
   
   --루프 돌리기
   read_loop: LOOP
     
     --선택된 값을 변수에 할당
     FETCH cur INTO result;
     
     -- 로우 마지막 루프를 종료
     IF done THEN
      LEAVE read_loop;

     -- 로우 마지막이 아닐경우
     ELSE
      -- 처음 로우 (resultTmp는 기본값이 2이기때문에 무조건 루프 첫바퀴에 들어옴)
       IF resultTmp = 2 THEN

          -- 연승 연패 문자열 셋팅
          IF result = 1 THEN 
              SET winOrLose = '연승';
          ELSE 
              SET winOrLose = '연패';
          END IF;
           
          --연승 카운트 증가
          SET cnt = cnt + 1;

          -- 템프에 결과 저장
          SET resultTmp = result;
       
       -- 나중 로우 
       ELSE 
          -- 연승이 끊겻을때. 앞에서 초기화 했기 때문에 0 또는 1 의 값이 들어 있다. result           -- 0 = 패 result 1 승
          -- 전 게임 결과와 이번루프에서 뽑아온 결과가 같을경우 연속 카운트 증가
          IF resultTmp = result THEN
           SET cnt = cnt + 1;
          -- 결과가 다르면 루프를 종료
          ELSE 
              LEAVE read_loop;
          END IF;
       
       END IF;
     END IF;
     
     
   --루프 구문 종료  
   END LOOP;
   --커서 닫기
   CLOSE cur;
   
   --리턴할 값 셋팅
   SET resultStr = CONCAT(cnt,winOrLose);
   RETURN resultStr;
END


아주 친절 하게 주석을 일일이 다 달아놓았다. 알아서 필요한대로 응용해서 사용할것.

추가로 mysql 에서의 함수 호출은

select  함수명(파라미터), t.col1,t.col2,.....

from table t
where ...

와 같은 방식으로 호출 하면된다.

[mysql]CURSOR 사용하기

MYSQL 은 함수 또는 프로시저 내에서 CURSOR 를 제공한다.

CURSOR 루프를 통해 선택된 열 에 특정컬럼에 접근하여 로직을 수행할수 있다.

EX) 특정 팀의 특정 시즌 최근 연승또는 연패 기록을 구하는 경우



DROP FUNCTION IF EXISTS `스키마`.`함수명`;
CREATE FUNCTION `스키마`.`함수명`
--파라미터 셋팅 (팀코드,리그코드,시즌코드,시리즈코드)
(P_T_ID VARCHAR(5) , P_LE_ID INT(11), P_SEASON_ID INT(11), P_SR_ID INT(11)) 
--리턴 타입을 정의한다.

RETURNS varchar(50) CHARSET utf8
BEGIN

   --루프를 다돌았을때 핸들러에서 초기화 해주는변수
   DECLARE done INT DEFAULT FALSE;
   --승패 여부를 담기위한 변수
   DECLARE result  INT DEFAULT 1;
   --이전 승패를 담기위한 변수 0 패 1 승 가 승이기때문에 2로 기본값 셋팅
   DECLARE resultTmp  INT DEFAULT 2;
   --연승인지 연패인지를 담는 문자열변수
   DECLARE winOrLose varchar(5) DEFAULT '';
   --연승 또는 연패 카운트 수
   DECLARE cnt INT DEFAULT 0;
   --현재 이함수가 리턴 해야할 문자열
   DECLARE resultStr varchar(50) DEFAULT '';
   
   -- 선택된 값을 cur 에 셋팅하게끔 정의
   DECLARE cur CURSOR FOR
      
      -- 커서루프에서 셀렉트할 컬럼명 또는 데이터 
      -- 스케줄이 있는 게임테이블에서 
      -- 스코어와 리그,시리즈,시즌아이디 키로 조인하고
      -- 스코어에는 홈팀 원정팀 아이디에 따른 스코어가 있다.
      
      -- 해당팀이 홈일때 홈스코어가 크면 1 원정일때 원정스코어가 크면 1을 셀렉트하는
      -- 구문 요약하면  이겻을 경우 1 지면 0 이 셀렉트됨.
      SELECT 
               IF(B.H_T_ID = P_T_ID,IF(B.H_SCORE > B.V_SCORE ,1,0),IF(B.V_SCORE >                 B.H_SCORE ,1,0))  
      FROM 
      GAME A --게임의 스케줄이 있는 테이블 게임키가 있다.
      INNER JOIN LIVESCORE B ON  A.G_ID = B.G_ID AND B.STATE_SC = 3 --게임키에따         른 스코어 정보 테이블 
      WHERE
      1=1
      AND A.LE_ID = P_LE_ID
      AND A.SR_ID = P_SR_ID
      AND A.SEASON_ID = P_SEASON_ID 
      --파라미터로 받은 P_T_ID 가 홈팀 또는 원정일 때 조건 추가
      AND (A.H_T_ID = P_T_ID OR A.A_T_ID = P_T_ID)
      --최근경기부터 정렬하여 루프를 돌려야한다. 최근 연승 연패 기록이기때문.
      ORDER BY A.G_DT_KR DESC;

   --이부분은 그냥 검색에서 가따씀. 아마도 핸들러에서 로우를 못찾는 익셉션이 일어났을경우 Set 되는거 같음
   DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    
   --커서 열기
   OPEN cur;
   
   --루프 돌리기
   read_loop: LOOP
     
     --선택된 값을 변수에 할당
     FETCH cur INTO result;
     
     -- 로우 마지막 루프를 종료
     IF done THEN
      LEAVE read_loop;

     -- 로우 마지막이 아닐경우
     ELSE
      -- 처음 로우 (resultTmp는 기본값이 2이기때문에 무조건 루프 첫바퀴에 들어옴)
       IF resultTmp = 2 THEN

          -- 연승 연패 문자열 셋팅
          IF result = 1 THEN 
              SET winOrLose = '연승';
          ELSE 
              SET winOrLose = '연패';
          END IF;
           
          --연승 카운트 증가
          SET cnt = cnt + 1;

          -- 템프에 결과 저장
          SET resultTmp = result;
       
       -- 나중 로우 
       ELSE 
          -- 연승이 끊겻을때. 앞에서 초기화 했기 때문에 0 또는 1 의 값이 들어 있다. result           -- 0 = 패 result 1 승
          -- 전 게임 결과와 이번루프에서 뽑아온 결과가 같을경우 연속 카운트 증가
          IF resultTmp = result THEN
           SET cnt = cnt + 1;
          -- 결과가 다르면 루프를 종료
          ELSE 
              LEAVE read_loop;
          END IF;
       
       END IF;
     END IF;
     
     
   --루프 구문 종료  
   END LOOP;
   --커서 닫기
   CLOSE cur;
   
   --리턴할 값 셋팅
   SET resultStr = CONCAT(cnt,winOrLose);
   RETURN resultStr;
END


아주 친절 하게 주석을 일일이 다 달아놓았다. 알아서 필요한대로 응용해서 사용할것.

추가로 mysql 에서의 함수 호출은

select  함수명(파라미터), t.col1,t.col2,.....

from table t
where ...

와 같은 방식으로 호출 하면된다.

[OS]리눅스서버 WAS 관련 권한 관리

[Best Practice] Linux 서버 WAS 권한 체계 구축 가이드 리눅스 환경에서 다수의 운영자가 WAS(Tomcat, Nginx 등)를 공동 관리할 때 발생하는 권한 꼬임(Permission Denied) 문제를 방지하기 위한 표준 설정...