PL/SQL Challenge 每日一题:2013-10-24 CASE表达式

[复制链接]
查看11 | 回复6 | 2008-9-15 01:28:12 | 显示全部楼层 |阅读模式
最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。
以往旧题索引:
http://www.itpub.net/forum.php?m ... eid&typeid=1808
http://www.itpub.net/thread-1499223-1-1.html
原始出处:
http://www.plsqlchallenge.com/
作者:Steven Feuerstein
运行环境:SQLPLUS, SERVEROUTPUT已打开
注:本题给出答案时候要求给予简要说明才能得到奖品
在PL/SQL Challenge网站,我们想要在2014年加入年度冠军赛,所以是时候将我们许多比赛相关的逻辑(以前只是为季度赛)变得更通用了。下面这个函数就是这个重构过程的一部分。
哪些选项提供了这个函数的函数体:
CREATE OR REPLACE FUNCTION plch_start_date (
frequency_in IN VARCHAR2,
date_inIN DATE DEFAULT SYSDATE)
RETURN VARCHAR2
IS
使得我执行下面这个代码块之后:
BEGIN
DBMS_OUTPUT.put_line (
plch_start_date ('Y', DATE '2014-01-01'));
DBMS_OUTPUT.put_line (
plch_start_date ('Q', DATE '2014-01-01'));
DBMS_OUTPUT.put_line (
plch_start_date ('M', DATE '2013-11-01'));
END;
/
我在屏幕上会看到这个输出:
2013-01-01
2013-10-01
2013-10-01
(A)
BEGIN
IF frequency_in = 'Y'
THEN
RETURN TO_CHAR (ADD_MONTHS (date_in, -12), 'YYYY-MM-DD');
ELSIF frequency_in = 'Q'
THEN
RETURN TO_CHAR (ADD_MONTHS (date_in, -3), 'YYYY-MM-DD');
ELSIF frequency_in = 'M'
THEN
RETURN TO_CHAR (ADD_MONTHS (date_in, -1), 'YYYY-MM-DD');
END IF;
END;
/
(B)
BEGIN
RETURN TO_CHAR (

CASE frequency_in

WHEN 'Y' THEN ADD_MONTHS (date_in, -12)

WHEN 'Q' THEN ADD_MONTHS (date_in, -3)

WHEN 'M' THEN ADD_MONTHS (date_in, -1)

END,

'YYYY-MM-DD');
END;
/
(C)
TYPE shifts_t IS TABLE OF PLS_INTEGER
INDEX BY VARCHAR2 (1);
l_shifts shifts_t;
BEGIN
l_shifts ('M') := 1;
l_shifts ('Q') := 3;
l_shifts ('Y') := 12;
RETURN TO_CHAR (

ADD_MONTHS (date_in, -1 * l_shifts (frequency_in)),

'YYYY-MM-DD');
END;
/
(D)
BEGIN
RETURN TO_CHAR (

ADD_MONTHS (

date_in,

CASE frequency_in

WHEN 'Y' THEN -12

WHEN 'Q' THEN -3

WHEN 'M' THEN -1

END),

'YYYY-MM-DD');
END;
/
(E)
BEGIN
RETURN TO_CHAR ( TRUNC (date_in - 1,
REPLACE (frequency_in, 'M', 'MM')), 'YYYY-MM-DD');
END;
/


回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
觉得e有问题
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
E选项不太确定啊,主要是‘Q’,这个是转为季度,所以感觉('Q', DATE '2014-01-01'-1) 应该会trunc为2013-10-01。
那我猜正确答案是A,B,C,D,E


回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案:ABCDE
A,B,D可以作为对比,相对于A来说,B应该要好,D对于B来说,没有必要那样做了,推荐B方式
C,这种赋值方式感觉有点牵强了,对于本题而言,似乎有点大材小用了
E,正确,当frequency_in 为Y的时候,取的是year,是MM的时候取月,
Q的时候取的是本季度的开始月的第一天(看文档上说的)
SELECT TO_CHAR(TRUNC(DATE '2014-01-01' - 1, 'Q'), 'YYYY-MM-DD') FROM DUAL;
------------------------------------
1
2013-10-01
SELECT TO_CHAR(TRUNC(DATE '2013-08-25', 'Q'), 'YYYY-MM-DD') FROM DUAL;
----------------------------------
1
2013-07-01
SELECT TO_CHAR(TRUNC(DATE '2013-07-01' - 1, 'Q'), 'YYYY-MM-DD') FROM DUAL;
------------------------------------------
1
2013-04-01

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
OO周末凌晨就起来答题?这精神可嘉啊
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
每个选项都对
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案ABCDE, 4楼得奖。
A:(不推荐)
它输出了正确信息,但是方法不够好:它用了三个RETURN子句,重复了整个表达式来产生字符串型的日期。
首先,最好在执行部分的底部仅有一个RETURN,这是为了避免"ORA-06503: PL/SQL: Function returned without value"这个很囧的错误。
其次,为什么要重复这个逻辑?应该合并起来!
B:(不推荐)
这个选项用了CASE来变成单个的RETURN并且去除了多余的代码,但是还可以做得更好!
C:(推荐)
这个选项完全避免了使用CASE表达式,相反,它将唯一可变的元素放到一个由字符串做索引的集合,从而将算法“软编码化”。
很酷对吧?唯一的问题可能是:这对一个相当简单的公式是不是有点杀鸡用牛刀?有可能...但绝对是应该记住的一个好技术!
D:(推荐)
嗯...这里我们找到了CASE的正确用法来隔离和选择公式中唯一可变的部分:我们必须“往回走”的月份数。
E:(不推荐)
我们的评阅者Elic认为这是一个聪明的方法,完全避免了条件逻辑!
然而,我(Steven Feuerstein)不推荐这个选项,因为它要求传入的日期必须是下一个期间的第一天。
回复

使用道具 举报

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

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行