- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我们正在为我们的环境数据库从 Oracle 10g 迁移到 18c。使事情复杂化的是,并非所有环境都计划一次迁移,因此应用程序必须同时支持这两种环境。发现的不兼容性之一是 WM_Concat
在 10g 中受支持但在 18c 中不受支持,而 ListAgg
(新的等效函数)在 18c 中受支持但在 10g 中不受支持。因此,我正在寻找一种暂时适用于两个数据库版本的实现。
我的想法是10g中的wm_concat(myColumn)
等同于18c中的listagg(myColumn, ',')
,所以我想定义wm_concat(myColumn)
成为新的 18c 数据库中的一个函数,它在后台传递给 listagg(myColumn, ',')
并返回结果。这样,应用程序可以安全地继续在 10g 和 18c 数据库上正常使用 wm_concat
,直到所有环境都在 18c 上,之后可以将应用程序切换为使用 listagg
并且可以从 18c 数据库中删除临时自定义 wm_concat
函数,完成迁移。
总而言之,定义 wm_concat
的正确方法是什么,以便 wm_concat(myColumn)
的行为与 listagg(myColumn, ',' )
在查询中?
最佳答案
[TL;DR] 您无法在 Oracle 18c 中实现自定义版本的 WM_CONCAT
以使其行为与 LISTAGG
完全相同,但您可以接近用户-定义聚合函数。
WM_CONCAT
的语法是:
WM_CONCAT( expr )
您可以看到 WM_CONCAT
无法指定分隔符或 ORDER BY
子句。
如果你想在以后的版本中重新定义 WM_CONCAT
那么你最终可能会使用用户定义的聚合函数:
用户定义对象:
CREATE OR REPLACE TYPE t_string_agg AS OBJECT
(
g_string VARCHAR2(32767),
STATIC FUNCTION ODCIAggregateInitialize(
sctx IN OUT t_string_agg
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateIterate(
self IN OUT t_string_agg,
value IN VARCHAR2
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateTerminate(
self IN t_string_agg,
returnValue OUT VARCHAR2,
flags IN NUMBER
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateMerge(
self IN OUT t_string_agg,
ctx2 IN t_string_agg
) RETURN NUMBER
);
/
用户定义的对象主体:
CREATE OR REPLACE TYPE BODY t_string_agg IS
STATIC FUNCTION ODCIAggregateInitialize(
sctx IN OUT t_string_agg
) RETURN NUMBER
IS
BEGIN
sctx := t_string_agg(NULL);
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateIterate(
self IN OUT t_string_agg,
value IN VARCHAR2
) RETURN NUMBER
IS
BEGIN
SELF.g_string := self.g_string || ',' || value;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateTerminate(
self IN t_string_agg,
returnValue OUT VARCHAR2,
flags IN NUMBER
) RETURN NUMBER
IS
BEGIN
returnValue := SUBSTR( SELF.g_string, 2 );
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateMerge(
self IN OUT t_string_agg,
ctx2 IN t_string_agg
) RETURN NUMBER
IS
BEGIN
SELF.g_string := SELF.g_string || ctx2.g_string;
RETURN ODCIConst.Success;
END;
END;
/
用户定义的聚合函数:
CREATE OR REPLACE FUNCTION wm_concat (p_input VARCHAR2)
RETURN VARCHAR2
PARALLEL_ENABLE AGGREGATE USING t_string_agg;
/
测试数据:
CREATE TABLE test_data ( id, value ) AS
SELECT 1, 'C' FROM DUAL UNION ALL
SELECT 1, 'A' FROM DUAL UNION ALL
SELECT 1, 'B' FROM DUAL UNION ALL
SELECT 2, 'D' FROM DUAL UNION ALL
SELECT 2, 'E' FROM DUAL;
测试查询:
SELECT id,
wm_concat( value ) AS wm_concat,
LISTAGG( value, ',' ) WITHIN GROUP ( ORDER BY ROWNUM ) AS listagg
FROM test_data
GROUP BY id;
输出:
ID | WM_CONCAT | LISTAGG-: | :-------- | :------ 1 | C,B,A | C,A,B 2 | D,E | D,E
如您所见,输出的顺序不同;所以你可以接近但不是完全匹配。
db<> fiddle here
更新:
如果我们寻找一个低效的聚合函数,将所有值存储在一个集合中,然后调用 LISTAGG
,那么我们可以更接近:
CREATE TYPE stringlist IS TABLE OF VARCHAR2(4000);
CREATE OR REPLACE TYPE t_string_agg AS OBJECT
(
strings stringlist,
STATIC FUNCTION ODCIAggregateInitialize(
sctx IN OUT t_string_agg
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateIterate(
self IN OUT t_string_agg,
value IN VARCHAR2
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateTerminate(
self IN t_string_agg,
returnValue OUT VARCHAR2,
flags IN NUMBER
) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateMerge(
self IN OUT t_string_agg,
ctx2 IN t_string_agg
) RETURN NUMBER
);
/
CREATE OR REPLACE TYPE BODY t_string_agg IS
STATIC FUNCTION ODCIAggregateInitialize(
sctx IN OUT t_string_agg
) RETURN NUMBER
IS
BEGIN
sctx := t_string_agg( stringlist() );
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateIterate(
self IN OUT t_string_agg,
value IN VARCHAR2
) RETURN NUMBER
IS
BEGIN
SELF.strings.EXTEND;
SELF.strings( SELF.strings.COUNT ) := value;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateTerminate(
self IN t_string_agg,
returnValue OUT VARCHAR2,
flags IN NUMBER
) RETURN NUMBER
IS
BEGIN
SELECT LISTAGG( column_value, ',' ) WITHIN GROUP ( ORDER BY column_value )
INTO returnValue
FROM TABLE( SELF.strings );
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateMerge(
self IN OUT t_string_agg,
ctx2 IN t_string_agg
) RETURN NUMBER
IS
BEGIN
SELF.strings := SELF.strings MULTISET UNION ALL ctx2.strings;
RETURN ODCIConst.Success;
END;
END;
/
CREATE OR REPLACE FUNCTION wm_concat (p_input VARCHAR2)
RETURN VARCHAR2
PARALLEL_ENABLE AGGREGATE USING t_string_agg;
/
然后:
SELECT id,
wm_concat( value ) AS wm_concat,
LISTAGG( value, ',' ) WITHIN GROUP ( ORDER BY value ) AS listagg
FROM test_data
GROUP BY id;
输出:
ID | WM_CONCAT | LISTAGG-: | :-------- | :------ 1 | A,B,C | A,B,C 2 | D,E | D,E
如果(且仅当)您想要按字母顺序对值进行排序,它将给出与 LISTAGG
相同的输出;您不能指定不同的顺序。它还需要从 PL/SQL 到 SQL 的上下文切换以在最后一步中执行聚合,因此它可能比纯 PL/SQL 聚合函数慢,并且它将集合保存在内存中并继续扩展它,因此会有随着集合的增长(或在并行系统中合并)会产生额外的开销,这将进一步减慢它的速度。
因此,它仍然不是 LISTAGG
,但如果您愿意忍受性能方面的问题,它会尽可能接近。
db<> fiddle here
关于oracle - 将 "WM_CONCAT(col)"定义为 "LISTAGG(col, ' ,')"用于 Oracle 迁移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58277474/
Oracle 即时客户端和 Oracle 客户端有什么区别?你能给我解释一下吗?谢谢 最佳答案 Oracle 客户端带有安装程序和许多可执行文件,例如 sqlplus,tnsping,它是完整而庞大的
我正在寻找一个Delphi组件来直接连接到ORACLE数据库服务器,而无需安装oracle客户端。 我知道Oracle Data Access (ODAC)来自DevArt 。还有其他组件具有此功能吗
如何编写 Oracle 存储过程,以表 (X) 作为输入参数,并在过程内部使用表 X 来与另一个表 Y 联接? 表 X 将包含数千条记录。 不希望将表名作为 varchar 传递,然后使用动态 SQL
如何编写 Oracle 存储过程,以表 (X) 作为输入参数,并在过程内部使用表 X 来与另一个表 Y 联接? 表 X 将包含数千条记录。 不希望将表名作为 varchar 传递,然后使用动态 SQL
我要过滤COMMENTS属性为空的记录 我试过了 SELECT TABLE_NAME, COMMENTS FROM (SELECT TABLE_NAME, COMMENTS FROM (sel
我要下载 Oracle Instant Client for Linux x86-64 (64-bit)现在有一段时间了。 现在我注意到该网站在过去几个月中一直遇到技术问题。 要从 Oracle 下载
有什么方法可以将我的 Delphi 应用程序 (FireDac) 直接连接到 Oracle 数据库? 目前可以连接,但需要安装Oracle Client 在 embarcadero 站点 ( http
我有一张表,其中日期列的数据格式如下:“7/25/2014 12:14:27 AM”。我需要通过放入 where 子句来获取此日期。有人可以建议我该怎么做吗? 最佳答案 日期(存储在表中)是 repr
如果两个事务试图同时修改同一行会发生什么?通常,一旦行被修改,另一个事务等待直到第一个事务执行提交或回滚。但是,如果他们恰好在同一时刻发送更新请求怎么办? 最佳答案 答案是否定的。两个事务不能同时修改
我想知道为什么我不能在 Oracle 模式中有两个同名的索引?它抛出一个错误,指出该名称已被使用。我的印象是,由于索引在一个特定的表上,这应该不会导致任何错误,除非我们对同一个表上的两个不同列使用相同
我需要构建一个查询来按成员和到期日期检索信息组,但我需要为每个成员提供一个序列号.. 例如: 如果成员“A”有 3 条记录要过期,“B”只有 1 条,“C”有 2 条,我需要这样的结果: Number
独立程序 create procedure proc1 ( begin end; ) 存储过程 create package pkg1 ( procedure proc2 begin end; ) 最
在 Oracle 9i 中声明 FK 时遇到问题。我在这里查看了许多关于 SO 和一些在线文档(例如 http://www.techonthenet.com/oracle/foreign_keys/f
我和我的同事维护的应用程序在后端有一个 Oracle 数据库。我们正在考虑偶尔以“受限”模式运行应用程序,其中一个数据库表空间设置为只读。我们可以轻松地将必要的表和索引移动到单独的表空间,这些表空间将
我想实现一个自定义的回归聚合函数,类似于现有的 REGR_SLOPE . 我要定义的函数需要获取两列作为参数,例如 select T.EMPLOYEE_ID, CUSTOM_REGR_SL
我已经尝试解决这个问题一段时间了,我认为是时候寻求帮助了。我正在构建一个架构配置脚本,我想添加一些脚本输出和错误处理。这个想法是脚本输出窗口只会向我显示关键消息而没有所有噪音。 Create Temp
在旧的 Oracle 服务器(我被告知是 8i)上使用 JDBC 时,我遇到了一个非常令人困惑和奇怪的问题。我在那里准备了一个表,其中包含大约 10 列、数字、varchars、一个 raw(255)
我有一张 table Customer_Chronics在 Oracle 11g 中。 该表具有三个关键列,如下所示: 分支代码 客户 ID 期 我已按 branch_code 列表按表分区,现在我进
是否有存储用户自定义异常的oracle表? 最佳答案 没有。 与其他变量一样,用户定义的异常在 PL/SQL block 中定义,并且具有 PL/SQL 变量将具有的任何范围。所以,例如 DECLAR
在 oracle 中使用序列并使用 Before insert trigger 自动递增列或使用标识列是否更好,因为它在 Oracle 12 c 中可用? 最佳答案 无论哪种方式,您都将使用序列。 1
我是一名优秀的程序员,十分优秀!