PL/SQL Challenge 每日一题:2016-9-1 数字的格式化

[复制链接]
查看11 | 回复6 | 2008-9-15 01:28:12 | 显示全部楼层 |阅读模式
最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。
每两周的优胜者可获得itpub奖励的技术图书一本。
以往旧题索引:
http://www.itpub.net/forum.php?m ... eid&typeid=1808
原始出处:
http://www.plsqlchallenge.com/
作者:Kim Berg Hansen
运行环境:SQLPLUS, SERVEROUTPUT已打开
注:本题给出答案时候要求给予简要说明才能得到奖品
我有一张表保存着一本书的章节标题:
create table plch_chapters (
ch# integer primary key
, title varchar2(30)
)
/
insert into plch_chapters values (1, 'Aggregation')
/
insert into plch_chapters values (2, 'Analytic Functions')
/
insert into plch_chapters values (3, 'Model Clause')
/
insert into plch_chapters values (4, 'Row Pattern Matching')
/
commit
/
我想要创建一个内容列表,把章节数标记成罗马数字。
为了使得章节名称正确对齐,罗马数字必须向右对齐,后面跟着一个句号和一个空格,然后是章节标题。
根据定义,章节数不会超过25,所以可能最长的罗马数字会是五个字符(XVIII 和 XXIII),所以为了向右对齐,数字必须在左边补齐至五个字符。
为了得到这个内容表我有如下未完成的查询:
select ##REPLACE##

as table_of_contents
from plch_chapters
order by ch#
/
哪些选项包含了一个表达式可用来取代##REPLACE##使得查询返回这个输出:
TABLE_OF_CONTENTS
-------------------------------------
I. Aggregation
II. Analytic Functions
III. Model Clause
IV. Row Pattern Matching
(主意罗马数字向左补齐长度为5,所以句号永远是字符串的第六个字符)

(A)
to_char(ch#, 'RN') || '. ' || title
(B)
lpad(ltrim(to_char(ch#, 'RN')), 5) || '. ' || title
(C)
lpad(to_char(ch#, 'FMRN'), 5) || '. ' || title
(D)
to_char(ch#, 'RN5') || '. ' || title
(E)
lpad(
to_char(ch#, 'FMRN') || '. ' || title
, length(title) + 7
)
(F)
lpad(
to_char(ch#, 'FMRN ". ' || title ||'"')
, length(title) + 7
)
(G)
substr(
to_char(ch#, 'RN') || '. ' || title
, -(length(title) + 7)
)
(H)
substr(
to_char(ch#, 'RN')
, -5
) || '. ' || title
(I)
substr(
to_char(ch#, 'RN') || '. ' || title
, length(to_char(1, 'RN')) - 5 + 1
)
(J)
substr(
to_char(ch#, 'RN')
, length(to_char(1, 'RN')) - 5 + 1
) || '. ' || title


回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
方法真多
居然左边这么多空格
SQL> select '*'||to_char(4,'RN') from dual;
'*'||TO_CHAR(4,'
----------------
*
IV

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
https://docs.oracle.com/cd/B1930 ... ents004.htm#g195443
RN
rn

RN
rn

Returns a value as Roman numerals in uppercase.
Returns a value as Roman numerals in lowercase.
Value can be an integer between 1 and 3999.

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
BCEGHIJ
DF是无效数字有语法错,
A 在前面占字符远远超过5个
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案BCEGHIJ, 4楼得奖。
A:
一个单独的格式化模型元素总是被补齐到固定的长度,那就是可能到达的最大长度(把NLS设置也考虑进去)。因为RN可以处理1到3999的整数,可能的最长的字符串是MMMDCCCLXXXVIII (=3888),它有15个字符。所以此处的TO_CHAR表达式把一个罗马数字向左补齐到15的长度,得到这个错误输出:
TABLE_OF_CONTENTS
-------------------------------------

I. Aggregation

II. Analytic Functions

III. Model Clause

IV. Row Pattern Matching
B:(不推荐)
我们可以把前一选项的所有空白符都截除,然后补齐到我们需要的5个字符。
C:(推荐)但是比起截除空白符更容易的做法是使用FM格式(Fill Mode),这是决定一个格式化元素是否要补齐的开关。FMRN给了我们一个未追加空白符的罗马数字,然后我们就可以补齐到所需的长度。
D: RN格式化元素并不支持用一个数字来指定长度。这个选项会报错:
ORA-01481: invalid number format model.
E: (不推荐)
我们在C选项只是LPAD了TO_CHAR的输出,然后我们追加了句号和章节标题。此处我们先追加,然后我们需要把标题+句号和空格的2个字符+所需的5个字符全部补齐。这是可行的,但是很费劲。
F: 这个试图做到和E一样,只是把句号和标题作为带引号的字面量字符串放到格式化模型中。如果这是TO_CHAR(DATE)也许能行,但是TO_CHAR(NUMBER) 不支持格式模型中的引号字面量。所以这会报错:
ORA-01481: invalid number format model.
G: (不推荐)
不同于E选项中对FMRN字符进行补齐,我们也可以利用不带FM的RN模型来创建一个字符串,它左边被补上了多于的空格。因此我们可以执行SUBSTR,位置是从右到左计算标题长度+句号和空格的2个字符+所需的5个字符
H:正如G是E的SUBSTR版本,C也有一个SUBSTR版本。仅仅带有RN的TO_CHAR表达式会在我们的罗马数字左边补上很多空格,所以我们可以用SUBSTR来仅仅保留最后5个字符。然后我们在后面加上句号和标题。
I:
如果不像G和H在SUBSTR的表达式中“从后往前算”,我们一也可以“从前往后算”。表达式"length(to_char(1, 'RN')) - 5 + 1" 的结果是11, 因为能支持的最长的罗马数字是15个字符(见A的解释),但是不用将11写成硬编码,如果未来版本的RN支持的值大于3999, 这个计算方法仍然适用。
J:
当我们“从前往后算”的时候,不管我们追加句号和标题是在SUBSTR之前(上一选项)或者是之后(当前选项),结果都是一样的。

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
涨姿势了.....
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
学习了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行