查看: 216|回复: 3

[每日一题] PL/SQL Challenge 每日一题:2020-9-9 结果缓存与隐式转换

[复制链接]
论坛徽章:
527
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
发表于 2020-9-15 03:48 | 显示全部楼层 |阅读模式

最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。

每两周的优胜者可获得itpub奖励的技术图书一本。

以往旧题索引:
http://www.itpub.net/forum.php?m ... eid&typeid=1808

原始出处:
https://devgym.oracle.com/

作者:Steven Feuerstein

运行环境:SQLPLUS, SERVEROUTPUT已打开, 最低版本要求:11.2
注:本题给出答案时候要求给予简要说明才能得到奖品

我记性很差,总是忘记事情,哪怕是我人生中那些重要的事件。所以我决定是时候利用ORACLE数据库来弥补我的记忆了。我创建了一张表,插入了几个重大事件,并且创建了一些PL/SQL 对象。

CREATE TABLE qz_big_moments
(
   what_happened   VARCHAR2 (100),
   happened_on     DATE
)
/

BEGIN   
   INSERT INTO qz_big_moments (what_happened, happened_on)
        VALUES ('Got married', DATE '2020-01-03');

   INSERT INTO qz_big_moments (what_happened, happened_on)
        VALUES ('First hole in one', DATE '2020-03-01');

   COMMIT;
END;
/

CREATE OR REPLACE FUNCTION qz_what_happened (date_in IN VARCHAR2)
   RETURN VARCHAR2
   AUTHID DEFINER
   RESULT_CACHE
IS
   l_info   qz_big_moments.what_happened%TYPE;
BEGIN
   DBMS_OUTPUT.put_line (
         'Fetching row for '
      || TO_DATE (date_in, 'YYYY-MM-DD')
      || ' -> '
      || TO_DATE (date_in));

   SELECT what_happened
     INTO l_info
     FROM qz_big_moments
    WHERE happened_on = TO_DATE (date_in);

   RETURN l_info;
END;
/

CREATE OR REPLACE PROCEDURE qz_init (format_in IN VARCHAR2)
   AUTHID DEFINER
IS
BEGIN
   EXECUTE IMMEDIATE
      (q'[ALTER SESSION SET nls_date_format = ']' || format_in || q'[']');

   DBMS_OUTPUT.put_line ('What''s your big moment? (' || format_in || ')');
END;
/

哪些选项在执行之后,下列之一为真:

1. 文本  "First hole in one" 出现两次

或者

2. 文本 "Got married" 出现两次

(A)
BEGIN
   qz_init ('YYYY-DD-MM');
   DBMS_OUTPUT.put_line (qz_what_happened (date_in => '2020-01-03'));
   qz_init ('YYYY-MM-DD');
   DBMS_OUTPUT.put_line (qz_what_happened (date_in => '2020-01-03'));
END;
/

(B)
BEGIN
   qz_init ('YYYY-MM-DD');
   DBMS_OUTPUT.put_line (qz_what_happened (date_in => DATE '2020-01-03'));
   qz_init ('YYYY-DD-MM');
   DBMS_OUTPUT.put_line (qz_what_happened (date_in => DATE '2020-03-01'));
END;
/

(C)
BEGIN
   qz_init ('YYYY-DD-MM');
   DBMS_OUTPUT.put_line (qz_what_happened (date_in => DATE '2020-01-03'));
   DBMS_OUTPUT.put_line (qz_what_happened (date_in => DATE '2020-03-01'));
END;
/

(D)
BEGIN
   qz_init ('YYYY-MM-DD');
   DBMS_OUTPUT.put_line (qz_what_happened (date_in => DATE '2020-01-03'));
   DBMS_OUTPUT.put_line (qz_what_happened (date_in => DATE '2020-01-03'));
END;
/

论坛徽章:
18
山治
日期:2017-01-11 16:13:26妮可·罗宾
日期:2020-09-01 08:52:07秀才
日期:2018-01-02 10:32:00技术图书徽章
日期:2017-08-23 14:17:00技术图书徽章
日期:2017-08-23 14:17:00秀才
日期:2017-08-11 15:30:05秀才
日期:2017-08-11 15:30:05秀才
日期:2017-08-11 15:30:05秀才
日期:2017-08-11 15:30:05秀才
日期:2017-08-11 15:30:05
发表于 2020-9-15 09:33 | 显示全部楼层
答案  ABD


A) 正确,qz_init初始化两次时间,虽然入参一样都是'2020-01-03',但是转换后就不一致了,
         但是由于qz_what_happened有RESULT_CACHE选项,所以输出一致。

B) 正确,传入的是时间类型,而存储过程要求的是字符类型,这个地方有一个隐式转换,所以没有报错。
         虽然入参数不一样,但是时间格式不一致,所以其实入参是一样的,输出也是一致。

C) 错误,同B同样存在隐式转换的问题,然后入参不同,有转换的情况下z_what_happened有RESULT_CACHE选项失效
         所以两次输出的内容不同

D) 正确,修复了C的问题,存在隐式转换,但入参一样,所以输出也一致

使用道具 举报

回复
论坛徽章:
527
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
 楼主| 发表于 2020-9-16 03:17 | 显示全部楼层
答案ABD, 2楼得奖。

A:
我是将一个字符串参数值传递给一个字符串参数,所以没有隐式转换。

这也就意味着,第一次调用qz_what_happened后,该输入值和返回值会被缓存。第二次调用时,函数的主体不会被执行。

即使NLS的日期格式已经发生了变化!

这就指出了一个问题----在决定哪些函数需要 "结果缓存"时,函数内部对特定会话的依赖性可能导致返回错误的值。

但是在这个题目中,这个选项是正确的。

输出:

What's your big moment? (YYYY-DD-MM)
Fetching row for 2020-03-01 -> 2020-01-03
First hole in one
What's your big moment? (YYYY-MM-DD)
First hole in one

B:
现在乍一看,我向函数的参数列表传递了两个不同的值, 所以函数体应该被执行两次。但它只执行了一次,因为参数的数据类型是VARCHAR2,而我提供的是一个日期。因此,NLS的日期格式设置发生作用,由于我把第一次调用的MM和DD换成了第二次调用的MM,所以当把值传给函数时,两次都是同一个值。

输出:

What's your big moment? (YYYY-MM-DD)
Fetching row for 2020-01-03 -> 2020-01-03
Got married
What's your big moment? (YYYY-DD-MM)
Got married

C:
现在我传入了两个不同的日期作为参数,它们都依靠相同的默认NLS日期格式来隐式转换为字符串。因此,函数体被执行了两次,日期是不同的(从字符串值隐式转换回来),并且获取了两条不同的记录。

输出:

What's your big moment? (YYYY-DD-MM)
Fetching row for 2020-01-03 -> 2020-03-01
Got married
Fetching row for 2020-03-01 -> 2020-01-03
First hole in one


D:
现在我传入了两次相同的日期,会话中的NLS日期格式相同,所以函数体只被执行了一次,同样的值 "Got married" 被返回两次。

输出:

What's your big moment? (YYYY-MM-DD)
Fetching row for 2020-01-03 -> 2020-01-03
Got married
Got married


使用道具 举报

回复
论坛徽章:
527
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
 楼主| 发表于 2020-9-16 03:17 | 显示全部楼层
答案ABD, 2楼得奖。

A:
我是将一个字符串参数值传递给一个字符串参数,所以没有隐式转换。

这也就意味着,第一次调用qz_what_happened后,该输入值和返回值会被缓存。第二次调用时,函数的主体不会被执行。

即使NLS的日期格式已经发生了变化!

这就指出了一个问题----在决定哪些函数需要 "结果缓存"时,函数内部对特定会话的依赖性可能导致返回错误的值。

但是在这个题目中,这个选项是正确的。

输出:

What's your big moment? (YYYY-DD-MM)
Fetching row for 2020-03-01 -> 2020-01-03
First hole in one
What's your big moment? (YYYY-MM-DD)
First hole in one

B:
现在乍一看,我向函数的参数列表传递了两个不同的值, 所以函数体应该被执行两次。但它只执行了一次,因为参数的数据类型是VARCHAR2,而我提供的是一个日期。因此,NLS的日期格式设置发生作用,由于我把第一次调用的MM和DD换成了第二次调用的MM,所以当把值传给函数时,两次都是同一个值。

输出:

What's your big moment? (YYYY-MM-DD)
Fetching row for 2020-01-03 -> 2020-01-03
Got married
What's your big moment? (YYYY-DD-MM)
Got married

C:
现在我传入了两个不同的日期作为参数,它们都依靠相同的默认NLS日期格式来隐式转换为字符串。因此,函数体被执行了两次,日期是不同的(从字符串值隐式转换回来),并且获取了两条不同的记录。

输出:

What's your big moment? (YYYY-DD-MM)
Fetching row for 2020-01-03 -> 2020-03-01
Got married
Fetching row for 2020-03-01 -> 2020-01-03
First hole in one


D:
现在我传入了两次相同的日期,会话中的NLS日期格式相同,所以函数体只被执行了一次,同样的值 "Got married" 被返回两次。

输出:

What's your big moment? (YYYY-MM-DD)
Fetching row for 2020-01-03 -> 2020-01-03
Got married
Got married


使用道具 举报

回复

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

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 
京ICP备09055130号-4  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表