PL/SQL Challenge 每周一题:2022-2-5 MAP_LANGUAGE_FROM_ISO

[复制链接]
查看11 | 回复1 | 2008-9-15 01:28:12 | 显示全部楼层 |阅读模式
本帖最后由 newkid 于 2022-2-15 00:04 编辑
最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。
每两周的优胜者可获得itpub奖励的技术图书一本。
以往旧题索引:
http://www.itpub.net/forum.php?m ... =typeid&typeid=1808
原始出处:
https://devgym.oracle.com/
作者:Kim Berg Hansen
运行环境:SQLPLUS, SERVEROUTPUT已打开, 最低版本要求:11.2
注:本题给出答案时候要求给予简要说明才能得到奖品
我有一张顾客表,里面有一个LOCALE,包含两位字符的ISO语言以及一个两位字符的地区代码。我还有一张订单表,保存着顾客的预期投递日期:
create table qz_customers (
id
integer primary key
, namevarchar2(20)
, localevarchar2(10)
);
create table qz_orders (
id
integer primary key
, customerreferences qz_customers
, shipmentdate
, description varchar2(20)
);
insert into qz_customers values (142, 'Cafe Saint-Henri', 'fr_CA');
insert into qz_customers values (261, 'Den Gamle Kaffebar', 'da_DK');
insert into qz_customers values (337, 'Kaffee Alt Wien' , 'de_AT');
insert into qz_customers values (450, 'Einstein Kaffee' , 'de_DE');
insert into qz_orders values (1002, 450, date '2022-03-01', 'Blue Mountain');
insert into qz_orders values (1003, 337, date '2022-03-04', 'Kona Peaberry');
insert into qz_orders values (1004, 261, date '2022-03-08', 'Sumatra Mandheling');
insert into qz_orders values (1005, 142, date '2022-03-11', 'Valhalla Java');
commit;
我想要一个顾客列表,带有订单投递日期,根据顾客的所在地以正确的语言显式月份的全名。
为此我写了这个未完成的查询:
select
c.name
, to_char(
d.shipment
, 'FMDD. Month YYYY'
, ##REPLACE##
) as shipment
, description
from qz_customers c
join qz_orders d
on d.customer = c.id
order by d.id;
哪些选项包含了一个表达式可以用来取代##REPLACE##,作为TO_CHAR的第三个参数,使得查询可以执行不出错并且产生这个所需的输出:
NAME
SHIPMENT
DESCRIPTION
-------------------- -------------------- --------------------
Einstein Kaffee1. M?rz 2022 Blue Mountain
Kaffee Alt Wien4. M?rz 2022 Kona Peaberry
Den Gamle Kaffebar 8. Marts 2022Sumatra Mandheling
Cafe Saint-Henri 11. Mars 2022Valhalla Java
注意:这个输出包含了普通题目假定之外的字符。这是意料之中的,不是错误。

(A)
'NLS_DATE_LANGUAGE=''' || utl_i18n.map_language_from_iso(c.locale) || ''''
(B)
'NLS_DATE_LANGUAGE=' || utl_i18n.map_language_from_iso(c.locale)
(C)
'NLS_DATE_LANGUAGE=''' || utl_i18n.map_language_from_iso(substr(c.locale, 1, 2)) || ''''
(D)
'NLS_DATE_LANGUAGE=''' || utl_i18n.map_language_from_iso(substr(c.locale, 4, 2)) || ''''
(E)
'NLS_DATE_LANGUAGE=''' || substr(c.locale, 1, 2) || ''''
(F)
'NLS_DATE_LANGUAGE=''' || utl_i18n.map_from_short_language(substr(c.locale, 1, 2)) || ''''
(G)
'NLS_DATE_LANGUAGE=''' || utl_i18n.map_from_short_language(substr(c.locale, 4, 2)) || ''''
(H)
'NLS_DATE_LANGUAGE=''' || utl_i18n.map_from_short_language(

case locale

when 'fr_CA' then 'FRC'

when 'da_DK' then 'DK'

when 'de_AT' then 'D'

when 'de_DE' then 'D'

end

) || ''''



回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案ACH, 本期无人参与。
A:
在TO_CHAR的第三个参数你可以指定一个NLS参数的子集,其中一个是NLS_DATE_LANGUAGE。为了从一个ISO区域值里面得到一个NLS_DATE_LANGUAGE值,ORACLE提供了一个函数UTL_I18N.MAP_LANGUAGE_FROM_ISO。
B:
前一选项明确地用单引号包起语言值(它们被输入成两个单引号因为它们处于一个字符串字面量之中)。此处我们跳过了语言值的引用,这在'fr_CA'这个区域值出现了问题,它映射到ORACLE NLS语言'CANADIAN FRENCH',里面包含一个空格,使得选项报错:
ORA-12702: invalid NLS parameter string used in SQL function.
C:
此处我们在调用MAP_LANGUAGE_FROM_ISO时没有使用整个区域值,而仅仅是两位字符的语言代码。对于那个特定的ISO语言代码,MAP_LANGUAGE_FROM_ISO会返回缺省的NLS语言,这意味着'fr_CA'映射到'CANADIAN FRENCH',而'fr'单独映射到'FRENCH'。
在这个题目的这些数据中,我们的目的可以达到,因为月份名在Canadian French 和 French里面是一样的,但是在一些特殊情况下这可能不一定正确,所以虽然这个选项在这种特定情况下能工作(因此这个选项是正确的),它不像使用整个区域值的A选项那样通用以及安全。
D:
区域值的后两位是地区代码,不是语言。仅仅在'de_DE'这个选项是能工作的,其他所有的行都不行。于是这个选项回报错:
ORA-12702: invalid NLS parameter string used in SQL function.
E:
我们不能仅仅使用区域值中的两位语言代码作为NLS_DATE_LANGUAGE的值,它必须被映射为一个有效的ORACLE NLS语言值。所以这个选项会报错:
ORA-12702: invalid NLS parameter string used in SQL function.
F:
UTL_I18N包含一个函数MAP_FROM_SHORT_LANGUAGE,但是它期望的值不是我们的区域值中的两位语言ISO代码,而是期望一个ORACLE语言简写值。因为这不是同一个值,这个选项也会报错:
ORA-12702: invalid NLS parameter string used in SQL function.
G:
MAP_FROM_SHORT_LANGUAGE所期望的ORACLE语言简写值也不是区域代码----这个会报错:
ORA-12702: invalid NLS parameter string used in SQL function.
H:
此处我们明确将区域转换成MAP_FROM_SHORT_LANGUAGE所期望的正确的ORACLE语言简写值,对于这些数据它可以工作(于是这个选项是正确的),但并不通用,所以这不是一个好的做法。
总结:
Oracle 提供了一个用于国际化/全球化的内置包 UTL_I18N,它具有多个实用功能,其中包括 MAP_LANGUAGE_FROM_ISO,用于从具有 ISO 语言和地区代码的区域设置值中获取 Oracle NLS 语言值。

背景:
Oracle 为 Oracle 服务器提供了许多 PL/SQL 包,以扩展数据库功能并提供对 SQL 特性的 PL/SQL 访问。您可以在创建应用程序时使用提供的包,或在创建自己的存储过程时获得灵感。
执行以下查询以查看数据库中当前安装的大多数 Oracle 提供的包和类型。请将“all_objects”更改为“dba_objects”,如果您对该视图具有权限的话。然后你会看到更多!

SELECT DISTINCT Owner, Object_Type, Object_Name FROM All_Objects_AE
WHERE Owner IN (
'SYS', 'OUTLN', 'SYSTEM', 'CTXSYS', 'DBSNMP',
'LOGSTDBY_ADMINISTRATOR', 'ORDSYS',
'ORDPLUGINS', 'OEM_MONITOR', 'MDSYS', 'LBACSYS',
'DMSYS', 'WMSYS', 'OLAPDBA', 'OLAPSVR', 'OLAP_USER',
'OLAPSYS', 'EXFSYS', 'SYSMAN', 'MDDATA',
'SI_INFORMTN_SCHEMA', 'XDB', 'ODM')
AND Object_Type IN ('PACKAGE', 'TYPE')
ORDER BY Owner, Object_Type, Object_Name
请注意,某些 Oracle 提供的包和类型仅供其他 Oracle 提供的组件使用。不支持客户直接使用 Oracle 数据库文档库中未描述的任何包或类型。
UTL_I18N 提供了多种用于在不同语言代码之间进行翻译的功能。我们可以对本题中涵盖的内容进行进一步调查:
select
c.name
, c.locale
, utl_i18n.map_language_from_iso(c.locale) as map_locale
, utl_i18n.map_to_short_language(utl_i18n.map_language_from_iso(c.locale)) as ora_short
, substr(c.locale, 1, 2) as lang_alone
, utl_i18n.map_language_from_iso(substr(c.locale, 1, 2)) as map_lang_alone
, utl_i18n.map_to_short_language(utl_i18n.map_language_from_iso(substr(c.locale, 1, 2))) as lang_alone_short
from qz_customers c
order by c.id;
NAME
LOCALE MAP_LOCALE ORA_SH LANG_A MAP_LANG_A LANG_A
-------------------- ------ -------------------- ------ ------ ---------- ------
Cafe Saint-Henri fr_CACANADIAN FRENCHFRCfr FRENCH F
Den Gamle Kaffebar da_DKDANISH
DK da DANISH DK
Kaffee Alt Wiende_ATGERMAN
Dde GERMAN D
Einstein Kaffeede_DEGERMAN
Dde GERMAN D
MAP_LOCALE 列显示,我们可以使用 MAP_LANGUAGE_FROM_ISO 从完整的 LOCALE 值中获取 Oracle NLS 语言的相关值。
如果我们去掉区域环境,只保留 LANG_ALONE 列中的语言,它仍然可以为我们提供一种语言,但 FRENCH 和 CANADIAN FRENCH 不一定在所有情况下都相同。对于本题中的简单案例,仅使用 FRENCH 就足够了,但您不能期望在每种情况下都如此。
如果我们获取 MAP_LOCALE 和 MAP_LANG_ALONE 的值并将它们传递给 MAP_TO_SHORT_LANGUAGE,我们可以看到 Oracle 为这些 NLS 语言使用的缩写值。我们再次观察 FRC 和 F 之间的差异。这些是我们在选项 H 中将 ISO 语言环境映射到的值,以使 MAP_FROM_SHORT_LANGUAGE 工作。
总而言之,您应该注意,这不仅仅是语言问题----可能有许多版本的英语、法语、西班牙语等,具体取决于使用的地方。 Oracle 中的 NLS 语言参数支持处理这些多版本的值。在实践中,总是使用完整的 NLS 语言名称,很少看到缩写的 Oracle 语言代码。
回复

使用道具 举报

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

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行