SQL 조건문 팁

이 페이지의 내용은 MySQL 기준으로 작성했습니다.
PostgreSQL와 다른 데이터베이스 쿼리의 경우 별도 표시를 해두었습니다.

📘

셀렉트는 Bind Parameter / Prepared Statements를 기본으로 합니다.

SQL 보안을 위해 번거롭더라도 원본 raw query 입력을 원칙적으로 막고 있습니다.
인가된 사용자만 어드민 시스템을 이용한다고 하더라도 동일 네트워크상 세션탈취나 기타 물리적인 침입/침해를 막기 위해 보안 가이드라인을 제공하고 있습니다.

더 향상된 보안을 위해 Enterprise 플랜에서는 general query log의 anomaly scoring을 제공합니다.

검색조건 필수

빈칸이면 결과물 없음

SELECT *
FROM users
WHERE name = :name

검색조건 옵션

CASE-WHEN 활용

SELECT *
FROM users
WHERE status = 'active'
  AND CASE
    WHEN LENGTH(:name) THEN name = :name
    ELSE 1=1
  END

빈칸이면 해당 조건 없이 결과물 표시

SELECT *
FROM users
WHERE status = 'active'
  AND (!LENGTH(:name) OR name = :name)

PostgreSQL: 빈칸이면 해당 조건 없이 결과물 표시

SELECT *
FROM users
WHERE status = 'active'
  AND (LENGTH(:name) = 0 OR name = :name)

검색조건 LIKE

MySQL

SELECT *
FROM users
WHERE name LIKE CONCAT('%', :name, '%')

PostgreSQL: 타입 지정 필요

SELECT *
FROM users
WHERE name LIKE CONCAT('%', :name::text, '%')

검색조건에 따른 쿼리입력

types 값에 해당하는 쿼리가 안전하게 bind 됩니다.

sql: >
  SELECT * 
  FROM properties 
  WHERE name LIKE CONCAT('%', :name, '%') 
    AND {{query}}
  LIMIT 1000
params:
- key: name
  label: 숙소명
- key: types
  label: 숙소타입
  query:
    '': >
      `type` = :types
    'HOTEL': >
      `type` = 'HOTEL'
    'NON HOTEL': >
      `type` IN ('GUESTHOUSE', 'BNB')

types에 NON HOTEL 값이 들어가는 경우 실제 실행 쿼리는 다음과 같습니다.

SELECT * 
  FROM properties 
  WHERE name LIKE CONCAT('%', :name, '%') 
    AND `type` IN ('GUESTHOUSE', 'BNB') AND 1=1
  LIMIT 1000

검색조건에 따른 쿼리 정렬

pages:
  - path: property/list
    blocks:
    - type: query
      resource: mysql
      name: 업체목록
      sqlType: select
      sql: >
        SELECT *
        FROM property
        {{ orderBy }}
        LIMIT 100
      params:
        - key: orderby
          label: 정렬
          defaultValue: 최근가입순
          dropdownSize: 2
          dropdown:
            - 최근가입순
            - 오래된가입순
          orderBy:
            '최근가입순': ORDER BY id DESC
            '오래된가입순': ORDER BY id ASC

날짜 검색조건 기본값

CASE-WHEN 활용

SELECT 
  id, active, name, email, created_at, last_updated, trial_expiry_date  
FROM s_users
WHERE CASE WHEN LENGTH(:user_id) THEN id = :user_id ELSE 1=1 END
  AND CASE WHEN LENGTH(:user_name) THEN name LIKE CONCAT('%', :user_name, '%') ELSE 1=1 END
  AND CASE WHEN LENGTH(:signed_up) THEN created_at >= GREATEST('2000-01-01', :signed_up) ELSE 1=1 END

위와 동일 합니다.

SELECT 
  id, active, name, email, created_at, last_updated, trial_expiry_date  
FROM s_users
WHERE (!LENGTH(:user_id) OR id = :user_id)
  AND (!LENGTH(:user_name) OR name LIKE CONCAT('%', :user_name, '%'))
  AND (!LENGTH(:signed_up) OR created_at >= GREATEST('2000-01-01', :signed_up))

여러 항목 UPDATE

number는 Number 숫자로 escape하여 들어갑니다.
user_ids는 Array/List로 각 항목을 알맞게 escape하여 들어갑니다.

pages:
- path: customer/support
  blocks:
    - type: query
      resource: mysql
      sqlType: select
      sql: >
        SELECT 
          id AS '고객ID', 
          active AS '활성', name AS '이름', email AS '이메일', 
          created_at AS '생성일', last_updated AS '최근수정일', 
          trial_expiry_date AS '만료일'    
        FROM s_users
        
      selectOptions:
        enabled: true
        selectionText: 건 선택됨
        clearSelectionText: 취소
        selectOnCheckboxOnly: true
        disableSelectInfo: true   

      actions:
        - label: 만료일 연장
          type: query
          resource: mysql
          sql: >
            UPDATE s_users 
              SET trial_expiry_date = NOW() + INTERVAL :number DAY 
            WHERE id IN (:user_ids)
          valueFromSelectedRowsAs: 고객ID
          params:
            - key: number
              label: 만료일 연장 (D+1)
              dropdown:
                - 1
                - 4
                - 7
                - 14 
              required: true
            - key: user_ids
              valueFromSelectedRows: true
              valueFromSelectedRowsAs: 고객ID

검색조건 IN

비어있는 IN ()으로 에러가 나는 경우 빈값 IN ('', :tags) 또는 IN (0, :ids)을 넣습니다.

- path: stock-a/return
  blocks:
  - type: query
    resource: mysql.qa
    sqlType: select
    sql: >
      SELECT name FROM test_10k 
      WHERE name IN ('', :tag) 
      LIMIT 100
    params:
    - key: tag
      label: Tag
      datalist: true
      datalistLength: 5
      datalistFromQuery: 
        type: query
        resource: mysql.qa
        sqlType: select
        sql: SELECT DISTINCT name FROM test_10k LIMIT 10

PostgreSQL 문법은 차이가 있습니다. 아래 문서를 참고해주세요.
계속 업데이트 중입니다. 궁금하신 점은 문의바랍니다.