SafeQL Practice
sh
pnpm i postgressh
pnpm i -D eslint libpg-query @ts-safeql/eslint-pluginjs
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の操作
- 入金額が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
}
]- 出勤額が4,000円を超える行を全て削除する
ts
await sql`DELETE FROM KAKEIBO WHERE shukin > 4000`- 2024年2月3日のメモを「カフェラテを購入」に変更する。
ts
await sql`UPDATE KAKEIBO SET memo = 'カフェラテを購入' WHERE date = '2024-02-03'`