假设我有下表:
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_label
从page_end_label
罗马转换为阿拉伯语。两个额外的整数加上位意味着每条记录多出 8 个字节的额外存储空间,但大多数记录都留下了page_start_label
空白,page_end_label
我实际上可能会节省空间!
这听起来像是一个合理的解决方案吗?还是我错过了潜在的陷阱/不利因素?