罗马数字作为数据库中的页码

时间:2012-10-03 17:00:39

标签: sql database-schema roman-numerals

假设我有下表:

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_labelpage_end_label空白我可能实际上保存< / em>空间!

这听起来像是一个合理的解决方案吗?或者我错过了潜在的陷阱/缺点?

1 个答案:

答案 0 :(得分:1)

虽然我通常会将演示文稿详细信息留给表示层,但在这种情况下我同意@njk。

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

重申一下,我假设页码有一些合理的上限,你不会转换任何你需要数百万个值的查找表的东西。这足以说服我在表示层中使用代码。

似乎已经any number of functions out there,所以你不必重新发明轮子来创建这个表。

即使您将来转向其他方案,使用罗马数字传入数据的想法意味着您可能始终需要此类表格才能导入书籍/部分。