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 ...
)

请注意,起始页和结束页字段是 varchars。这样我就可以包含通常使用罗马数字的序言中的页码。

我的问题是:修改此表和编写应用程序的有效方法是什么:

  • 我可以通过开始和结束页面正确地对部分进行排序,最好使用 SQL
  • 我可以用页数计算一个部分的长度
  • 我可以确定给定的页码(例如“xviii”或 475)是否在给定的部分内

请记住以下条件/事实:

  • 我不希望用户必须输入任何附加信息。例如,他们不必计算前缀的阿拉伯语等值并将其输入。
  • 任何可能存在的书籍预编号规则都被严格遵循(因此,例如,所有页码都将以正确的罗马或阿拉伯格式输入)
  • 我可以添加我需要的任何其他字段,如果需要,甚至可以添加一个单独的表格
  • 这是一个网络应用程序,因此我可以在插入或显示数据之前对数据库中的数据进行预处理或后处理
  • 部分可以即时添加或删除,例如可能有一个介绍部分,然后稍后添加另一个部分。该书中所有部分的分页和排序应该保持正确。

我最终可能会在不同平台上用几种不同的语言实现它,因此首选与代码无关的伪代码。

澄清

因为我要处理成千上万条记录,所以我不能以编程方式遍历所有记录来执行排序之类的操作。所以有些工作需要在数据库端进行。

使用 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_labelpage_end_label罗马转换为阿拉伯语。两个额外的整数加上位意味着每条记录多出 8 个字节的额外存储空间,大多数记录都留下了page_start_label空白,page_end_label我实际上可能会节省空间!

这听起来像是一个合理的解决方案吗?还是我错过了潜在的陷阱/不利因素?

4

1 回答 1

1

虽然我通常会将演示细节留给演示层,但在这种情况下我同意@njk。

由于您将罗马数字作为传入数据的一部分,需要潜在地服务于多个前端和翻译,并且您希望能够轻松地在 SQL 中排序,我会预先计算一个罗马数字及其查找表整数等价于一些相当大的页码(也许是 32,767,尽管你知道你的数据)。

重申一下,我假设页码有一些合理的上限,并且您不会在需要包含数百万个值的查找表的地方转换任何内容。这足以说服我为此使用表示层中的代码。

那里似乎已经有许多功能,因此您不必重新发明轮子来创建此表。

即使您将来转向不同的方案,使用罗马数字传入数据的想法意味着您可能总是需要这种类型的表才能导入书籍/章节。

于 2012-10-03T17:20:21.937 回答