배열, 날짜 및 인덱스에 대한 SQL 테이블 설계 - ORM에서 배운 것

12408 단어 ormnosqlsqlsqlite
요컨대 적절한 주석과 섹션으로 고칠 수 있습니다. 또한 다대다 관계를 두려워하지 마십시오.

SQL 기반 정의 만들기



better-sqlite3 으로 했으므로 JavaScript/TypeScript 라도 await 는 필요 없습니다.

  init() {
    this.db.exec(/* sql */ `
    CREATE TABLE IF NOT EXISTS tag (
      id        INT PRIMARY KEY,
      [name]    TEXT NOT NULL UNIQUE COLLATE NOCASE
    );
    `)

    this.db.exec(/* sql */ `
    CREATE TABLE IF NOT EXISTS token (
      [entry]       TEXT PRIMARY KEY,
      -- sub m2m
      -- sup m2m
      -- var m2m
      frequency     FLOAT,
      hanzi_level   INT,
      vocab_level   INT,
      -- tag m2m
      pinyin        TEXT,
      english       TEXT,
      [data]        TEXT -- json // This can be queried using JSON1 extension
    );

    CREATE INDEX IF NOT EXISTS idx_token_frequency ON token(frequency);
    CREATE INDEX IF NOT EXISTS idx_token_hanzi_level on token(hanzi_level);
    CREATE INDEX IF NOT EXISTS idx_token_vocab_level on token(vocab_level);

    CREATE TABLE IF NOT EXISTS token_sub (
      parent  TEXT NOT NULL REFERENCES token,
      child   TEXT NOT NULL REFERENCES token,
      PRIMARY KEY (parent, child)
    );

    CREATE TABLE IF NOT EXISTS token_sup (
      parent  TEXT NOT NULL REFERENCES token,
      child   TEXT NOT NULL REFERENCES token,
      PRIMARY KEY (parent, child)
    );

    CREATE TABLE IF NOT EXISTS token_var (
      parent  TEXT NOT NULL REFERENCES token,
      child   TEXT NOT NULL REFERENCES token,
      PRIMARY KEY (parent, child)
    );

    CREATE TABLE IF NOT EXISTS token_tag (
      [entry]   TEXT NOT NULL REFERENCES token,
      tag_id    INT NOT NULL REFERENCES tag,
      PRIMARY KEY ([entry], tag_id)
    );
    `)
  }


그건 그렇고, /* sql */와의 거래는 이 VSCode 확장 - Comment tagged templates 입니다. 나는 그것을 통해 정말 추천합니다.



ORM과 유사하게 만들기



이제 의사 ORM에 대한 class 구문을 사용합니다.

import sqlite3 from 'better-sqlite3'

class Db {
  db: sqlite3.Database

  constructor(public filename: string) {
    this.db = sqlite3(filename)
  }

  init() { ... }

  tagFindOrCreate(names: string[]): number[] { ... }

  tokenFindOrCreate(names: string[]): string[] { ... }

  ...
}


실제로 주요 테이블의 이름으로 그룹화methods할 수 있지만 그렇게 직관적이지는 않습니다.

import sqlite3 from 'better-sqlite3'

class Db {
  tag = {
    findOrCreate: this.tagFindOrCreate.bind(this)
  }

  token = {
    findOrCreate: this.tokenFindOrCreate.bind(this)
  }

  ...
}


배열, 날짜, JSON을 만드는 방법


SELECT 집계(json_group_array/group_concat) 내에서 사용

  SELECT
    [entry], pinyin, english, frequency,
    (
      SELECT group_concat(child, '') FROM token_sub WHERE parent = [entry] GROUP BY parent
    )   sub,
    (
      SELECT group_concat(child, '') FROM token_sup WHERE parent = [entry] GROUP BY parent
    )   sup,
    (
      SELECT group_concat(child, '') FROM token_var WHERE parent = [entry] GROUP BY parent
    )   [var]
  FROM token


네이티브가 아닌 데이터 구조로 변환하는 경우(일부 PostGres 드라이버 또는 HarperDB가 훨씬 더 쉽다는 것을 알고 있음) 특정 명명 규칙을 사용하여 이를 알릴 수 있습니다.

    zh.db
      .prepare(
        /* sql */ `
  SELECT
    [entry], _json_data, _date_updatedAt
    (
      SELECT json_group_array(child) FROM token_sub WHERE parent = [entry] GROUP BY parent
    )   _json_sub
  FROM token
  LIMIT 10
  `
      )
      .all().map((r) => {
        const out: Record<string, any> = {}
        let m: RegExpExecArray | null
        for (const [k, v] of Object.entries(r)) {
          if (v === null) {
            continue
          }

          if (m = /^_json_(.+)$/.exec(k)) {
            out[m[1]] = JSON.parse(v)
          } else if (m = /^_date_(.+)$/.exec(k)) {
            out[m[1]] = new Date(v)
          } else {
            out[k] = v
          }
        }

        return out
      })


CASCADE/트리거에 대한 생각



필수는 아닙니다. 항상 권장되는 것은 아닙니다.

그러나 데이터베이스를 정기적으로 모니터링/정리해야 합니다.

좋은 웹페이지 즐겨찾기