열 조회
이전 포스팅에서는 직접 변수 타입을 지정해 테이블의
열 타입과 바인딩해서 쿼리문을 사용했다.

확장성을 위해 초기에 테이블을 파싱을 해서 어떤 열 정보를 갖고 있는지
파악 후, 열의 타입을 알아내 변수를 바인딩하는 작업이 바람직하다.
그러기 위해서 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 |
문자, 정수, 실수 타입를 스위치문을 사용해
맞는 타입으로 바인딩 후에 벡터에 저장하는 모습이다.