2

在我在 Oracle 的旅途中,当我不得不动态创建动态 SQL 查询时,“stragg”函数或“String Aggregator”可以挽救生命。

你可以在这里阅读:http ://www.oratechinfo.co.uk/delimited_lists_to_collections.html

它的基本用途是:

select stragg(fruit) from food;

fruit
-----------
apple,pear,banana,strawberry

1 row(s) returned

使用起来非常简单,连接 chr(13) 将其变成一个长列表,从系统表中选择信息为动态生成的 SQL 提供了 5 分钟的解决方案,例如审计触发器。

现在我负责将与审计相关的 oracle 功能转移到 Sybase 中,类似 Stragg 的功能将非常适合此目的。

例如

select @my_table = 'table_of_fruit'

select 'insert into '+@mytable+'_copy (' +char(10)
   + stragg(c.name) +char(10)
   + 'select '
   + stragg('inserted.'+c.name) + char(10)
   + 'from '+@mytable
from syscolumns c
where objectid(@mytable) = c.id


------------------------------------------
insert into table_of_fruit_copy
(fruit, sweetness, price) 
select fruit, sweetness,price 
from inserted

完毕。简单的。

除了我不知道如何让字符串聚合函数在 Sybase 中工作。

有谁知道尝试做这种事情,或者可以与可以以这种方式使用的 stragg 相同的代码?

目前的替代方法是打印基于复杂游标等的代码(示例 LOC:500),或者选择结合用户表中的静态字符串和列的语句(示例 LOC:200)。Stragg 将大大降低此代码的复杂性,并且在将来会有很大的帮助(示例 LOC:谁知道呢,可能是 50 个?)

ps 我通过 shell 脚本调用这些选择,然后将它们传送到文件,然后通过 iSQL 运行文件。不是最好的解决方案,但它比替代方案更好。

4

2 回答 2

2

三个不同的答案

问题

您对简单性发表了评论,在我们找到解决方案之前需要解决这些问题。

能够获取分隔的值列表(例如 A、B、C、D)并将这些数据视为表中的一组行是一项常见要求,反之亦然

  1. 这是我最近读到的十大最糟糕的编程实践之一。

  2. 通常,Sybase 类型在学术和关系方面比 Oracle 类型更符合要求,因此我们在 SybaseLand 或 DB2Land 中根本不做这种事情。

  3. 在与 Sybase 合作的 20 年中,我不得不将它作为我项目的一部分进行一次编码,那是为将结果集加载到 MS Access 中的非技术审计员编写的。

  4. 另一方面,在生成要导入 Oracle 数据库的文本文件时,我必须至少编写 12 次代码(满足外部要求不在我的项目范围内,但我免费满足任何此类要求)。显然,目标数据库是不合标准的和非关系型的(加载具有多个数据的列会破坏 1NF,并创建更新异常),这是 Oracle 类型为了获得一定速度而必须做的典型事情。

  5. 因此,不,这不是简单,至少在该原则的意义上。根据定义,复杂性。

  6. 您对“数组”的引用不正确。所有商业 dbms 都根据 ISO/IEC/ANSI SQL 处理数组(STRAGGR 和 LIST 运算符是非标准 SQL,因此不是 SQL)。Sybase 在处理数组方面非常强大。如果它是一个数组,则您不需要特殊的手动编码来处理它(根据您的问题,您可以这样做)。这不是一个数组,单元格没有定义。这是一个连接的标量字符串。

  7. 透视是一个完全不同的过程,它使用集合处理;它不需要行处理。(据我所知,Oracle 在标量子查询方面毫无希望,因此 Oracle 人习惯于将它们编写为 [非常低效的] 连接或内联视图,然后进行过滤:所有这些都可以通过标量子查询提升为集合处理,它的执行速度会更快。尤其是你的 Pivots。)

  8. 甚至您链接中的作者也发布如下。请熟悉注意事项:

就这么简单:如果您想要一个系统在传递给给定进程的数据元素数量上没有逻辑限制,那么请忘记以下机制!它们只是解决问题的错误方法。

  1. 因此,要知道你所做的一切都是不合标准的、无关紧要的、有限的;睁大眼睛继续前行。假装没有用:它不会破裂;不受限制;它是一个“数组”;或者 Sybase 没有 Oracle 所具有的简洁的小功能。任何专业人士都会看穿这一切。如果超出字符串长度,看在上帝的份上,将一些指示符发送回调用者(字符串中的“!Exceeded”)来识别该条件。

  2. 本质上,您正在将集合处理引擎置于其头上,并强制其进入行处理模式,因此它会非常慢。WHILE 循环明显比游标快,但两者都属于同一类,即行处理器。

目前的替代方法是打印基于复杂光标等的代码

  1. 什么 200 或 500 LoC?我可能遗漏了一些东西,但我的代码与链接中“使用表函数”下标识的几行代码相同。 最多 20,如果你算上漂亮的格式;循环;初始化;错误处理。它没有什么“复杂”的。执行完全相反的操作以连接多行中的单个字符串。我们为此使用存储过程(oracle 没有,实际上,PL/SQL 是另一种动物)。如果您有 ASE 15.0.2 或更高版本,则可以使用用户定义函数,然后您可以使用它来代替列。存储过程更适合真正的数组。

    • Sybase 中的连接运算符是加号。对于反转(分解 CSV 字符串),您需要 CHARINDEX 和 SUBSTRING 函数

    • 如果没有别的原因,您可能需要函数参考手册,以避免在我们有函数的地方编写代码。

同样,我们没有RANK()函数。我们对子查询所需的 4 行代码感到非常满意。它只对 Oracle 是必需的,因为子查询被削弱了。


好的,我已经回答了你的问题,现在来解决方法。

  • 您将意识到需要更改使用 SQL 标准的Oracle扩展的代码。

  • Sybase 比 Oracle 自动化得多。如果您熟悉它的功能集,在许多情况下,您无需编写任何代码即可获得相同的结果(就像您在 Oracle 中所做的那样)。在推土机的背景下,为代码块编写代码是一种链式的破石方法。即使您的公司有充分的理由使用该方法,您也需要意识到功能的工作方式完全不同,例如。触发器,这就是为什么我要发布这么多细节。

  • 另一个让您烦恼的问题是 Oracle 并不真正符合 ANSI SQL(在许多地方延伸定义,以便看起来符合标准),而 Sybase 鉴于其客户群,严格地符合 SQL 标准。因此,除了相同的功能以不同的方式工作或在不同的部署中工作之外,您还需要注意,可能需要更改代码才能将 Oracle 代码提升到 ANSI 合规级别,只是为了在 ANSI SQL 合规平台上执行。

我不确定您是否正在尝试为触发器的内容编写代码,或者您是否正在尝试捕获对数据库的更改。我将提供两个答案。

审计

捕获对数据库的更改

我们有一个非常强大、快速和可配置的审计子系统,适合大批量和银行级别的审计要求。让您的 DBA 设置 sybaudit(独立)数据库,并准确配置需要捕获的更改。该工具的执行速度将比您或我在触发器中编写的任何代码快得多(比上述所需的逐行处理快 100 倍,因为它是在引擎中执行的线程中执行的)。当然,设置时间只是编码时间的一小部分。

触发器

同样,我不确定您要实现的确切目标,但假设您要将每个插入复制到某个表到该表的副本(在触发器内),那么您提供的示例代码将不起作用(我是不计算语法问题)。

  1. 说到你的例子,你需要做更多的工作来处理不同的数据类型;列大小;精度;规模; 等等。也许还有 UPDATE() 函数来识别哪些列已更改(当然对于 UPDATE 触发器)。如果您要做的只是将各种数据类型转换为字符串,请检查 CONVERT() 函数。

    • 触发器是事务性的。

    • 永远不要将行处理代码放在触发器中(它会扼杀表格)

    • 您不能将动态 SQL 放在触发器中。

  2. 但在 Sybase 中,即使这样也没有必要。请参阅《用户指南》,第 19 章专门介绍触发器,其中包含几个变体和示例。在触发器内部,您应该能够简单地:

    INSERT table_copy
        SELECT column_list  -- never use * unless you want the db fixed in cement
            FROM inserted
    
  3. 如果您尝试将所有表的插入复制到一个审核表中,请注意。然后我更了解你的例子。您将强制一个高度对称的多线程服务器(oracle 不是架构意义上的服务器)通过您的表进行单线程处理。审计是多线程的。

最后,不需要使用任何类型的手动方法,因此,如果您可以在 PS 上进行更多扩展,您要满足的要求是,我可以为您确定程序化方法。看来您正在尝试使用 PL/SQL 方法(这是非常有限的)。

于 2010-12-12T09:41:57.927 回答
0

只需使用该LIST()功能。它是功能的直接替代品stragg()。例子:

SELECT LIST(state, ', ') FROM cities

结果:

name
CA, CA, MA, NY
于 2015-01-19T02:04:42.497 回答