3

次のテーブルがあるとします。

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実際にスペースを節約できる可能性があります!

これは合理的な解決策のように聞こえますか? または、潜在的な落とし穴/欠点を見逃していますか?

4

1 に答える 1

1

通常、プレゼンテーションの詳細はプレゼンテーション レイヤーに任せますが、この場合は @njk に同意します。

入力データの一部としてローマ数字が含まれ、複数のフロントエンドと翻訳を提供する必要があり、SQL で簡単にソートできるようにする必要があるため、ローマ数字とそのルックアップ テーブルを事前に計算します。かなり大きなページ番号 (おそらく 32,767 ですが、データはわかっています) までの整数に相当します。

繰り返しますが、ページ番号には合理的な上限があり、何百万もの値のルックアップ テーブルが必要な場合は何も変換しないと想定しています。これは、このためにプレゼンテーション層でコードを使用するように私を説得するのに十分です.

世の中にはすでにたくさんの関数があるように見えるので、このテーブルを作成するために車輪を再発明する必要はありません。

将来別のスキームに移行したとしても、ローマ数字を含む受信データのアイデアは、ブック/セクションをインポートできるようにするために、このタイプのテーブルが常に必要になる可能性があることを意味します.

于 2012-10-03T17:20:21.937 に答える