2015-01-12 41 views
0

我急于采用适用于PostGre和Amazon RedShift的SQL产品,并将其移植到Oracle上。 (请注意,“工作”目前并不意味着“最佳”,而是“正确”)。使用PERL进行SQL方言翻译

我们所有的TABLE都是使用ORM(DBI)定义的,但是我们所有的VIEW当前都是以行内SQL 。

我的希望是有一种相对简单的方式来运行封装SQL的一种通用的意义,并使用一些现有的工具将其转换为方言特定的SQL。


简单的例子:

  • SELECT CAST(x AS DECIMAL(16,4)) AS foo FROM bah
    =>
  • SELECT CAST(x AS NUMBER(16,4)) AS foo FROM bah

这很简单。我们在部署时有一个“查找和替换阶段”。 SQL存储为CAST(x AS #DECIMAL#(16,4)),然后我们用一个新字符串替换#DECIMAL#,具体取决于我们要部署的方言。


令人沮丧的实施例:

  • SELECT x % y AS modulo FROM foo
    =>
  • SELECT MOD(x, y) AS modulo FROM foo

而且......

  • SELECT x/y AS int_div FROM foo
    =>
  • SELECT trunc(x/y) AS int_div FROM foo


我不是PERL专家,所以我在寻找如何做某种宏展开的指针。
- SQL将与字符串中的某种宏表达式一起存储
- 将使用参数(包括“方言”和“sql”)调用“处理器” - “方言”参数将决定宏扩展

Dialectless-SQL:SELECT #DIV(x,y)# AS z FROM foo

方言:RedShift
输出:SELECT x/y AS z FROM foo

方言:Oracle11g
输出:SELECT floor(x/y) AS z FROM foo


这将需要应付子查询,等:

Dialectless-SQL:SELECT #MOD(x, (SELECT MAX(y) FROM bah))# AS z FROM foo

方言:RedShift
输出:SELECT x % (SELECT MAX(y) FROM bah) AS z FROM foo

方言:Oracle11g
输出:SELECT mod(x, (SELECT MAX(y) FROM bah)) AS z FROM foo


或者用于存储“通用” SQL,并能翻译为“方言具体” SQL任何可靠的方法。

+2

你在这里有一个挑战你的手。听起来你想同时支持多种方言,而不是简单地将一种方言转换为另一种方言?我认为从写一套全面的测试开始很重要,因为目前您的目标有点不准确。我还建议您将基准SQL方言限制为函数而不是运算符(即'MOD(x,y)'而不是'x%y'),包括像添加这样的基本操作。这将使解析输入的工作变得非常简单。 – Borodin

+1

毫无疑问,你会发现类似于['Parse :: RecDescent'](https://metacpan.org/module/Parse:RecDescent)的解析模块很有用,因为该任务涉及两个步骤:将输入减少到解析树并将该解析树扩展为SQL方言。您将拥有一个前端和两个(或更多?)后端。 – Borodin

+0

@Borodin - 我们已经有了一个可以验证这一点的测试系统;从我们的ORM构建DDL,部署到新数据库,通过ETL处理测试数据集,查询预期结果的意见。我确实赞同具有函数*的“无方言/宏”SQL(例如我最后一个使用'#DIV(x,y)#'和'#MOD(x,y)#')*的例子。我们的前端将需要以同样的方式“翻译”其SQL。 *(一个“通用”前端,一个“通用”后端,许多实例/安装,在安装时将方言“应用”到SQL)。* – MatBailie

回答

3

您可能会发现SQL::Translator模块对此很有用。

SQL :: Translator是一组的Perl模块 供应商特定的SQL表定义转换成其他格式,其他如 供应商特定的SQL,ER图,文档(POD和HTML), XML和Class :: DBI类。

+0

我们已经使用DBI,所以表的DDL足够简单。这是VIEWs和产品中嵌入的任何内嵌SQL,需要在部署时进行翻译。感谢指向SQL :: Translator的指针,你是否发现它可以解析人类生成的SQL,可能包括位置参数标记? – MatBailie

+0

我从来没有在特别复杂的SQL上使用它,所以我不能真正评论,恐怕。 –

+1

我会跳过一个机会来使用称为'SQLFairy'的东西! – Borodin