Table A (group by 한 값들이 모두 들어있는 테이블)
select '1' from dual union all
select '2' from dual union all
select '3' from dual union all
select '4' from dual union all

Table B (실제 값 가져오는 쿼리)

이런 식으로 group by 했을 때 무조건 나와서 통계 표와 맞춰야 하는 값들 강제 작성 후 left join 

Posted by 知彼知己百戰不殆
,

오류 상황 : 쿼리 실행 시 String 값 하나만 넘기면 되는데 굳이 vo를 생성해서 넘기기도 귀찮아서 String 파라미터를 넘기는데 계속 로그에 parameters : null이 찍힘

원인 : Dao쪽을 살펴보니 selectList(statement , object )가 아니라 selectList(statement)를 호출 중

해결 : selectList(statement , object)로 Dao 메소드 변경

Posted by 知彼知己百戰不殆
,

변동값을 group by 하는 tip

예를 들어 각 나이대별 00 건수 데이터를 뽑고 싶을 때

구분 5년이상 10년이하 10년이상 15년이하 15년이상 20년이하 ~~~
20세 ~ 30세        
30세 ~ 40세        
40세~ 80세        
         

위와 같은 표의 데이터를 뽑을 때 처음에 어떻게 데이터를 뽑아야 할지 머리가 안 돌아갔다.
구분값이 다 변동값인데 이걸 어떻게 group by로 뽑아내지 하다가 문득 든 생각 

20세와 30세를 그룹으로 묶고 30세~40세를 그룹으로 묶어 버리자.

그래서 gruop by를 하기 전 case when 컬럼1 between 20 and 30 then '1'
when 컬럼1 between 30 and 40 then '2' 
...

이런 방식으로 그룹핑을 지어주었다. 그리고 또한 기간도 case when 컬럼2 between 5년 between 10년 then '1'
when 컬럼2 between 10년 and 15년 then '2'

이렇게 변동값을 그룹으로 한정해버리고 쿼리 추출!!

쿼리는 항상 너무 어렵다 ㅠㅠ

Posted by 知彼知己百戰不殆
,

왜 프레임워크를 안 쓰는지 모르겠으나 ㅠㅠ 쌩 java로만 돌리는 환경.
대량 조회 하는 SQL을 thread까지 사용해서 동시에 돌리니 기존에 잘 돌아가던 쿼리도 executeQuery 부분에서 OutOfMemory가 발생함ㅠㅠ

생각한 해결책
1. executeQuery의 Fetch Size 조절(현재는 40,000건씩 fetch)
2. mybatis 프레임워크 도입(Spring을 이용한 mybatis 정보는 상당히 많음 ㅠㅠ)

일단 급한 불부터 꺼야 했기에 1번 해결책으로 Fetch 사이즈를 조절해보았다. 10,000건으로 줄여보았는데도 똑같이 Heap space 에러가 발생하였다. 근데 default fetch를 쓰자니 10건씩이고...10배만 늘리자 타협하여 100건씩 fetch하니 일단은 잘 돌아간다.
하지만, 지금까지 대량건 조회는 Spring에서 rowhandler를 써왔기에 java 코드 안에 SQL이 들어가 있어서 관리하기도 불편해서 이번 기회에 java mybatis without Spring 을 도입해보기로 했다.

오류 내용
- AbstractMethodError : Method oracle/jdbc/driver/OracleResultSetImpl.isClosed()Z is abstract
Exception in thread "main" java.lang.AbstractMethodError: Method oracle/jdbc/driver/OracleResultSetImpl.isClosed()Z is abstract
        at oracle.jdbc.driver.OracleResultSetImpl.isClosed(OracleResultSetImpl.java)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:68)
        at cohttp://m.sun.proxy.$Proxy2.isClosed(Unknown Source)
        at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:364)
        at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:337)
        at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:310)
        at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:202)
        at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:66)
        at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:80)
        at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:65)
        at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:336)
        at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:158)
        at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:110)
        at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:90)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:154)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:142)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:75)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:69)
        at dao.(~~~~~). (~~~~~) ( (~~~~~) .java:9)
        at logic.Main.main(Main.java:74)

구글링 해보니 ojdbc 버전이 안 맞아서 발생하는 오류라는 것 확인. Oracle 홈페이지에 들어가 현재 업무 환경에 맞는 jdbc는 ojdbc6.jar란 것을 확인. ㅡㅡ 시스템은 개판이면서 현재 ojdbc14를 사용 중
출처: https://www.oracle.com/database/technologies/faq-jdbc.html

 

Oracle JDBC Frequently Asked Questions

For byte data, there are three Oracle SQL types: VARCHAR2, LONG and CLOB. VARCHAR2 data is of limited length, is stored directly in a column, and is transmitted to the server in inline packets. LONG data has a much larger limit (2 Gigibytes), is stored via

www.oracle.com

https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc6/11.2.0.4

메이븐 리포지토리에 들어가 ojdbc6.jar 다운로드 후 jar파일 적용하니 mybatis로 쿼리가 동작한다!
(처음부터 rowhandler를 만들면서 테스트 하기엔 무리라고 판단되어 정말 간단한 select 1 from dual 쿼리로 조회)

File list
1. xml 패키지 밑에 mybatis-config.xml (원하는 이름으로 해도 되는지는 추후 확인 필요)
2. sqlMappers 패키지 밑에 "원하는이름"-mapper.xml (SQL 작성 파일)
3. database 패키지 밑에 "원하는이름" .java (getSqlSession() 메소드 존재)
4. dao 패키지 밑에 "원하는이름" .java(mapper id로 쿼리 실행)

to-do : 추후 정보 제거한 핵심만 간추린 소스 업로드

Posted by 知彼知己百戰不殆
,

A조건 : 건수
B조건 : 건수
C조건 : 건수

위와 같이 각 조건별로 건수를 한 방에 출력하고 싶을 때 

select count(case when ~~~~ then 1 end ) as column1
        , count(case when ~~~~ then 1 end ) as column2  
        , count(case when ~~~~ then 1 end ) as column3
  from 테이블명

Posted by 知彼知己百戰不殆
,

0원 초과 1만원 미만 데이터를 구하고 싶은데 >, <를 쓰자니 쿼리가 길어질 거 같고 간단한 건 뭐 없을까 고민하다가 검색

NOT BETWEEN A AND B
=> A 미만 B 초과  

Posted by 知彼知己百戰不殆
,

jar파일 버전을 낮춘 후 다시 DB접속을 시도했으나 이번엔 다음과 같은 오류가 발생했다. ㅠㅠ

원인 : 서버에서 인증서 유효성을 확인할 수 없음

해결 : datasource 마지막 줄에 신뢰 유효성을 확인하기 위한 인증서 검사 무시 여부를 true로 설정
SQLServerDataSource ds = new SQLServerDataSource();
ds.set ~~~
ds.setTrustServerCertificate(true);

https://learn.microsoft.com/ko-kr/dotnet/api/microsoft.data.sqlclient.sqlconnectionstringbuilder.trustservercertificate?view=sqlclient-dotnet-standard-5.1

 

SqlConnectionStringBuilder.TrustServerCertificate 속성 (Microsoft.Data.SqlClient)

채널이 암호화될 때 신뢰의 유효성을 검사하기 위한 인증서 체인 검사가 무시되는지 여부를 나타내는 값을 가져오거나 설정합니다.

learn.microsoft.com

Exception in thread "main" com.microsoft.sqlserver.jdbc.SQLServerException: "encrypt" 속성이 "true"(으)로 설정되고 "trustServerCertificate" 속성이 "false"(으)로 설정되었지만 드라이버가 SSL(Secure Sockets Layer) 암호화를 사용하여 SQL Server에 대한 보안 연결을 설정할 수 없습니다. 오류: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target. ClientConnectionId:14656c10-20ff-4388-924f-fba7692ec81e
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:4026)
        at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1954)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:3552)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:3172)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:3014)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:1836)
        at com.microsoft.sqlserver.jdbc.SQLServerDataSource.getConnectionInternal(SQLServerDataSource.java:1489)
        at com.microsoft.sqlserver.jdbc.SQLServerDataSource.getConnection(SQLServerDataSource.java:99)
        at database.SQLServerLMSDbConn.getConnection(SQLServerLMSDbConn.java:20)
        at database.DBConnectionFactory.<init>(DBConnectionFactory.java:15)
        at database.Main.main(Main.java:21)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1497)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
        at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1843)
        ... 9 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
        at sun.security.validator.Validator.validate(Validator.java:260)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:105)
        at com.microsoft.sqlserver.jdbc.HostNameOverrideX509TrustManager.checkServerTrusted(SQLServerTrustManager.java:88)
        at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:922)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1479)
        ... 17 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145)
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
        ... 25 more



Posted by 知彼知己百戰不殆
,

시스템 모니터링 자동화를 하며 지난 번에 구축한 SQL Server LMS 발송 DB와 내가 만든 모니터링 자동화 프로그램을 연결시켜보려고 했다. 그러나 연동 테스트 시 아래와 같은 오류가 발생하였다.

Exception in thread "main" java.lang.UnsupportedClassVersionError: com/microsoft/sqlserver/jdbc/SQLServerDataSource has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at database.SQLServerLMSDbConn.getConnection(SQLServerLMSDbConn.java:12)
        at database.DBConnectionFactory.<init>(DBConnectionFactory.java:15)
        at database.Main.main(Main.java:21)

필요사항
- 로직 소스는 최대한 건드리지 않고 내가 필요한 DB connection을 어떤 DB든지 쉽게 갖다 쓰고 싶다.

그래서 예전부터 적용해보고 싶었던 DB connection을 가져오는 factory 패턴을 적용했고, Oracle은 문제가 되질 않았다. 하지만 SQL Server는 jdbc가 달라서 MS 홈페이지에서 다운받아서 External jar로 따로 넣어주었고, MS에서 제공한 샘플 코드를 보고 했는데도 위와 같은 오류가 발생하였다.
SQL server jdbc 다운로드 url:https://learn.microsoft.com/ko-kr/sql/connect/jdbc/download-microsoft-jdbc-driver-for-sql-server?view=sql-server-ver16

 

다운로드 - JDBC Driver for SQL Server

Microsoft JDBC Driver for SQL Server를 다운로드하여 SQL Server 및 Azure SQL Database에 연결하는 Java 애플리케이션을 개발합니다.

learn.microsoft.com

원인 : 현재 java 버전엔 위 jdbc 버전이 너무 높음
https://learn.microsoft.com/ko-kr/sql/connect/jdbc/system-requirements-for-the-jdbc-driver?view=sql-server-ver16

해결 : 다운받은 zip파일 내부에 jdbc 버전이 2개가 있어서 숫자(버전)이 낮은 거로 jar 파일 교체

 

시스템 요구 사항 - JDBC Driver for SQL Server

JDBC 드라이버 시스템 요구 사항을 찾습니다. 지원되는 Java, 운영 시스템 및 데이터베이스 버전을 포함합니다.

learn.microsoft.com

 

Posted by 知彼知己百戰不殆
,

빨간 박스부분(Agent 부분)이 활성화 되어있지 않다면 

SQL Server 관리자메뉴에 들어가서 빨간 네모박스 서비스를 수동 실행해야 함

Posted by 知彼知己百戰不殆
,

SQL Server 프로시저는 아래와 같은 방식으로 생성.
프로시저 실행은 EXEC DB명.스키마명.프로시저명

CREATE PROCEDURE 프로시저명 
AS
BEGIN
SET NOCOUNT ON; --프로시저 성능향상

DECLARE @VIRABLE Table (
          REG_EMP_NO          CHAR(10)  DEFAULT '604411'
)

BEGIN TRY
   INSERT INTO @VIRABLE (REG_EMP_NO)
   select EMP_NO  from openquery(DB Link명,'오라클 쿼리')
END TRY
BEGIN CATCH
   오류났을 때 insert든, 뭔가 처리할 쿼리
END CATCH

END

 

P.S : try-catch는 굳이 안 써도 상관없음. 난 그냥 내가 오류났을 때 빠른 대처를 위해 로직 작성하느라 저렇게 한 것

Posted by 知彼知己百戰不殆
,