查看: 189|回復: 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
跳轉到指定樓層
1#
發表于 2020-9-15 03:48 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式

最先答對且答案未經編輯的puber將獲得紀念章一枚(答案不可編輯但可發新貼補充或糾正),其他會員如果提供有價值的分析、討論也可獲得紀念章一枚。

每兩周的優勝者可獲得itpub獎勵的技術圖書一本。

以往舊題索引:
http://www.3490925.live/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
2#
發表于 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
3#
 樓主| 發表于 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
4#
 樓主| 發表于 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號
  
快速回復 返回頂部 返回列表
30岁的男人干啥赚钱快赚钱多 股票牛股 15选5经典杀号公式 多乐彩板材 上市公司基金配资 四川快乐12开奖结果图真准网 pc蛋蛋真送q币 浙江体彩6十1开奖结果 广西快三计划软件手机 北京配资公司 安徽十一选五开奖查询