Skip to content

SafeQL Practice

sh
pnpm i postgres
sh
pnpm i -D eslint libpg-query @ts-safeql/eslint-plugin
js
import safeql from '@ts-safeql/eslint-plugin/config'
import tseslint from 'typescript-eslint'

export default tseslint.config(
  {
    languageOptions: {
      parserOptions: {
        projectService: true,
      },
    },
  },
  safeql.configs.connections({
    // read more about configuration in the next section
    databaseUrl: 'postgres://postgres:postgres@localhost:5432/postgres',
    targets: [{ tag: 'sql' }],
  }),
)
ts
import postgres from 'postgres'

const sql = postgres(`postgres://postgres:postgres@localhost:5432/****`)

async function createKakeiboTable() {
  return sql.unsafe(`
    CREATE TABLE IF NOT EXISTS KAKEIBO (
      date DATE,
      himoku VARCHAR(100),
      memo VARCHAR(100),
      nyukin INTEGER,
      shukin INTEGER
    );
  `)
}

async function seedKakeibo() {
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2023-12-10', '給料', '11月の給料', 280000, 0)`
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2023-12-18', '水道光熱費', '水道代', 0, 4200)`
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2023-12-24', '食費', 'レストランみやび', 0, 5000)`
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2023-12-25', '移住日', 'レストラン', 0, 5000)`
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2024-01-10', '給料', '12月の給料', 280000, 0)`
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2024-01-13', '教養娯楽費', 'スッキリシネマズ', 0, 1800)`
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2024-01-14', '食費', '新年会', 0, 5000)`
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2024-01-15', '移住日', '2月の家賃払い', 0,80000)`
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2024-02-03', '食費', 'コーヒーを購入', 0, 450)`
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2024-02-04', '教養娯楽費', 'お小遣い', 50000, 0)`
}

async function main() {
  try {
    await createKakeiboTable()
    await seedKakeibo()
    const result = await sql`SELECT * FROM KAKEIBO`
    console.log(result)
  } catch (e) {
    console.error('❌ エラーが発生しました:', e)
    await sql.end()
    process.exit(1)
  }
}

main()

取得結果

sh
Result(20) [
  {
    date: 2023-12-10T00:00:00.000Z,
    himoku: '給料',
    memo: '11月の給料',
    nyukin: 280000,
    shukin: 0
  },
  {
    date: 2023-12-18T00:00:00.000Z,
    himoku: '水道光熱費',
    memo: '水道代',
    nyukin: 0,
    shukin: 4200
  },
  {
    date: 2023-12-24T00:00:00.000Z,
    himoku: '食費',
    memo: 'レストランみやび',
    nyukin: 0,
    shukin: 5000
  },
  {
    date: 2023-12-25T00:00:00.000Z,
    himoku: '移住日',
    memo: 'レストラン',
    nyukin: 0,
    shukin: 5000
  },
  {
    date: 2024-01-10T00:00:00.000Z,
    himoku: '給料',
    memo: '12月の給料',
    nyukin: 280000,
    shukin: 0
  },
  {
    date: 2024-01-13T00:00:00.000Z,
    himoku: '教養娯楽費',
    memo: 'スッキリシネマズ',
    nyukin: 0,
    shukin: 1800
  },
  {
    date: 2024-01-14T00:00:00.000Z,
    himoku: '食費',
    memo: '新年会',
    nyukin: 0,
    shukin: 5000
  },
  {
    date: 2024-01-15T00:00:00.000Z,
    himoku: '移住日',
    memo: '2月の家賃払い',
    nyukin: 0,
    shukin: 80000
  },
  {
    date: 2024-02-03T00:00:00.000Z,
    himoku: '食費',
    memo: 'コーヒーを購入',
    nyukin: 0,
    shukin: 450
  },
  {
    date: 2024-02-04T00:00:00.000Z,
    himoku: '教養娯楽費',
    memo: 'お小遣い',
    nyukin: 50000,
    shukin: 0
  },
  {
    date: 2023-12-10T00:00:00.000Z,
    himoku: '給料',
    memo: '11月の給料',
    nyukin: 280000,
    shukin: 0
  },
  {
    date: 2023-12-18T00:00:00.000Z,
    himoku: '水道光熱費',
    memo: '水道代',
    nyukin: 0,
    shukin: 4200
  },
  {
    date: 2023-12-24T00:00:00.000Z,
    himoku: '食費',
    memo: 'レストランみやび',
    nyukin: 0,
    shukin: 5000
  },
  {
    date: 2023-12-25T00:00:00.000Z,
    himoku: '移住日',
    memo: 'レストラン',
    nyukin: 0,
    shukin: 5000
  },
  {
    date: 2024-01-10T00:00:00.000Z,
    himoku: '給料',
    memo: '12月の給料',
    nyukin: 280000,
    shukin: 0
  },
  {
    date: 2024-01-13T00:00:00.000Z,
    himoku: '教養娯楽費',
    memo: 'スッキリシネマズ',
    nyukin: 0,
    shukin: 1800
  },
  {
    date: 2024-01-14T00:00:00.000Z,
    himoku: '食費',
    memo: '新年会',
    nyukin: 0,
    shukin: 5000
  },
  {
    date: 2024-01-15T00:00:00.000Z,
    himoku: '移住日',
    memo: '2月の家賃払い',
    nyukin: 0,
    shukin: 80000
  },
  {
    date: 2024-02-03T00:00:00.000Z,
    himoku: '食費',
    memo: 'コーヒーを購入',
    nyukin: 0,
    shukin: 450
  },
  {
    date: 2024-02-04T00:00:00.000Z,
    himoku: '教養娯楽費',
    memo: 'お小遣い',
    nyukin: 50000,
    shukin: 0
  }
]

RDBの基本構造

  • RDBには複数の行が入っており、それぞれの表をテーブル(table)という。
  • ここのテーブルには名前がついており、その名前をテーブル名という。
  • テーブルは行(row)と列(column)で構成される。
  • 1つの行が1件のデータに対応する。列はそのデータの要素に対応する。

※ 行をレコード、列をカラムやフィールドと呼ぶこともある。

SQLの操作

  1. 入金額が50,000円に等しい行を検索してすべての列を表示する。
ts
import postgres from 'postgres'

const sql = postgres(`postgres://postgres:postgres@localhost:5432/****`)

async function createKakeiboTable() {
  return sql.unsafe(`
    CREATE TABLE IF NOT EXISTS KAKEIBO (
      date DATE,
      himoku VARCHAR(100),
      memo VARCHAR(100),
      nyukin INTEGER,
      shukin INTEGER
    );
  `)
}

async function seedKakeibo() {
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2023-12-10', '給料', '11月の給料', 280000, 0)`
  await sql`INSERT INTO KAKEIBO (date, himoku, memo, nyukin, shukin) VALUES ('2023-12-18', 'ボーナス', 'ボーナス', 50000, 0)`
}

async function main() {
  try {
    await createKakeiboTable()
    await seedKakeibo()
    const result = await sql`SELECT * FROM KAKEIBO WHERE nyukin = 50000`
    console.log(result)
  } catch (e) {
    console.error('❌ エラーが発生しました:', e)
    await sql.end()
    process.exit(1)
  }
}

main()

取得結果

sh
Result(1) [
  {
    date: 2023-12-18T00:00:00.000Z,
    himoku: 'ボーナス',
    memo: 'ボーナス',
    nyukin: 50000,
    shukin: 0
  }
]
  1. 出勤額が4,000円を超える行を全て削除する
ts
await sql`DELETE FROM KAKEIBO WHERE shukin > 4000`
  1. 2024年2月3日のメモを「カフェラテを購入」に変更する。
ts
await sql`UPDATE KAKEIBO SET memo = 'カフェラテを購入' WHERE date = '2024-02-03'`