Skip to main content

PostgreSQL

쿼리 추가

페이지 목록에서 워크플로우를 추가하여 쿼리 스텝을 추가할 수 있습니다.
워크플로우 스텝 사이드바에서 PostgreSQL 데이터 소스를 선택하면 쿼리 입력 창이 나타납니다.
데이터 소스 추가 방법은 PostgreSQL 데이터 소스 가이드를 참고해주세요.

postgresql

기본 쿼리 작성

Hops에서는 일반적인 SQL 문법을 모두 사용할 수 있습니다. 데이터를 조회하거나 수정하는 모든 SQL 명령어를 사용할 수 있습니다.

-- 기본적인 SELECT 쿼리
SELECT * FROM customer;

-- WHERE 절을 사용한 필터링
SELECT id, name FROM customer WHERE advertisement_agreed;

-- JOIN을 사용한 테이블 연결
SELECT payment.id, payment.created_at, customer.name
FROM payment
JOIN payment_method ON payment.payment_method_id = payment_method.id
JOIN customer ON payment_method.customer_id = customer.id;

템플릿 문법 활용

템플릿 활용 방법에는 두가지가 있습니다.

  1. {{}}: JavaScript 표현식을 사용할 수 있습니다. 홉스 내에 있는 상태와 변수를 사용할 수 있습니다.
  2. {{$ }}: 타입에 맞추어 SQL escape 처리가 됩니다.
    예를 들어 {{$ 'abc' }}라는 코드는 string 타입에 맞추어 SELECT abc가 아닌 SELECT 'abc'로 해석됩니다.
-- 기본 사용
SELECT {{ 'name' }} FROM customer; -- SELECT name FROM customer와 동일한 결과. customer 테이블의 name 컬럼을 조회합니다.
SELECT {{$ 'name' }} FROM customer; -- SELECT 'name' FROM customer와 동일한 결과. `'name'`이라는 문자열 타입의 값이 결과로 나옵니다.

-- 조건부 WHERE 절
SELECT * FROM customer
WHERE
({{$ searchInput.value }} = '' OR name LIKE '%{{ searchInput.value }}%')
AND advertisement_agreed = {{$ advertisementAgreedCheckbox.checked }}

-- 배열 활용
SELECT * FROM payment
WHERE status IN (
{{ statusMultiSelect.values.length == 0 ? 'NULL' : statusMultiSelect.values.map(v => '${v}').join(',') }}
)

SQL Escape

SQL injection 공격을 방지하고 데이터 타입의 안전성을 보장하기 위해서는 적절한 escape 처리가 필요합니다. Hops에서는 {{$ }} 구문을 통해 자동 SQL escape 처리를 지원합니다.

-- 기본 문자열 escape
SELECT * FROM customer WHERE name = {{$ textField1.value }}
-- -> SELECT * FROM customer WHERE name = 'textField1.value'

-- 숫자 타입 escape
SELECT * FROM payment WHERE points_rate > {{$ numberField1.value }}
-- -> SELECT * FROM payment WHERE points_rate > 100

-- 날짜 타입 escape
SELECT * FROM payment WHERE created_at = {{$ dateField1.value }}
-- -> SELECT * FROM payment WHERE created_at = 'dateField1.value'

변수 사용하기

다음과 같은 방식으로 변수를 사용할 수 있습니다.

1. 페이지 변수 사용

페이지에 등록된 변수는 page.변수명 형식으로 사용합니다. 자세한 내용은 페이지 변수 이해하기 문서를 참고해주세요.

SELECT * FROM customer WHERE id = {{page.userId}};

2. 워크플로우 입력값 사용

워크플로우에 정의된 입력값은 inputs.변수명 형식으로 사용합니다. 자세한 내용은 워크플로우 변수 값 가져오기 문서를 참고해주세요.

SELECT * FROM payment
WHERE created_at BETWEEN CAST({{$ inputs.startDate }} AS DATE) AND CAST({{$ inputs.endDate }} AS DATE);

3. 이전 스텝의 결과값 사용

이전 스텝의 결과값은 outputs.스텝명 형식으로 사용합니다. 자세한 내용은 워크플로우 스텝의 결과 값 가져오기 문서를 참고해주세요.

SELECT * FROM payment
WHERE payment_method_id = {{outputs.step1.data[0].payment_method_id}};

4. 컴포넌트 상태값 사용

페이지 내 컴포넌트의 상태값은 컴포넌트명.상태명 형식으로 사용합니다. 자세한 내용은 컴포넌트 문서를 참고해주세요.

SELECT * FROM customer
WHERE name LIKE '%{{searchInput.value}}%';

쿼리 결과값

SQL 쿼리를 실행하면 결과값이 data: Record<string, unknown>[]와 같은 구조로 반환됩니다.

  • data: 쿼리 결과를 담고 있는 최상위 객체
  • Record<string, unknown>[]: 컬럼명을 key로, 해당 값을 value로 가지는 객체들의 배열

결과값 활용하기

-- 첫번째 SQL 스텝 쿼리
SELECT id, name FROM customer;

-- 결과값 구조
{
data: [
{ id: 1, name: "John Doe" },
{ id: 2, name: "Jane Doe" }
]
}

-- 두번째 JavaScript 스텝 쿼리
return outputs.step1.data.map(item => item.name);

주의사항

  1. 템플릿 내에서는 SQL 인젝션을 방지하기 위해 적절한 이스케이프 처리가 필요합니다.
  2. 복잡한 조건문이나 데이터 처리가 필요한 경우, JavaScript 스텝을 먼저 실행한 후 그 결과를 SQL 쿼리에서 사용하는 것이 좋습니다.
  3. 대량의 데이터를 다루는 경우 적절한 LIMIT과 페이지네이션을 사용하는 것이 권장됩니다.

예시: 검색 기능 구현

다음은 검색어와 카테고리 필터를 적용한 제품 검색 쿼리의 예시입니다:

SELECT payment.id, payment.created_at, customer.name
FROM payment
JOIN payment_method ON payment.payment_method_id = payment_method.id
JOIN customer ON payment_method.customer_id = customer.id
WHERE
(
customer.name LIKE '%{{searchInput.value}}%' OR
payment.id LIKE '%{{searchInput.value}}%'
)
AND payment.created_at BETWEEN CAST({{$ inputs.startDate }} AS DATE) AND CAST({{$ inputs.endDate }} AS DATE)
ORDER BY payment.created_at DESC
LIMIT {{$ paymentTable1.page.limit }}
OFFSET {{$ paymentTable1.page.offset }}

이 예시는 검색어, 페이지네이션을 모두 포함하고 있습니다.