02
03

열 조회

이전 포스팅에서는 직접 변수 타입을 지정해 테이블의

열 타입과 바인딩해서 쿼리문을 사용했다.

 

변수 선언 후 테이블 열 정보와 바인딩 SQLBindCol()

 

확장성을 위해  초기에 테이블을 파싱을 해서 어떤 열 정보를 갖고 있는지

파악 후, 열의 타입을 알아내 변수를 바인딩하는 작업이 바람직하다.

그러기 위해서 SQLDescribeCol 함수가 있다.

 

그전에 열 정보를 얻기 위해서는 해당 열의 인덱스가 필요하므로

SQLNumResultCols() 함수로 열의 개수를 반환받는다.

 

1
2
3
SQLRETURN SQLNumResultCols(  
     SQLHSTMT        StatementHandle, //명령핸들
     SQLSMALLINT *   ColumnCountPtr); // 반환 버퍼 포인터
cs

 

총 열의 개수를 알아냈으니 열 인덱스에 맞게 열의 정보를 얻어오면 된다. 

 

1
2
3
4
5
6
7
8
//열 총 사이즈
SQLNumResultCols(handle_stmt, &총 열수);
 
for (int 열위치 = 1; 열위치<= 총 열수; 열위치++)
    {
        SQLDescribeCol(열위치)
    }
 
cs

 

위 방식으로 조회하면 된다. (의사 코드)

 

SQLDescribeCol

 

Select문에 의해 생성된 결과로 표시된 열에 대한 결과, 정보를 반환한다.

중요한 것은 이 SQLDescribeCol를 호출하기 전에 SQLPrepare(), 

또는 SQLExecDirect() 함수를 호출해야 된다는 것이다.

 

1
2
3
4
5
6
7
8
9
10
cㅊSQLRETURN SQLDescribeCol(  
      SQLHSTMT       StatementHandle, //명령문 핸들
      SQLUSMALLINT   ColumnNumber, //1부터 시작하는 데이터의 열수
      SQLCHAR *      ColumnName, //null로 끝나는 열 이름 버퍼
      SQLSMALLINT    BufferLength,//버퍼, 문자의 길이
      SQLSMALLINT *  NameLengthPtr,//문자 수를 반환할 버퍼의 포인터
      SQLSMALLINT *  DataTypePtr,  //데이터 형식 반환 포인터
      SQLULEN *      ColumnSizePtr, // 열 크기 포인터
      SQLSMALLINT *  DecimalDigitsPtr, //열의 소수 자릿수 포인터
      SQLSMALLINT *  NullablePtr);  //출력 열이 Null 허용 여부 
cs

 

명령 핸들과 포인터를 매개변수로 열에 대한 여러 정보를 반환해준다.

이러한 정보와 갖은 내용의 구조체를 만들어서

그 구조체를 vector로 저장하도록 했다.

 

 

데이터베이스의 인덱스는 0이 아닌 1부터 시작한다. 반복문도

이 점을 유념해서 사용해야 한다. 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
bool KODBC::Execute_TableSet(const TCHAR* tablename)
{
    Table_Info table;
    table.table_name = tablename;
    std::wstring statement = L"select * from ";
    statement += tablename;
 
    SQLRETURN ret = SQLExecDirect(handle_stmt, (SQLTCHAR*)statement.c_str(), SQL_NTS);
    if (ret != SQL_SUCCESS)
    {
        Check();
        return false;
    }
 
    //결과집합의 콜 열수를 반환함
    SQLNumResultCols(handle_stmt, &table.table_col_num);
    //데이터 베이스는 행이 0이 아닌 1부터 시작함
    for (int icol = 1; icol <= table.table_col_num; icol++)
    {
        //열 정보 구조체 생성
        Table_ColumnInfo column;
        //행 수 
        column.col_num = icol;
        //열 이름 만큼 사이즈
        int col_size = _countof(column.col_name);
 
        /*SQLDescribeCol 결과 집합의 한 열에 대해 결과 설명자-
        열 이름, 형식, 열 크기, 10 진수 숫자 및 null 허용 여부를 반환 합니다. */
        SQLDescribeCol(handle_stmt,
            icol,
            column.col_name,
            col_size,
            &column.col_name_ptr,
            &column.col_data_type,// 데이터형
            &column.col_size_ptr,
            &column.col_decimal_ptr, // 10진수 자리수
            &column.col_nullable);// NULL 허용여부
        table.table_data.push_back(column);
    }
}
cs

 

이렇게 해서 ODBC의 SQLDescribeCol() 를 사용해

모든 데이터베이스의 테이블의 열의 정보를 알아내는 방법을 알아보았다.

왜 이 함수를 사용하냐면,

 

Select와 같은 sql 쿼리문 명령어를 사용할 때 필요한 변수 타입 바인딩을

사전에 알아낸 열의 정보를 활용해 바인딩을 한다면,

추후에 변경사항이 있어도 맞는 변수 타입으로 바인딩해주는,

유지보수성이 있는 프로그래밍이 가능하다.    

 

아래는 C타입 데이터 타입과 SQL 데이터 타입 비교표이다. 

 

SQL 타입 ID
SQL 데이터 타입 C 타입 ID ODBC C typedef C 데이터 타입
SQL_CHAR CHAR(n) SQL_C_CHAR SQLCHAR * unsigned char *
SQL_VARCHAR VARCHAR(n) SQL_C_CHAR
SQL_WCHAR WCHAR(n) SQL_C_WCHAR SQLWCHAR * wchar_t *
SQL_WVARCHAR VARWCHAR(n) SQL_C_WCHAR
         
    SQL_C_TCHAR SQLTCHAR *  
         
SQL_BIGINT BIGINT SQL_C_SBIGINT SQLBIGINT _ _int64
SQL_INTEGER INTEGER SQL_C_SLONG SQLINTEGER long int
SQL_SMALLINT SMALLINT SQL_C_SSHORT SQLSMALLINT short int
SQL_TINYINT TINYINT SQL_C_UTINYINT SQLCHAR unsigned char
         
SQL_REAL REAL SQL_C_FLOAT SQLREAL float
SQL_FLOAT FLOAT(p) SQL_C_DOUBLE SQLFLOAT double
SQL_DOUBLE DOUBLE SQLDOUBLE
         
SQL_BINARY BINARY(n) SQL_C_BINARY SQLCHAR * unsigned char *
SQL_VARBINARY VARBINARY(n) SQL_C_BINARY
         
SQL_TYPE_DATE DATE SQL_C_TYPE_DATE SQL_DATE_STRUCT struct tagDATE_STRUCT
SQL_TYPE_TIME TIME(p) SQL_C_TYPE_TIME SQL_TIME_STRUCT struct tagTIME_STRUCT
SQL_TYPE_TIMESTAMP TIMESTAMP(p) SQL_C_TYPE_TIMESTAMP SQL_TIMESTAMP_STRUCT struct tagTIMESTAMP_STRUCT

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
}
        //변수 타입 바인딩
        SQLLEN lTemp = 0;
        TCHAR szData[100][21= { 0, };
        int   iData[100];
        Table_Record record_data;
        //모든 열만큼 돌면서 변수 바인딩
        for (int iBind = 0; iBind < table.table_data.size(); iBind++)
        {
            switch (table.table_data[iBind].col_data_type)
            {
            case SQL_WCHAR://문자열 타입일때,
            case SQL_WVARCHAR: {
                Table_Field data;
                data.field_data_type = SQL_UNICODE;
                ret = SQLBindCol(handle_stmt, iBind + 1,
                    SQL_UNICODE,
                    szData[iBind],
                    sizeof(szData[iBind]),
                    &lTemp);
                if (ret != SQL_SUCCESS)
                {
                    Check();
                    return false;
                }
                record_data.record.push_back(data);
            }break;
            case SQL_INTEGER: {
                Table_Field data;
                data.field_data_type = SQL_INTEGER;
                ret = SQLBindCol(handle_stmt, iBind + 1,
                    SQL_INTEGER,
                    &iData[iBind],
                    0,
                    &lTemp);
                if (ret != SQL_SUCCESS)
                {
                    Check();
                    return false;
                }
                record_data.record.push_back(data);
            }break;
            case SQL_REAL: {
                Table_Field data;
                data.field_data_type = SQL_C_FLOAT;
                ret = SQLBindCol(handle_stmt, iBind + 1,
                    SQL_C_FLOAT,
                    &iData[iBind],
                    0,
                    &lTemp);
                if (ret != SQL_SUCCESS)
                {
                    Check();
                    return false;
                }
                record_data.record.push_back(data);
            };
            }
        
        }
        std::cout << "" << std::endl;
}
cs

 

문자, 정수, 실수 타입를 스위치문을 사용해

맞는 타입으로 바인딩 후에 벡터에 저장하는 모습이다. 

COMMENT