본문 바로가기

📢 들어가며

업무 중 콤마를 포함한 스트링으로 DB 데이터를 조회해야하는 일이 생겼다.

간단히 설명하자면, "apple,banana,orange"라는 데이터를 콤마로 구분하여 각 단어를 뽑아내고

fruit 라는 컬럼에서 apple, banana, orange가 존재한다면 select 해오는 일이었다.

자바에서 작업하고 List<String> 로 넘겨 Mybatis에서 IN 작업을 해주려고 했었는데,

PostgreSQL ANY 만으로도 간단히 해결하는 방법을 찾아내어 포스팅해보려고 한다.

💬 ANY 란?

서브 쿼리의 반환 값과 비교할 때 사용하는 연산자.
서브 쿼리의 반환 값 중 하나라도 일치하면 조건이 성립된다.

 

JavaScript 유저라면 '하나라도 일치하면' 이라는 문구에서 some() 과 비슷한 느낌을 받았을 것이다.
실제로 SQL 에도 SOME 이라는 연산자가 존재하고, 이는 ANY 와 동의어이다.
ANY 가 쓰일 수 있는 모든 곳에 SOME 을 쓸 수 있다.

 

이렇게만 봐선 아직 잘 모르겠다. 아래 예제를 살펴보자.

💬 ANY 예제

SELECT title
FROM film
WHERE length >= ANY(
    SELECT MAX( length )
    FROM film
    INNER JOIN film_category USING(film_id)
    GROUP BY  category_id );

ANY 내의 서브 쿼리는 카테고리로 그룹 지어진 영화 중 가장 긴 length(컬럼 명임)를 반환한다는 내용이다.

 

예를 들어 서브쿼리의 반환 값이 7 이라고 했을 때
film 테이블의 length(컬럼 값)가 7보다 같거나 크면 해당 title을 반환한다.

 

즉, ANY는 서브 쿼리의 반환 값과 특정 컬럼을 비교 했을 떄 하나라도 일치한다면 조건이 성립하는 것이다.

 

위 예제에선 MAX를 썼기 때문에 서브 쿼리의 반환 값이 하나여서 굳이 ANY를 쓰지 않아도 됐겠지만
반환 값이 여러개인 경우 ANY가 유용하게 쓰일 수 있다.

 

위와 같은 서브 쿼리 외에도 function 의 반환 값과도 ANY 를 사용할 수 있다.
"📢 들어가며" 에서 언급한 상황을 시도해보자.

select 
    fruit
from 
    food
where 
    fruit = ANY(string_to_array('apple,banana,orange', ','))

string_to_array 연산자가 보이는가?
string_to_array 가 무엇인지도 짚고 넘어가보자.

💡 string_to_array

string_to_array는 문자열을 특정 문자(구분자)로 나누거나 특정 문자를 null 로 만들고 싶을 떄 사용하는 연산자이다.

string_to_array('문자열', '구분자', '구분자', '구분자'...)

💡 string_to_array 예제

SELECT string_to_array('xx~^~yy~^~zz', '~^~', 'yy');

결과

 string_to_array
-----------------
 {xx,NULL,zz}
(1 row)

문자열 xx~^~yy~^~zz 에서 ~^~yy 가 null로 대체된 것을 알 수 있다!

 

다시 ANY 예제로 돌아와보자.

 

즉, string_to_array('apple,banana,orange', ',')
{apple,NULL,banana,NULL,orange} 를 반환할 것이다.

 

이 반환 값이 ANY 를 돌게 되는데,
fruit 컬럼의 값이 apple 또는 banana 또는 orange 와 같다(=)면 참이라는 뜻이다.

💬 ANY 와 IN의 차이

결론적으로 ANY 는 비교 연산자(>=, <=, =, >, < 등)와 사용이 가능하고 IN 은 그렇지 않다는 것이다.
이 것 외엔 여러 값을 하나의 컬럼 값과 비교한다는 점에서 거의 유사하다고 할 수 있다.

  • ANY 예제
SELECT 
	title, category_id 
FROM 
	film 
INNER JOIN 
	film_category 
    	USING(film_id) 
 WHERE 
 	category_id = ANY( 
    	SELECT 
        	category_id 
        FROM 
        	category 
        WHERE 
        	NAME = 'Action' 
            OR 
            NAME = 'Drama' 
        );
  • IN 예제
SELECT 
	title, category_id
FROM 
	film 
INNER JOIN 
	film_category 
    	USING(film_id) 
WHERE 
	category_id IN( 
    	SELECT 
        	category_id 
        FROM 
        	category 
        WHERE 
        	NAME = 'Action'
        	OR 
            NAME = 'Drama' 
        );

 

Seize the day!

Spring MVC | Spring Boot | Spring Security | Mysql | Oracle | PostgreSQL | Vue.js | Nuxt.js | React.js | TypeScript | JSP | Frontend | Backend | Full Stack | 자기계발 | 미라클 모닝 | 일상