次のテーブルがあるとします。
create table Section (
id integer not null primary key,
book_id integer not null foreign key references Book (id),
title varchar(100) not null,
page_start varchar(10) not null,
page_end varchar(10) not null
... remaining fields ...
)
開始ページと終了ページのフィールドは varchar であることに注意してください。これは、一般的にローマ数字で書かれている序文のページ番号を含めることができるようにするためです。
私の質問は、次のように、このテーブルを変更してアプリを作成する効果的な方法は何ですか?
- 理想的にはSQLを使用して、ページの開始と終了によってセクションを正しくソートできます
- セクションの長さをページ数で計算できます
- 特定のページ番号 (「xviii」や 475 など) が特定のセクション内にあるかどうかを判断できます
次の条件/事実に留意してください。
- ユーザーが追加情報を入力する必要はありません。たとえば、接頭辞に相当するアラビア語を計算して入力する必要はありません。
- 本の事前番号付けに関する規則が存在する場合は、それが正確に守られます (したがって、たとえば、すべてのページ番号は正しいローマ字またはアラビア語の形式で入力されます)。
- 必要なフィールドを追加したり、必要に応じて別のテーブルを追加したりできます
- これは Web アプリなので、データを挿入または表示する前に、データベース内のデータに対して前処理または後処理を行うことができます。
- セクションはオンザフライで追加または削除できます。たとえば、1 つの紹介セクションがあり、後で別のセクションが追加される場合があります。ページネーションとソートは、その本のすべてのセクションで正しく維持される必要があります。
これを異なるプラットフォームのいくつかの異なる言語で実装することになる可能性があるため、コードに依存しない疑似コードが優先されます。
明確化
私は何千ものレコードを扱っているため、並べ替えなどを行うためにプログラムですべてをループすることはできません。そのため、データベース側でいくつかの作業を行う必要があります。
njk のルックアップ テーブルのアイデアを使用すると、次のようになります。
SELECT id, book_id, title, page_start, page_end,
COALESCE(RN_Lookup_End.value - RN_Lookup_Start.value + 1, CAST(page_end AS integer)-CAST(page_start AS integer) + 1) as number_of_pages
FROM
Section
LEFT JOIN RN_Lookup AS RN_Lookup_Start ON Section.page_start=RN_Lookup_Start.key
LEFT JOIN RN_Lookup AS RN_Lookup_End ON Section.page_end=RN_Lookup_End.key
ORDER BY
book_id,
CASE WHEN RN_Lookup_Start.value IS NOT NULL
THEN -1
ELSE 0
END, -- roman page numbers come before normal page numbers
COALESCE(RN_Lookup_Start.value, page_start), COALESCE(RN_Lookup_End.value, page_end)
ページ番号順に並べられたすべての本をループしたい場合。それは正しく見えますか?
考えてみると、テーブルに次の変更を加えた方が良いのではないかと思います。
create table Section (
id integer not null primary key,
book_id integer not null foreign key references Book (id),
title varchar(100) not null,
page_start integer not null,
page_end integer not null,
is_front_matter bit default 0,
page_start_label varchar(10) null,
page_end_label varchar(10) null
... remaining fields ...
)
上記のクエリは次のようになります。
SELECT id, book_id, title,
COALESCE(page_start_label, CAST(page_start as varchar)) as page_start,
COALESCE(page_end_label, CAST(page_end as varchar)) as page_end,
(page_end - page_start + 1) as number_of_pages
FROM
Section
ORDER BY
book_id, is_front_matter DESC, page_start, page_end
page_start_label
次に、挿入と更新の際にローマ字とpage_end_label
ローマ字からアラビア語に値を変換するだけです。2 つの追加の整数とビットは、レコードごとに 8 バイト強の余分なストレージを意味しますが、ほとんどのレコードが空白のままpage_start_label
になると、page_end_label
実際にスペースを節約できる可能性があります!
これは合理的な解決策のように聞こえますか? または、潜在的な落とし穴/欠点を見逃していますか?