MSSQL 서버에 사용자 PASSWORD 데이터가 'SHA2_xxx'방식으로 암호화되어 저장되있습니다.

 

그럼 php로 입력받은 id와 password값을 처리하기 위해서 아래와 같은 쿼리를 날려 준 후 결과값이 있으면 로그인 허용을 해주면 될 것입니다.

select * from 사용자정보
where 유저id = $id
and 비밀번호 = $password

하지만 위처럼  $password 값이 암호화 처리되지 않은 값이라면 쿼리를 아래처럼 수정해야합니다.

select * from 사용자정보
where 유저id = $id
and 비밀번호 =  HASHBYTES('SHA2_256' , $password)

하지만 sql 수준의 hashbytes 함수의 return값은 binary형(0x.....)식 입니다.

만약 사용자정보 테이블의 유저id 컬럼이 binary형식으로 저장이 안 되어있는 경우라면 아래처럼 character 형태로 convert를 해줄 수도 있습니다.

select * from 사용자정보
where 유저id = $id
and 비밀번호 =  CONVERT(NVARCHAR(32),HASHBYTES('SHA2_256' , $password))

아니면 php 수준에서 아래와 같이 hash()함수로 처리한 뒤에 쿼리로 넘겨주는 방법도 활용할 수 있습니다.

$password_hash = hash("sha256", $password)

 

TOP, OFFSET 또는 FOR XML을 함께 지정하지 않으면 뷰, 인라인 함수, 파생 테이블, 하위 쿼리 및 공통 테이블 식에서 ORDER BY 절을 사용할 수 없습니다.

 프로시저 내에서 union 되는 쿼리를 임시테이블(with)로 작성하여 처리하던 중에 위와 같은 에러가 발생했습니다.

문제가 발생한 쿼리 구조는 아래와 같습니다.

;WITH '임시테이블' AS (
SELECT 
    --top 100 percent
    A.aaa
    A.bbb
    A.ccc
FROM	
	AAA AS A
WHERE	...			   

UNION ALL

SELECT
    --top 100 percent
    B.aaa
    B.bbb
    B.ccc
FROM	
	BBB AS B
WHERE	...

ORDER BY B.aaa DESC, B.ccc DESC
)
select * from '임시테이블'

 Union 한 두 select 쿼리 하단에 order by 구문으로 인해 발생한 에러입니다.

쿼리에 select 다음에 주석처리 되있는 'top 100 percent'를 작성해주면 위 에러는 해결이 됩니다.

 

 * 참고로 top N percent 퀴리는 예를 들어 select 쿼리 결과 row수가 400개 일 때 top 20 percent 쿼리를 작성해주면 400개의 20%인 80개의 결과. top 20으로 작성하면 20개의 결과만 출력됩니다

키워드 'with' 근처의 구문이 잘못되었습니다. 이 문이 공통 테이블 식이거나, xmlnamespaces 절이거나, 변경 내용 추적 컨텍스트 절인 경우에는 이전 문을 세미콜론으로 종료해야 합니다.

  MSSQL에서 임시테이블(with)쿼리를 작성하다보면 위와 같은 에러가 종종 발생합니다.

해결은 허무할 만큼 에러 메시지에 간단하게 나와있습니다

'With'앞에 세미콜론(;)만 붙여주면 됩니다.

-- WITH 앞에 세미콜론을 붙여주세요 --
;WITH '임시테이블명' AS (
			SELECT *
			  FROM	A   
			
			UNION ALL
			
			SELECT *			 
			  FROM	B
			 )
     select * from '임시테이블명'

  회사의 API서버가 무려 ASP CLASSIC으로 되어 있었습니다.

같은 서버에 다행히 PHP도 설치가 되어있어서, 서버 구성에 손대지 않고 API를 이 참에 다 갈아엎고자 PHP로 작업을 진행하고 있습니다.

 보통 mysql(maria db)과 많이 사용하여서 Mssql과 연동하는 작업은 전무했던터라 자주사용하는 소스를 공유드리고자 합니다.


1. DB 접속정보를 갖고 있는 config.php

 config.php를 생성하여 상수로 자주 사용할 정보들을 define 해줍니다.

<?php
	// IP는 예시이므로 사용하실 IP로 변경해주세요
    // DB 주소 (메인 DB와 테스트 DB를 사용)
    define('DB_MAIN','192.100.100.111');
    define('DB_TEST','192.100.100.112');

	// 데이터베이스 이름
    define('DB_EMPL','사원관리DB');
    define('DB_SALARY','급여관리DB');

	// DB 접속 정보
    define('DB_ID_ADMIN','id_admin');
    define('DB_PW_ADMIN','pw_admin');

	// 인코딩 
    define('DB_CHARACTERSET','UTF-8');

?>

2. config.php를 include 해주고 같은 경로에 select.php 라는 예제 파일을 아래와 같이 작성해보겠습니다.

각 코드별로 주석을 기재하였으나 어려우신 분들은 언제든 댓글 달아주세요 :)

<?php
    header('Content-Type: text/html; charset=utf-8');

    // 테스트할 때 모든 에러를 출력해주는게 좋습니다.
    error_reporting( E_ALL ); 
    ini_set( "display_errors", 1 );

    // DB 연결과 관련한 상수에 대한 값을 불러와줍니다.
    // 예를들어 select.php, update.php 등의 CRUD 작업페이지가 여러개라 할 때, DB의 접속 정보가 변경된 상황이 발생할 경우 
    // Config.php만 변경해주면 됩니다. 
    include 'config.php';
?>

<html>
    <head>
    <meta charset="utf-8">
    </head>

    <body>
        <?php
        // 연결할 MSSQL 서버에 대한 정보를 입력해줍니다.
        $serverName = DB_TEST;
        $connectionOptions = array(
            "database" => DB_EMPL,        // 데이터베이스명
            "uid" => DB_ID_ADMIN,             // 유저 아이디
            "pwd" => DB_PW_ADMIN,             // 유저 비번
            "CharacterSet" => DB_CHARACTERSET // 한글꺠짐 방지!
        );

        
        // --------------------------------------------------------------------
        // SQL 조건문에 변수를 넣을 경우 활용 하는 방법 
        // 1) 변수에 그대로 값 대입
        $F_EMPL_CODE = '사번';
        $F_START_DATE = '날짜';

        // 2) URL에 입력된 변수를 불러올 경우
        // 테스트는 GET / API 호출은 POST 사용
        // ex) http://localhost/select.php?EMPL_CODE=사번&START_DATE=데이타
        $F_EMPL_CODE = $_GET['F_EMPL_CODE'];
        $F_START_DATE = $_GET['F_START_DATE'];
        // --------------------------------------------------------------------

        // 결과값을 받을 변수
        $F_START_TIME = '';

        // DB 연결
        $dbconn = sqlsrv_connect($serverName, $connectionOptions); 
        // 연결 확인
        if ($dbconn) {
            echo "DB 연결 완료<br><hr>";
        }else{
            echo "DB 연결 실패<Br>";
            die( print_r( sqlsrv_errors(), true));
            echo "<hr>";
        }

        // 쿼리 작성
        $query = "SELECT * FROM 출근기록테이블
                WHERE 사번 = '$F_EMPL_CODE' and 날짜 = '$F_START_DATE'"; 

        // 쿼리를 실행하여 statement 를 얻어온다
        $params = array();
        $options = array( "Scrollable" => SQLSRV_CURSOR_KEYSET );
        $stmt = sqlsrv_query($dbconn, $query, $params, $options );

        // 쿼리 결과 'row' 수를 반환해준다
        $row_count = sqlsrv_num_rows($stmt);
        
        // 결과가 1개 이상 있다면?
        if($row_count >= 1){
            // statement 를 돌면서 필드값을 가져온다
            while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))
            {   
                //  출력할 $row['컬럼명']; 형태로 출력해줌
                $F_START_TIME = (string) $row['근무시간'];
                echo $F_START_TIME."<Br>";
            }   
        }else{
            echo "조회된 정보가 없습니다";
        } 
        
        // 데이터 출력후 statement 를 해제한다
        sqlsrv_free_stmt($stmt);    

        // 데이터베이스 접속을 해제한다
        sqlsrv_close($dbconn);
        ?>
    </body>
</html>

 

SELECT TOP 100, 컬럼1, 컬럼2, * FROM 테이블이름;
SELECT TOP 1000 * FROM 테이블이름;

 mysql에선 'limit n'으로 쿼리를 작성하지만 mssql은 select 바로 다음에 'TOP N(숫자)'으로 쿼리를 작성해주면 상위 N개의 결과값이 검색된다.

 생각나서 찾아보니 하위 N개에 대한 쿼리는 없는 듯... order by desc/asc로 처리해주면 된다.

개발환경

  • Windows10 OS
  • SSMS(SQL Server Management Studio) 14버전

 예를 들어서 '사원'의 정보를 갖고 있는 테이블이 있을 때, 사원 테이블에 select/Insert/delete/update 쿼리를 작성or테스트 할 경우가 발생한다.

 단순하겐 테이블의 속성들을 조회하여 일일이 쿼리문을 작성해주면 되지만 시간이 정말 오래걸릴 수도 있고 귀찮은 작업이 될 수 있지만 SSMS에서는 테이블 스크립팅 이라는 기능을 제공하여 테이블의 속성에 맞는 쿼리를 자동으로 생성해 주는 편리한 기능을 제공한다.

데이터베이스 > 테이블 > 작업할 테이블에서 마우스 우클릭 > 새 쿼리 편집기 창 클릭

위 화면 처럼 작업할 테이블을 마우스 우클릭으로 선택 > 테이블 스크립팅 메뉴에 마우스 오버를 해보면 작업할 쿼리를 선택할 수 있다.

개인적으로 insert와 update 쿼리를 자주 사용하는데 insert 테이블 스크립팅을 생성해보면

테이블 속성에 맞는 INSERT 문이 자동으로 생성된다

INSERT 쿼리 문이 생성되며 Values에 친절하게 데이터 타입도 명세되어있으며, 이 부분에 입력할 데이터만 작성해주면 된다

+ Recent posts