PostgreSQL 컬럼 타입

정수(integer)

PostgreSQL의 모든 컬럼 타입을 기본적으로 지원합니다. 하지만 이로 충분하지 않다면 **커스텀 타입**을 만들어 사용할 수 있습니다.

중요

이 문서의 모든 예제는 데이터베이스 컬럼 이름 별칭을 사용하지 않으며, 컬럼 이름은 TypeScript 키에서 생성됩니다.

원한다면 데이터베이스 별칭을 사용할 수 있으며, casing 매개변수를 통해 Drizzle의 매핑 전략을 정의할 수도 있습니다.

자세한 내용은 여기에서 확인할 수 있습니다.

integer int int4
부호 있는 4바이트 정수

integer autoincrement가 필요하다면 **serial**을 참조하세요.

import { integer, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	int: integer()
});
CREATE TABLE IF NOT EXISTS "table" (
	"int" integer
);
import { sql } from "drizzle-orm";
import { integer, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	int1: integer().default(10),
	int2: integer().default(sql`'10'::int`)
});
CREATE TABLE IF NOT EXISTS "table" (
	"int1" integer DEFAULT 10,
	"int2" integer DEFAULT '10'::int
);

smallint

smallintint2로도 알려져 있으며, 2바이트 크기의 작은 범위의 부호 있는 정수 타입입니다.

smallint를 자동 증가(auto increment)로 사용하려면 **smallserial**을 참고하세요.

import { smallint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	smallint: smallint()
});
CREATE TABLE IF NOT EXISTS "table" (
	"smallint" smallint
);
import { sql } from "drizzle-orm";
import { smallint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	smallint1: smallint().default(10),
	smallint2: smallint().default(sql`'10'::smallint`)
});
CREATE TABLE IF NOT EXISTS "table" (
	"smallint1" smallint DEFAULT 10,
	"smallint2" smallint DEFAULT '10'::smallint
);

bigint

bigintint8로, 부호 있는 8바이트 정수입니다.

bigint에 자동 증가 기능이 필요하다면 **bigserial**을 참고하세요.

값이 2^31보다 크고 2^53보다 작을 것으로 예상된다면, mode: 'number'를 사용하여 bigint 대신 자바스크립트 number로 처리할 수 있습니다.

import { bigint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
    bigint: bigint({ mode: 'number' })
});

// `number` 타입으로 추론됨
bigint: bigint({ mode: 'number' })

// `bigint` 타입으로 추론됨
bigint: bigint({ mode: 'bigint' })
CREATE TABLE IF NOT EXISTS "table" (
    "bigint" bigint
);
import { sql } from "drizzle-orm";
import { bigint, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
    bigint1: bigint().default(10),
    bigint2: bigint().default(sql`'10'::bigint`)
});
CREATE TABLE IF NOT EXISTS "table" (
    "bigint1" bigint DEFAULT 10,
    "bigint2" bigint DEFAULT '10'::bigint
);

---

serial

serialserial4는 4바이트 정수 타입으로, 자동으로 증가하는 값을 가지며, 고유 식별자 컬럼을 생성하는 데 편리하게 사용됩니다. 이는 다른 데이터베이스에서 지원하는 AUTO_INCREMENT 속성과 유사합니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { serial, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
  serial: serial(),
});
CREATE TABLE IF NOT EXISTS "table" (
	"serial" serial NOT NULL,
);

smallserial

smallserial 또는 serial2는 2바이트 크기의 자동 증가 정수 타입입니다. 이 타입은 고유 식별자 컬럼을 생성할 때 편리하게 사용할 수 있습니다. (다른 데이터베이스에서 지원하는 AUTO_INCREMENT 속성과 유사합니다.)

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { smallserial, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
  smallserial: smallserial(),
});
CREATE TABLE IF NOT EXISTS "table" (
	"smallserial" smallserial NOT NULL,
);

bigserial

bigserial 또는 serial8은 8바이트 크기의 자동 증가 정수 타입입니다. 이 타입은 고유 식별자 컬럼을 생성할 때 편리하게 사용할 수 있으며, 다른 데이터베이스에서 제공하는 AUTO_INCREMENT 속성과 유사합니다.

더 자세한 정보는 PostgreSQL 공식 문서를 참고하세요.

만약 값이 2^31보다 크고 2^53보다 작은 범위를 예상한다면, mode: 'number'를 사용하여 bigint 대신 자바스크립트의 number 타입으로 처리할 수 있습니다.

import { bigserial, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
  bigserial: bigserial({ mode: 'number' }),
});
CREATE TABLE IF NOT EXISTS "table" (
	"bigserial" bigserial NOT NULL,
);

---

불리언(Boolean)

PostgreSQL은 표준 SQL 타입인 불리언을 제공합니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { boolean, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
	boolean: boolean()
});
CREATE TABLE IF NOT EXISTS "table" (
	"boolean" boolean
);

---

text

text
가변 길이(무제한) 문자열을 나타냅니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

{ enum: ["value1", "value2"] } 설정을 통해 insertselect 타입을 추론할 수 있습니다. 하지만 이 설정은 런타임 값 검사를 수행하지 않습니다.

import { text, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
  text: text()
});

// "value1" | "value2" | null 타입으로 추론됨
text: text({ enum: ["value1", "value2"] })
CREATE TABLE IF NOT EXISTS "table" (
	"text" text,
);

varchar

character varying(n) 또는 varchar(n)은 가변 길이 문자열을 저장할 수 있는 데이터 타입입니다. 최대 **n**개의 문자(바이트가 아님)를 저장할 수 있습니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

{ enum: ["value1", "value2"] } 설정을 통해 insertselect 타입을 추론할 수 있습니다. 하지만 이 설정은 런타임 값 검사를 수행하지 않습니다.

PostgreSQL 문서에 따르면 length 매개변수는 선택 사항입니다.

import { varchar, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
  varchar1: varchar(), // 길이 제한 없음
  varchar2: varchar({ length: 256 }), // 최대 256자
});

// "value1" | "value2" | null 타입으로 추론됨
varchar: varchar({ enum: ["value1", "value2"] }),
CREATE TABLE IF NOT EXISTS "table" (
	"varchar1" varchar,
	"varchar2" varchar(256),
);

char

character(n) 또는 char(n)
고정 길이의 공백으로 채워진 문자열 타입입니다. 최대 **n**개의 문자(바이트가 아님)를 저장할 수 있습니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

{ enum: ["value1", "value2"] } 설정을 통해 insertselect 타입을 추론할 수 있습니다. 하지만 이 설정은 런타임 값 검사를 수행하지 않습니다.

PostgreSQL 문서에 따르면 length 매개변수는 선택 사항입니다.

import { char, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
  char1: char(),
  char2: char({ length: 256 }),
});

// "value1" | "value2" | null 타입으로 추론됨
char: char({ enum: ["value1", "value2"] }),
CREATE TABLE IF NOT EXISTS "table" (
	"char1" char,
	"char2" char(256),
);

---

numeric

numeric 또는 decimal
선택 가능한 정밀도를 가진 정확한 숫자 타입입니다. 소수점 앞에 최대 131,072자리, 소수점 뒤에 최대 16,383자리까지 매우 큰 숫자를 저장할 수 있습니다.

더 자세한 정보는 공식 PostgreSQL **문서**를 참고하세요.

import { numeric, pgTable } from "drizzle-orm/pg-core";

export const table = pgTable('table', {
  numeric1: numeric(),
  numeric2: numeric({ precision: 100 }),
  numeric3: numeric({ precision: 100, scale: 20 }),
});
CREATE TABLE IF NOT EXISTS "table" (
	"numeric1" numeric,
	"numeric2" numeric(100),
	"numeric3" numeric(100, 20),
);

decimal

**numeric**의 별칭입니다.

real

realfloat4로도 알려져 있으며, 단정밀도 부동소수점 숫자(4바이트)를 나타냅니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { sql } from "drizzle-orm";
import { real, pgTable } from "drizzle-orm/pg-core";  

const table = pgTable('table', {
    real1: real(),
    real2: real().default(10.10),
    real2: real().default(sql`'10.10'::real`),
});
CREATE TABLE IF NOT EXISTS "table" (
    "real1" real,
    "real2" real default 10.10,
    "real2" real default '10.10'::real
);

Double Precision

double precisionfloat8로도 알려져 있으며, 8바이트 크기의 배정밀도 부동소수점 숫자를 나타냅니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { sql } from "drizzle-orm";
import { doublePrecision, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
    double1: doublePrecision(),
    double2: doublePrecision().default(10.10),
    double3: doublePrecision().default(sql`'10.10'::double precision`),
});
CREATE TABLE IF NOT EXISTS "table" (
    "double1" double precision,
    "double2" double precision default 10.10,
    "double3" double precision default '10.10'::double precision,
);

---

JSON

json
**RFC 7159**에 정의된 텍스트 기반 JSON 데이터입니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { sql } from "drizzle-orm";
import { json, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
    json1: json(),
    json2: json().default({ foo: "bar" }),
    json3: json().default(sql`'{foo: "bar"}'::json`),
});
CREATE TABLE IF NOT EXISTS "table" (
    "json1" json,
    "json2" json default '{"foo": "bar"}'::json,
    "json3" json default '{"foo": "bar"}'::json,
);

.$type<..>()를 사용해 JSON 객체의 타입을 지정할 수 있습니다. 이는 런타임 값을 검사하지 않으며, 기본값, 삽입 및 선택 스키마에 대한 컴파일 타임 보호를 제공합니다.

// { foo: string } 타입으로 추론됨
json: json().$type<{ foo: string }>();

// string[] 타입으로 추론됨
json: json().$type<string[]>();

// 컴파일 오류 발생
json: json().$type<{ foo: string }>().default({});

jsonb

jsonb
바이너리 JSON 데이터로, 분해된 형태로 저장됩니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { jsonb, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	jsonb1: jsonb(),
	jsonb2: jsonb().default({ foo: "bar" }),
	jsonb3: jsonb().default(sql`'{foo: "bar"}'::jsonb`),
});
CREATE TABLE IF NOT EXISTS "table" (
	"jsonb1" jsonb,
	"jsonb2" jsonb default '{"foo": "bar"}'::jsonb,
	"jsonb3" jsonb default '{"foo": "bar"}'::jsonb,
);

.$type<..>()를 사용하여 JSON 객체의 타입을 지정할 수 있습니다. 이는 런타임 값을 검사하지 않습니다.
기본값, 삽입 및 선택 스키마에 대해 컴파일 타임 보호를 제공합니다.

// { foo: string } 타입으로 추론됨
jsonb: jsonb().$type<{ foo: string }>();

// string[] 타입으로 추론됨
jsonb: jsonb().$type<string[]>();

// 컴파일되지 않음
jsonb: jsonb().$type<{ foo: string }>().default({});

---

시간(time)

time, timetz, time with timezone, time without timezone
시간대를 포함하거나 포함하지 않는 하루 중의 시간을 나타냅니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { time, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
  time1: time(),
  time2: time({ withTimezone: true }),
  time3: time({ precision: 6 }),
  time4: time({ precision: 6, withTimezone: true })
});
CREATE TABLE IF NOT EXISTS "table" (
  "time1" time,
  "time2" time with timezone,
  "time3" time(6),
  "time4" time(6) with timezone
);

타임스탬프

timestamp, timestamptz, timestamp with time zone, timestamp without time zone
시간대 정보를 포함하거나 포함하지 않는 날짜와 시간을 나타냅니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { sql } from "drizzle-orm";
import { timestamp, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
  timestamp1: timestamp(),
  timestamp2: timestamp({ precision: 6, withTimezone: true }),
  timestamp3: timestamp().defaultNow(),
  timestamp4: timestamp().default(sql`now()`),
});
CREATE TABLE IF NOT EXISTS "table" (
  "timestamp1" timestamp,
  "timestamp2" timestamp (6) with time zone,
  "timestamp3" timestamp default now(),
  "timestamp4" timestamp default now(),
);

date 또는 string 모드로 타입을 추론할 수 있습니다:

// date로 추론
timestamp: timestamp({ mode: "date" }),

// string으로 추론
timestamp: timestamp({ mode: "string" }),

string 모드는 어떤 매핑도 수행하지 않습니다. 이 모드는 개발자가 필요에 따라 날짜와 날짜 매핑을 직접 처리할 수 있도록 Drizzle ORM에 추가되었습니다. Drizzle은 데이터베이스와 주고받는 날짜를 문자열로 그대로 전달하므로, 동작은 가능한 한 예측 가능하며 데이터베이스 동작과 100% 일치합니다.

date 모드는 날짜를 다루는 일반적인 방식입니다. Drizzle은 데이터베이스와 JS Date 객체 간의 모든 매핑을 처리합니다.

timestamptimestamp with timezone에 대한 매핑 동작:

PostgreSQL 문서에 따르면:

timestamp without time zone로 결정된 리터럴에서 PostgreSQL은 시간대 표시를 무시합니다. 즉, 결과 값은 입력 값의 날짜/시간 필드에서 파생되며 시간대에 따라 조정되지 않습니다.

timestamp with time zone의 경우, 내부적으로 저장된 값은 항상 UTC(Universal Coordinated Time, 전통적으로 GMT로 알려짐)입니다. 명시적으로 시간대가 지정된 입력 값은 해당 시간대의 적절한 오프셋을 사용하여 UTC로 변환됩니다. 입력 문자열에 시간대가 명시되지 않은 경우, 시스템의 TimeZone 매개변수로 지정된 시간대로 간주되고 해당 시간대의 오프셋을 사용하여 UTC로 변환됩니다.

따라서 timestamp with timezone를 사용하면 Postgres 인스턴스에 설정된 시간대로 변환된 문자열을 반환합니다. 다음 SQL 쿼리를 사용하여 시간대를 확인할 수 있습니다:

show timezone;

날짜(date)

date
달력 날짜(년, 월, 일)를 나타냅니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { date, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	date: date(),
});
CREATE TABLE IF NOT EXISTS "table" (
	"date" date,
);

date 또는 string 타입으로 추론 모드를 지정할 수 있습니다:

// date 타입으로 추론
date: date({ mode: "date" }),

// string 타입으로 추론
date: date({ mode: "string" }),

interval

interval
시간 간격을 나타내는 타입입니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { interval, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	interval1: interval(),
  interval2: interval({ fields: 'day' }),
  interval3: interval({ fields: 'month' , precision: 6 }),
});
CREATE TABLE IF NOT EXISTS "table" (
	"interval1" interval,
	"interval2" interval day,
	"interval3" interval(6) month,
);

---

point

point
기하학적 점 타입

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

point 타입은 데이터베이스에서 매핑할 때 두 가지 모드를 지원합니다: tuplexy.

const items = pgTable('items', {
    point: point(),
    pointObj: point({ mode: 'xy' }),
});
CREATE TABLE IF NOT EXISTS "items" (
    "point" point,
    "pointObj" point,
);

line

line
기하학적 선(line) 타입

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

line 타입은 데이터베이스와의 매핑을 위해 두 가지 모드를 제공합니다: tupleabc.

const items = pgTable('items', {
    line: line(),
    lineObj: point({ mode: 'abc' }),
});
CREATE TABLE IF NOT EXISTS "items" (
    "line" line,
    "lineObj" line,
);

---

enum

enum열거형 타입(enumerated types)을 의미합니다.
열거형 타입은 정적이고 순서가 있는 값들의 집합으로 구성된 데이터 타입입니다.
이 타입은 여러 프로그래밍 언어에서 지원하는 enum 타입과 동일합니다.
예를 들어, 요일이나 데이터의 상태 값 집합이 열거형 타입의 예시가 될 수 있습니다.

더 자세한 정보는 PostgreSQL 공식 **문서**를 참고하세요.

import { pgEnum, pgTable } from "drizzle-orm/pg-core";

// 'mood'라는 이름의 enum 타입을 정의합니다. 값은 'sad', 'ok', 'happy'입니다.
export const moodEnum = pgEnum('mood', ['sad', 'ok', 'happy']);

// 'table'이라는 테이블을 정의합니다. 'mood' 컬럼은 위에서 정의한 enum 타입을 사용합니다.
export const table = pgTable('table', {
  mood: moodEnum(),
});
-- 'mood'라는 enum 타입을 생성합니다. 값은 'sad', 'ok', 'happy'입니다.
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');

-- 'table'이라는 테이블을 생성합니다. 'mood' 컬럼은 위에서 정의한 enum 타입을 사용합니다.
CREATE TABLE IF NOT EXISTS "table" (
	"mood" mood,
);

---

데이터 타입 커스터마이징

모든 컬럼 빌더는 .$type() 메서드를 제공합니다. 이 메서드를 사용하면 컬럼의 데이터 타입을 커스터마이징할 수 있습니다.

예를 들어, 알려지지 않은 타입이나 브랜드 타입을 다룰 때 유용합니다:

type UserId = number & { __brand: 'user_id' };
type Data = {
	foo: string;
	bar: number;
};

const users = pgTable('users', {
  id: serial().$type<UserId>().primaryKey(),
  jsonField: json().$type<Data>(),
});

Identity Columns (자동 증가 컬럼)

이 기능을 사용하려면 drizzle-orm@0.32.0 이상과 drizzle-kit@0.23.0 이상 버전이 필요합니다.

PostgreSQL은 자동으로 고유한 정수 값을 생성하는 Identity Columns를 지원합니다. 이 값은 시퀀스를 사용하여 생성되며, GENERATED AS IDENTITY 절을 통해 정의할 수 있습니다.


Identity Columns의 종류


주요 기능


제한 사항


사용 예제

import { pgTable, integer, text } from 'drizzle-orm/pg-core' 

export const ingredients = pgTable("ingredients", {
  id: integer().primaryKey().generatedAlwaysAsIdentity({ startWith: 1000 }),
  name: text().notNull(),
  description: text(),
});

.generatedAlwaysAsIdentity() 함수 내에서 시퀀스에 사용 가능한 모든 속성을 지정할 수 있습니다. 또한, 이러한 시퀀스에 커스텀 이름을 지정할 수도 있습니다.

PostgreSQL 공식 문서 참조.

기본값 설정

DEFAULT 절은 사용자가 INSERT를 수행할 때 명시적으로 값을 제공하지 않았을 경우, 컬럼에 사용할 기본값을 지정합니다. 컬럼 정의에 명시적인 DEFAULT 절이 없으면, 해당 컬럼의 기본값은 NULL이 됩니다.

명시적인 DEFAULT 절은 기본값을 NULL, 문자열 상수, 블롭 상수, 부호 있는 숫자, 또는 괄호로 둘러싸인 상수 표현식으로 지정할 수 있습니다.

import { sql } from "drizzle-orm";
import { integer, pgTable, uuid } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	integer1: integer().default(42),
	integer2: integer().default(sql`'42'::integer`),
	uuid1: uuid().defaultRandom(),
	uuid2: uuid().default(sql`gen_random_uuid()`),
});
CREATE TABLE IF NOT EXISTS "table" (
	"integer1" integer DEFAULT 42,
	"integer2" integer DEFAULT '42'::integer,
	"uuid1" uuid DEFAULT gen_random_uuid(),
	"uuid2" uuid DEFAULT gen_random_uuid()
);

$default() 또는 $defaultFn()을 사용하면, 런타임에 기본값을 생성하고 모든 삽입 쿼리에서 이 값을 사용할 수 있습니다. 이 함수들은 uuid, cuid, cuid2 등 다양한 구현을 활용하는 데 도움을 줄 수 있습니다.

참고: 이 값은 drizzle-kit 동작에 영향을 미치지 않으며, drizzle-orm에서만 런타임에 사용됩니다.

import { text, pgTable } from "drizzle-orm/pg-core";
import { createId } from '@paralleldrive/cuid2';

const table = pgTable('table', {
	id: text().$defaultFn(() => createId()),
});

$onUpdate() 또는 $onUpdateFn()을 사용하면, 런타임에 기본값을 생성하고 모든 업데이트 쿼리에서 이 값을 사용할 수 있습니다. 이 함수는 행이 업데이트될 때 호출되며, 반환된 값이 컬럼 값으로 사용됩니다. 만약 기본값(또는 $defaultFn)이 제공되지 않았다면, 이 함수는 행이 삽입될 때도 호출되고, 반환된 값이 컬럼 값으로 사용됩니다.

참고: 이 값은 drizzle-kit 동작에 영향을 미치지 않으며, drizzle-orm에서만 런타임에 사용됩니다.

import { integer, timestamp, text, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	updateCounter: integer().default(sql`1`).$onUpdateFn((): SQL => sql`${table.update_counter} + 1`),
	updatedAt: timestamp({ mode: 'date', precision: 3 }).$onUpdate(() => new Date()),
    	alwaysNull: text().$type().$onUpdate(() => null),
});

NOT NULL 제약 조건

NOT NULL 제약 조건은 해당 컬럼이 NULL 값을 포함할 수 없음을 의미합니다.

import { integer, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
	integer: integer().notNull(),
});
CREATE TABLE IF NOT EXISTS "table" (
	"integer" integer NOT NULL,
);

기본 키(Primary Key)

기본 키 제약 조건은 테이블의 행을 고유하게 식별할 수 있는 컬럼 또는 컬럼 그룹을 지정합니다. 이 제약 조건은 해당 값이 고유하고 NULL이 아니어야 합니다.

import { serial, pgTable } from "drizzle-orm/pg-core";

const table = pgTable('table', {
    id: serial().primaryKey(), // id 컬럼을 기본 키로 설정
});
CREATE TABLE IF NOT EXISTS "table" (
    "id" serial PRIMARY KEY NOT NULL, -- id 컬럼을 기본 키로 설정
);