Q.

SELECT 조회를 수행하면서 조회 결과로 출력되는 데이터집합의 총 ROW수를 어떻게 구해야할까? 

 

 

A.

  • 다른 컬럼을 조회하면서 동시에 결과 집합의 총 행 수를 구하려면 COUNT() 함수와 윈도우 함수를 함께 사용할 수 있다. 
SELECT
    column1,
    column2,
    COUNT(*) OVER () AS total_rows
FROM
    your_table
WHERE
    your_condition;

 

 

  • your_table은 대상 테이블이고, your_condition은 원하는 행을 선택하기 위한 조건이다. 
  • 이 쿼리는 your_table에서 your_condition을 만족하는 각 행에 대해 column1과 column2를 조회하면서, 동시에 전체 행 수를 나타내는 total_rows를 반환한다. 

 

 

 

 


 

 

 

 

COUNT(*) OVER () 란? 


  • COUNT(*) OVER ()는 SQL에서 사용되는 윈도우 함수(Window Function) 중 하나로, 전체 결과 집합의 총 행 수를 각 행에 포함된 결과로 반환하는데 사용된다. 
  • 이 함수는 각 행에 동일한 값을 부여하며, 그 값은 전체 결과 집합의 행 수다.
  • 즉, COUNT(*)는 각 행이 속한 전체 결과 집합의 행 수를, OVER ()는 윈도우 함수가 전체 결과 집합에 대해 적용되도록 지정한다.

 

 

 

 


 

 

 

 

그 외의 윈도우 함수(Window Function)


 

  • SQL에서 사용되는 윈도우 함수는 다양하며, 데이터를 파티션별로 나누고 정렬된 순서대로 처리하는데 사용된다. 

 

 

 

ROW_NUMBER(): 결과 집합 내에서 각 행에 대한 순서 번호를 할당합니다.
SELECT
    column1,
    column2,
    ROW_NUMBER() OVER (ORDER BY some_column) AS row_num
FROM
    your_table;



 

 

RANK(): 결과 집합 내에서 값이 동일한 행을 하나의 등급으로 묶어 순서 번호를 할당합니다. 같은 값이 여러 번 나타날 경우 같은 등급이 부여됩니다.
SELECT
    column1,
    column2,
    RANK() OVER (ORDER BY some_column) AS rank_num
FROM
    your_table;



 

 

DENSE_RANK(): RANK()와 비슷하지만, 같은 값이 여러 번 나타날 경우 중복된 등급이 부여되지 않습니다.
SELECT
    column1,
    column2,
    DENSE_RANK() OVER (ORDER BY some_column) AS dense_rank_num
FROM
    your_table;

 

 

 

SUM() OVER(): 결과 집합 내의 각 행에 대해 누적 합계를 계산합니다.
SELECT
    column1,
    column2,
    SUM(column2) OVER (ORDER BY some_column) AS cumulative_sum
FROM
    your_table;




 

AVG() OVER(): 결과 집합 내의 각 행에 대해 평균을 계산합니다.

 

SELECT
    column1,
    column2,
    AVG(column2) OVER (ORDER BY some_column) AS average
FROM
    your_table;



 

 

LEAD(): 현재 행 다음에 나오는 값을 가져옵니다.
SELECT
    column1,
    column2,
    LEAD(column2) OVER (ORDER BY some_column) AS next_value
FROM
    your_table;

 

 

 

LAG(): 현재 행 이전에 나오는 값을 가져옵니다.
SELECT
    column1,
    column2,
    LAG(column2) OVER (ORDER BY some_column) AS previous_value
FROM
    your_table;



 

 

 

 

 

 

 

 

 

 

Q.

스프링에서 서비스에서 쿼리에 보낼 변수를 임의 지정후 매퍼를 호출할때 @param을 붙여야 하는 이유가 뭘까?  왜 @param을 붙이지 않으면 변수를 못찾는 걸까? 

 

 

 

A.


  • 스프링에서 서비스에서 쿼리에 보낼 변수를 임의로 지정하고 매퍼를 호출할 때, @Param 어노테이션을 사용하는 이유는 MyBatis와 관련이 있다.
  • MyBatis는 SQL 쿼리를 실행할 때, 매개변수를 명시적으로 지정하지 않으면 자동으로 매핑을 수행한다.
  • 그래서 메서드의 매개변수가 하나일 때는 @Param 어노테이션을 사용하지 않아도 MyBatis가 매개변수를 찾아 매핑할 수 있습니다.
  • 하지만 메서드의 매개변수가 여러 개일 경우에는 MyBatis가 어떤 매개변수를 사용하여 SQL 쿼리의 파라미터로 매핑해야 하는지 알 수 없다.
  • 따라서 @Param 어노테이션을 사용하여 명시적으로 어떤 매개변수를 어떤 파라미터에 매핑해야 하는지 알려주는 것이 필요한 것이다.

 

 


 

 

 

  • 예를 들어, 다음과 같은 메서드 시그니처가 있다고 가정해본다.
public void updateData(String name, int age);

 

 

  • 이 경우에는 다음과 같이 MyBatis XML에서 쿼리를 작성할 수 있다.
<update id="updateData" parameterType="map">
    UPDATE your_table
    SET name = #{name},
        age = #{age}
</update>

 

 

 

  • 하지만 이때, MyBatis는 어떤 매개변수를 name에, 어떤 매개변수를 age에 매핑해야 하는지 알 수 없다.
  • 이런 경우에 @Param 어노테이션을 사용하여 메서드의 각 매개변수에 명시적으로 이름을 부여하여 사용한다.
public void updateData(@Param("name") String name, @Param("age") int age);

 

 

 

 

 

 

 

 

 

 

[Spring] @param 사용이유

public void countQuery(@Param("name")String parameter); 이렇게 @Param 어노테이션을 붙이면 본인이 원하는 명으로 mapper에서 사용할 수 있다. 위와 같은 경우는 #{name}이 되겠다. 사실 위의 코드같은경운 파라미

popo015.tistory.com

 

 

 

 

 

 

 

 

 

  • if~ else if 조건문의 공식은 다음과같다고 배웠다. 

 

  • 그러나 가끔 if 조건문을 작성하다가 조건의 경우와 가짓수가 명확해서 마지막 조건을 else if로 끝맺는 경우가 있었다.
  • 주로 조건에 해당하지않는 예외처리가 없는 경우 이랬다. 
  • 그렇다고 switch 문을 쓰기에도 적절하지않아 어떻게 해야하나 고민했다. 

 

  • 간단한 예시다.
  • 위와같이 코드를 작성후 컴파일하거나 실행해도 문제가 없어서 찜찜하지만 그대로 코드를 작성하곤했다.
  • 회사차원에서 코드 리뷰를 하거나 사수분이 여유가 있었다면 여쭤봤을텐데 안타깝게도 모두 해당하지않아서 매번까먹었다.
  • 그러나 우리의 GPT 선생님이 계시므로 생각난김에 물어봤다. 

 

 

 

 

 

 

 

가능은 하다.

 

  • else if 블록을 사용하여 여러 조건을 처리할 때, 마지막 else 블록이 없더라도 코드는 여전히 올바르게 동작할 수 있습니다. 마지막 else 블록은 선택적이며, 모든 if 또는 else if 조건에 맞지 않을 때 실행되는 기본 동작을 정의하는 역할을 합니다.
  • 따라서, 아래와 같이 else 블록이 빠져도 코드는 성립합니다:

 

 


 

하지만 논리적 명확성은 떨어질 수 있다. 

  • 하지만 else 블록을 빼게 되면, 위의 코드에서 num이 50 이하인 경우에 대한 처리가 없으므로 모든 경우에 대한 명시적인 처리가 없게 됩니다.
  • 따라서 프로그램의 논리를 명확하게 전달하기 위해 가능한 모든 경우에 대한 처리를 포함하는 것이 중요합니다.




 

 

 

 

 

 

시작하며

짧은 사이드 프로젝트를 하면서 내 로컬에서만 올렸다 내렸다 하는 단계를 지나 개발서버를 동작시켜보는 경험을 하게 되었다. 그 과정에서 푸티(putty)를 사용해보았는데 복기할겸, 다음 사용시 참고할겸 기록을 남겨본다.  

 

 

 

 

푸티(Putty)를 이용해 프로젝트를 개발서버에 올리기
  • 우선 가장 최신화된 프로젝트를 개발서버에 올려보는 단계이다.
  • EXPORT 하고자 하는 파일을 .war 확장자로 내보내 본다.

 

  • 프로젝트 > Export

 

 

 

  • 확장자는 .war 로 한다. > Next

 

 

 

  • 프로젝트 명을 설정하고 파일을 내보낼 경로도 설정한다. 
  • 만약 새로 내보내려는 파일이 기존 경로의 이름/파일과 중복된다면 Overwrite existing file을 체크해준다.
  • 작성 후 > Finish

 

 

 

  • 그러면 내가 선택한 경로에 .war 확장자를 가진 파일이 생성된다. 

 

 

 

  • FileZilla를 실행하여 호스트주소, 사용자명, 비밀번호, 포트번호를 입력후 빠른연결로 접속 시도한다.

 

 

 

  • 뭐.. 다 모자이크해서 사진이 의미가 있겠냐만 여기서 보여주고 싶은건 왼쪽 구역의 새로운 파일을 오른쪽 영역 개발 경로에 덮어 씌워준다는 것이다. 
  • 왼쪽에서 파일명을 드래그해 동일한 파일명이 존재하는 오른쪽 경로에 덮어씌워준다.

 

 

 

  • 푸티를 실행한다.

 

 

 

  • 호스트 네임, 혹은 아이피 주소를 입력 후 Port 번호까지 입력한다.
  • 이후 Open을 누르면 접속이 완료된다. 

 

 

 

  • 로그인시 아이디를 입력하면 비밀번호를 치라는 다음줄이 나올것인데
  • 비밀번호는 아무리 입력해도 눈에 보이지 않는다.
  • 그냥 감으로 맞게 치고 엔터를 누르면 다음과같이 로그인 이력이 나타난다. 

 

 

 

$ cd + 경로명 : 해당 경로로 이동하겠다는 명령어이다.
$ ll : 현재 위치한 파일 구조를 보이도록 하는 명령어이다. (영문 소문자 L엘)

 

 

 

  • 즉 cd home 폴더로 이동 후 'll '명령어를 입력하면 다음과같이 폴더의 모습이 나온다. 

 

 

 

  • 참고로 어떤 경로명을 일일이 치기 힘들어 복사를 하고싶다면 
  • 1. 푸티가 아닌 메모장에 복사, 붙여넣기 한 뒤
  • 2. 푸티로 옮겨와 cd 를 입력후 + '마우스 오른쪽 버튼' 을 클릭하면 자동으로 붙여넣어진다.  

 

 

 

  • 원하는 폴더경로로 이동했다면 이젠 방금 덮어씌웠던 war 확장자 파일의 압축을 풀어준다.
  • 압축을 푸는 명령어는 다음과 같다. 
  • $ jar -xfv [파일명].[확장자]

 

 

 

  • 서버를 올렸다 내릴땐 다음과같은 [./] 표식을 붙여준 후 실행한다. 

 

 

 

  • 정리하면, 다음과 같은 단계로 최신파일을 개발 서버에 올렸다가 내렸다.  
1. 깃에서 최신파일을 땡겨받는다 
2. 파일 경로와 globals.properties 내 경로 확인 후 war 파일로 만다
3. 파일질라에 업데이트 한다 
4. 푸티에 로그인한다. 서버 주소를 입력한다. 
5. 아이디 tomcat, 비밀번호 tomcat 을 친다. 
6. cd + 파일경로를 입력한다. 
7. $ ll을 쳤을때 나오는 경로가 현재폴더 내 들어와서 보이는 파일들 이다. 
8. 보이는 것중 하나로 들어가기 위해서 $ cd + 눈에보이는 경로를 친다. 

 

 

 

더보기

 

1. 올리려는 파일 압축하기 
( 기존에 있던 파일은 날짜 적어서 이름 바꾸기_ 같은 파일이라고 인식 못하도록)
이클립스 - export - war

2. was 경로 맞춰서 로컬에서 압축한 war파일을 filezilla(sftp)로 개발서버에 올리기

3. 개발 서버에 파일 올린 후 putty로 압축파일 풀기
war 파일 풀기 : jar -xvf klac.war
(-xvf : 압축풀기 명령어)

4. 서버 재기동 
cd /home/tomcat/apache-tomcat-9.0.75/bin/shutdown.sh - 중지
cd tomcat/apache-tomcat-9.0.75/bin/startup.sh - 시작

4-1. putty창 하나 더 켜서 로그 확인하기
로그경로
cd /home/tomcat/apache-tomcat-9.0.75/logs/catalina.out
cd /home/tomcat/apache-tomcat-9.0.75/logs/  이 경로에서 tail -f catalina.out

 

 

 

 

 

 

 

관련에러


JBWEB000236 : Servlet.service() for servlet jsp threw exception : java.lang.NumberFormatException : For input string : "lsNum1"

 

 

  • 조회 해올 쿼리에서 총 건수를 가져오는 화면을 만드는 도중 다음과같은 에러 메세지가 발생했다.
    결론만 말하자면 List로 날리고 있던 쿼리를 for문을 돌려서 가져오는게 아니라 특정값만 가져오려했기에 발생하는 문제이다.
  • 해결을 위해 객체.변수명의 형태가 아니라 객체[인덱스].변수명 의 형태로 인덱스를 기재해주어야 한다. 
  • 구글링 해보니 같은 오류의 또다른 원인으로는 ' ' 과 " " 의 위치혼동도 있다고 하니 참고해둘것

 

 

  • 다음과같이 작성했을때 나타나던 오류를 
<td class="class1">
	<c:out value="list.lsNum1"/>
</td>

 



  • 과 같이 작성하니 잘 해결되었다. 
<td class="class1">
	<c:out value="list[0].lsNum1"/>
</td>




 

 

 

 

 

 

현상


쿼리를 짠 후 서버를 올렸더니 여러단락의 에러가 떴다. 그 중 주된 에러메세지는 다음과 같다. 

: Error parsing Mapper XML, Parsing error was found in mapping 

Caused by: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. The location is...

 

 

 

 

해결방법


차례로 콘솔을 살펴보니 쿼리중 다음과 같은 오타가 눈에 띄었다. 구글링 해보니 주로 괄호를 잘못 사용한 경우에 많이 발생하는 에러임을 알 수 있었다. 콘솔에 뜨지않는다면 다시 쿼리를 꼼꼼히 들여다보는 수 밖에 없다.  

 #{RPSV_NM]

Caused by: org.apache.ibatis.builder.BuilderException: Parsing  error was found in mapping #{RPSV_NM]

 

 

 

 

 

 

 

 

 

+ Recent posts