동기

쿼리 문자열을 어플리케이션 레벨에서 빌드하기 위해 고생한 경험은 다들 한 번씩 해봤을 것이다.

user_id = '...'

query = "SELECT COUNT(*) FROM tbl_users WHERE id='{}'".format(user_id)

문자열 결합을 쓰거나, 위처럼 언어 차원에서 지원되는 string interpolation의 도움을 받는 식이다. 이렇게 '이 자리에 이거' 정도면 문자열 포매팅 수준이라 그나마 괜찮은데, where 절이 동적이라거나 하는 clause 단위의 쿼리 빌드는 더 번거롭다. 아래는 그 간단한 예제 코드인데, 굳이 다 읽고 이해하려 하진 않아도 된다.

class WhereClause:
    @classmethod
    def build_query(cls, *args, **kwargs):
        raise NotImplementedError()


class Between(WhereClause):
    @classmethod
    def build_query(cls, column_name, left, right):
        return "`{}` BETWEEN {} AND {}".format(column_name, left, right)


class Equal(WhereClause):
    ...


def build_query(dimensions, filters):
    query_base = """
        SELECT
            {}
        FROM
            tbl_users

        {}
    """

    query = query_base.format(
        ",".join("`{}`".format(dimension) for dimension in dimensions), "{}"
    )

    if filters:
        query = query.format(
            "WHERE "
            + " AND ".join(
                filter_item["operator"].build_query(
                    filter_item["dimension"], filter_item["left"], filter_item["right"]
                )
                for filter_item in filters
            )
        )
    else:
        query = query.format("")

    return query


builded_query = build_query(
    ["id", "pw", "name"],
    [{"dimension": "age", "operator": Between, "left": 10, "right": 20}],
)

뭐 대충 이런 느낌이다. 위의 경우 between 쿼리의 left와 right 값에 문자열이 들어가면 쿼리 문법 에러가 발생할 것이며, ORDER BY나 GROUP BY, JOIN 등 수많은 쿼리에 대응되는 쿼리 빌더수많은 예외를 모두 고려하며 직접, 그리고 잘 만드는 것은 정말 쉽지 않다. 나도 대표적인 몇가지 연산자(equal, not equal, lt/gt/lte/gte, between 정도)가 포함된 WHERE절 정도까지만 지원되는 쿼리 빌더를 직접 만들어 보려는 시도를 조금 했었는데, reinvent the wheel의 정석이라고 생각한다.

이런 고민을 가장 잘 해결해 주는 것이 SQLAlchemyPeewee같은 ORM들이다. 테이블 스키마를 클래스로서 명시해 두고, 빌더 패턴 느낌으로 쿼리를 빌드할 수 있기 때문이다. 그러나 ORM을 사용하지 않는 환경이라면 SQL 쿼리 빌딩을 해주는 헬퍼 정도가 필요해 지는데, 위에서도 말했듯 직접 만드는 건 너무 오바여서 그냥 'Python Query Builder' 정도로 구글링을 해보니 PyPika라는 라이브러리를 만나게 되었고 꽤 괜찮은 것 같아서 튜토리얼 번역과 함께 필자의 의견을 조금씩 섞어서 3~4편 정도로 짧게 PyPika에 대해 연재해 보겠다.

PyPika

Abstract

What is PiPika?

PyPika는 SQL 쿼리를 빌드해주는 Python API다. PyPika의 동기는 직접 작성하는(handwritten) SQL의 유연성을 제한하지 않고, SQL 쿼리를 작성하기 위한 간단한 인터페이스를 제공하는 것이다. 데이터 분석을 염두에 두고 설계된 PyPika는 지저분한 문자열 포맷과 결합을 피하기 위해 빌더 디자인 패턴을 활용하여 쿼리를 구성한다. 또한 SQL 데이터베이스 공급 업체(vendor - MySQL, PostgreSQL 등)의 특정 기능을 최대한 활용할 수 있도록 쉽게 확장된다.

Installation

PyPika는 Python 2.7Python 3.3 이상의 버전을 지원한다. 그리고 pypy, cython, jython에서도 동작하지만 이들에 맞춰 따로 테스트를 구성해 두진 않았다. PyPika를 설치하려면 아래의 커맨드를 입력하면 된다.

$ pip install pypika