源代码:大批量SQL代码语法转换实战:PIVOT函数改写(案例2)

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介: 源代码:大批量SQL代码语法转换实战:PIVOT函数改写(案例2)

### 背景:在不同数据库迁移的项目中,往往会遇到SQL语法不兼容的情况。比如有的数据库支持PIVOT函数,有的不支持。遇到这种情况,就必须对PIVOT函数进行改写。

### 问题:如果存在大量代码需要改写的情况,靠人工处理会很耗时,且容易出错。能不能通过工具实现代码语法的大批量自动转换?

### 方案:可以使用开源代码解析器 ZGLanguage 对SQL代码进行大批量自动转换

### 案例演示:

# 存在 SQL PIVOT函数 如下所示:

SELECT *
FROM table2222 PIVOT 
(
    SUM(sales) AS ss1,
    SUM(cogs) AS sc 
    FOR (yr, qtr)
    IN (
        (2001, 'Q1'),
        (2001, 'Q2'),
        (2001, 'Q3'),
        (2001, 'Q4')
    )
) tmp
;

# 使用开源软件 ZGLanguage 转换规则,执行转换,可得到结果:

SELECT *
FROM
( 
  select ###,###,###
         SUM(case when yr=2001 and qtr='Q1' then sales else null end ) AS "2001_Q1_ss1",
         SUM(case when yr=2001 and qtr='Q2' then sales else null end ) AS "2001_Q2_ss1",
         SUM(case when yr=2001 and qtr='Q3' then sales else null end ) AS "2001_Q3_ss1",
         SUM(case when yr=2001 and qtr='Q4' then sales else null end ) AS "2001_Q4_ss1",
         SUM(case when yr=2001 and qtr='Q1' then cogs else null end ) AS "2001_Q1_sc",
         SUM(case when yr=2001 and qtr='Q2' then cogs else null end ) AS "2001_Q2_sc",
         SUM(case when yr=2001 and qtr='Q3' then cogs else null end ) AS "2001_Q3_sc",
         SUM(case when yr=2001 and qtr='Q4' then cogs else null end ) AS "2001_Q4_sc"
  from table2222
  where (yr, qtr) IN 
        (
        (2001, 'Q1') ,
        (2001, 'Q2') ,
        (2001, 'Q3') ,
        (2001, 'Q4') 
    )
  group by ###,###,###
  
) tmp
;


# 转换规则如下所示 :

__DEF_FUZZY__             Y
__DEF_DEBUG__             N
__DEF_CASE_SENSITIVE__    N

__DEF_LINE_COMMENT__      -- 
__DEF_LINES_COMMENT__     /*     */


__DEF_STR__   __IF_KW__
<1,100>
[1,1]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
[0,100]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_


__DEF_PATH__    __FROM_PIVOT_2_1__
1              : frm         @ %__IF_KW__             | from
               : tab         @                        | __TABLE_NAME__
               : ssl         @                        + __SUB_SELECT__
               : pvt         @                        | pivot
               : x1          @                        | (
N              : fun         @                        | __NAME__        __//__ sum ....
               : fs          @                        | (
               : col1        @                        | __NAME__
               : fe          @                        | )
               : as1         @ %__IF_KW__ CAN_SKIP    | as
               : colas       @                        | __NAME__
e              : dh1         @                        | ,
1              : for2        @ %__IF_KW__             | for
               : y1          @                        | __COLS_4_FOR__
               : in2         @                        | in
               : y5          @                        | (
N              : y3          @                        | __VALUE_4_IN__
e              : dh7         @                        | ,
1              : y6          @                        | )
               : x2          @                        | )
------------------------------------------------------------------
1              : frm         @                        | from
               : tab         @                        | __TABLE_NAME__
               : ssl         @                        | __SUB_SELECT__
               : pvt         @                        | pivot
               : x1          @                        | (
N              : fun         @                        | __NAME__
               : fs          @                        | (
               : col1        @                        | __NAME__
               : fe          @                        | )
               : as1         @                        | as
               : colas       @                        | __NAME__
e              : dh1         @                        | ,
1              : for2        @                        | for
               : y1          @                        | __COLS_4_FOR__
               : in2         @                        | in
               : y5          @                        | (
N              : y3          @                        | __\b__
               : y1          @                        | __COLS_4_FOR__
               : y3          @                        | __VALUE_4_IN__
e              : dh7         @                        | ,
1              : y6          @                        | )
1              : for2        @                        | where
               : y1          @                        | __COLS_4_FOR__
               : in2         @                        | in
               : y5          @                        | (
N              : y3          @                        | __VALUE_4_IN__
e              : dh7         @                        | ,
1              : y6          @                        | )
               : x2          @                        | )


__DEF_PATH__    __FROM_PIVOT_2_2__
1              : frm         @ %__IF_KW__             | from
               : tab         @                        | __TABLE_NAME__
               : ssl         @                        + __SUB_SELECT__
               : pvt         @                        | pivot
               : x1          @                        | (
N              : fun         @                        | __NAME__
               : fs          @                        | (
               : col1        @                        | __NAME__
               : fe          @                        | )
               : as1         @ %__IF_KW__ CAN_SKIP    | as
               : colas       @                        | __NAME__
e              : dh1         @                        | ,
1              : for2        @ %__IF_KW__             | for
               : y1          @                        | __COLS_4_FOR__
               : in2         @                        | in
               : y5          @                        | (
N              : y3          @                        | __COLS_VALUES__
e              : dh7         @                        | ,
1              : y6          @                        | )
1              : where       @                        | where
               : y11         @                        | __COLS_4_FOR__
               : in21        @                        | in
               : y51         @                        | (
N              : y31         @                        | __VALUE_4_IN__
e              : dh71        @                        | ,
1              : y61         @                        | )
               : x2          @                        | )
------------------------------------------------------------------
1              : frm         @                        | from
               : tab         @                        | __TABLE_NAME__
               : ssl         @                        | __SUB_SELECT__
               : pvt         @                        | pivot
               : x1          @                        | (
N              : fun         @                        | __NAME__
               : fs          @                        | (
               : col1        @                        | __NAME__
               : fe          @                        | )
               : as1         @                        | as
               : colas       @                        | __NAME__
*              : y3          @                        | __COLS_VALUES__
e              : y3          @                        | ,
1              : where       @                        | where
               : y11         @                        | __COLS_4_FOR__
               : in21        @                        | in
               : y51         @                        | (
N              : y31         @                        | __VALUE_4_IN__
e              : dh71        @                        | ,
1              : y61         @                        | )
               : x2          @                        | )


__DEF_PATH__    __FROM_PIVOT_2_3__
1              : frm         @ %__IF_KW__             | from
               : tab         @                        | __TABLE_NAME__
               : ssl         @                        + __SUB_SELECT__
               : pvt         @                        | pivot
               : x1          @                        | (
N              : fun         @                        | __NAME__
               : fs          @                        | (
               : col1        @                        | __NAME__
               : fe          @                        | )
               : as1         @ %__IF_KW__ CAN_SKIP    | as
               : colas       @                        | __NAME__
               : cw          @                        | __CASE_WHEN__
               : as2         @                        | as
               : y2          @                        | __VALUE_2_COL__
e              : y3          @                        | ,
1              : where       @                        | where
               : y11         @                        | __COLS_4_FOR__
               : in21        @                        | in
               : y51         @                        | (
N              : y31         @                        | __VALUE_4_IN__
e              : dh71        @                        | ,
1              : y61         @                        | )
               : x2          @                        | )
--------------------------------------------------------------
1              : frm         @                        | from
               : x1          @                        | (
               : x1          @ STRING                 | select ###,###,###
N              : fun         @                        | __NAME__
               : fs          @                        | (
               : cw          @                        | __CASE_WHEN__
               : col1        @                        | __NAME__
               : col1        @ STRING                 | else null end
               : fe          @                        | )
               : as1         @                        | as
               : y2          @                        | __VALUE_2_COL__
               : colas       @                        \ __NAME__
               : colas       @                        \ "
e              : y3          @                        | ,
1              : pvt         @                        | from
               : tab         @                        | __TABLE_NAME__
               : ssl         @                        | __SUB_SELECT__
1              : where       @                        | where
               : y11         @                        | __COLS_4_FOR__
               : in21        @                        | in
               : y51         @                        | (
N              : y31         @                        | __VALUE_4_IN__
e              : dh71        @                        | ,
1              : y61         @                        | )
               : x1          @ STRING                 | group by ###,###,###
               : x2          @                        | )


__DEF_SUB_PATH__       __VALUE_2_COL__
N              : x1         @                         | __INT__
+              : x2         @                         | '
               : x3         @                         | __ANY__
               : x4         @                         | '
------------------------------------------------------------------
1              : x1         @                         | "
               : x3         @                         | "
N              : x1         @                         \ __INT__
               : x3         @                         \ __ANY__
               : x1         @                         \ _
               : x3         @                         \ _


__DEF_SUB_PATH__       __CASE_WHEN__
N              : x1         @                         | __NAME__
               : x2         @                         | =
               : x3         @                         | __INT__
               : x4         @                         + __STRING__
e              : x5         @                         | and
------------------------------------------------------------------
1              : x1         @ STRING                  | case when
N              : x1         @                         | __NAME__
               : x2         @                         | =
               : x3         @                         | __INT__
               : x4         @                         | __STRING__
e              : x5         @                         | and
1              : x1         @                         | then


__DEF_SUB_PATH__       __COLS_VALUES__
1              : x1         @                        | (
N              : x2         @                        | __NAME__
e              : x3         @                        | ,
1              : x4         @                        | )
               : y1         @                        | (
N              : y2         @                        | __INT__
               : y3         @                        + __STRING__
e              : y4         @                        | ,
1              : y5         @                        | )
----------------------------------------------------------------------
N              : x2         @                        | __NAME__
               : x2         @                        / =
               : y2         @                        / __INT__
               : y3         @                        / __STRING__
e              : x2         @                        | and
1              : x2         @                        | as 
N              : y2         @                        | __INT__
               : y3         @                        | __STRING__


__DEF_SUB_PATH__       __COLS_4_FOR__
1              : x1         @                        | (
N              : x2         @                        | __NAME__
e              : x3         @                        | ,
1              : x4         @                        | )


__DEF_SUB_PATH__       __VALUE_4_IN__
1              : x1         @                        | (
N              : x2         @                        | __INT__
               : x3         @                        + __STRING__
e              : x4         @                        | ,
1              : x5         @                        | )


__DEF_SUB_PATH__       __TABLE_NAME__
1        : srctab           @               | __NAME__
+        : schema           @               | __NAME__
         : pp               @               | .
         : srctab2          @               | __NAME__


__DEF_SUB_PATH__   __SUB_SELECT__
1        : x1               @               | __SUB__


__DEF_PATH__   __SUB__
1        : x1               @               | ( 
N        : x2               @               | __ALL_STR__
         : x3               @               + __SUB__
1        : x4               @               | )


__DEF_STR__   __ALL_STR__
<1,20000>
[1,20000]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*-_+={}[]\|:;'"<,>.?/


__DEF_STR__   __NAME__
<1,100>
[1,1]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_??
[0,100]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_??
[NO] create insert update delete truncate drop merge table select inner left join on from where group order partition by having union all with as set between and or like in is not null case when then pivot lateral view 


__DEF_STR__   __FLOAT__
<1,100>
[1,50]0123456789
[1,1].
[1,50]0123456789


__DEF_STR__   __INT__
<1,100>
[1,100]0123456789


__DEF_SUB_PATH__   __STRING__
1       : x1                  | '
        : x2                  | __ANY__
        : x3                  | '


### 转换规则详细说明:

以上PIVOT函数的转换规则比较复杂,不能一次性转换完毕,这里分成3次转换完成:

ZGLanguage -e PIVOT_UNPIVOT_SQL_REPLACE.syn -r pivot_unpivot.code -o 1_mid_result.zgl
ZGLanguage -e PIVOT_UNPIVOT_SQL_REPLACE.syn -r 1_mid_result.zgl -o 2_mid_result.zgl
ZGLanguage -e PIVOT_UNPIVOT_SQL_REPLACE.syn -r 2_mid_result.zgl -o result.zgl


# 第1次转换规则 “__FROM_PIVOT_2_1__” 对源代码进行转换,

 (A) 值“(yr, qtr)” 和 枚举值 “Q1,Q2,Q3,Q4” 的一一映射关系

 (B) 新增:where结构(由 FOR 结构转换得到)

 得到如下结果:

SELECT *
FROM table2222 PIVOT
(
    SUM ( sales ) AS ss1 ,
    SUM ( cogs ) AS sc
    FOR (yr, qtr)
    IN (  
    (yr, qtr) (2001, 'Q1') ,  
    (yr, qtr) (2001, 'Q2') ,  
    (yr, qtr) (2001, 'Q3') ,  
    (yr, qtr) (2001, 'Q4') )
    where (yr, qtr)
    IN (
        (2001, 'Q1') ,
        (2001, 'Q2') ,
        (2001, 'Q3') ,
        (2001, 'Q4') )
) tmp
;

# 第2次转换规则 “__FROM_PIVOT_2_2__” 对 “__FROM_PIVOT_2_1__” 的转换结果(以上)再次进行转换。  

 完成:

 (A) 聚合函数“SUM字段” 和 “(yr, qtr)字段” 的笛卡尔积映射

 (B) 提取枚举值准备生成新的字段别名

 得到如下结果:

SELECT *
FROM table2222 PIVOT
(
    SUM(sales) AS ss1    yr = 2001 and qtr = 'Q1' as 2001 'Q1' ,
    SUM(sales) AS ss1    yr = 2001 and qtr = 'Q2' as 2001 'Q2' ,
    SUM(sales) AS ss1    yr = 2001 and qtr = 'Q3' as 2001 'Q3' ,
    SUM(sales) AS ss1    yr = 2001 and qtr = 'Q4' as 2001 'Q4' ,
    SUM(cogs)  AS sc     yr = 2001 and qtr = 'Q1' as 2001 'Q1' ,
    SUM(cogs)  AS sc     yr = 2001 and qtr = 'Q2' as 2001 'Q2' ,
    SUM(cogs)  AS sc     yr = 2001 and qtr = 'Q3' as 2001 'Q3' ,
    SUM(cogs)  AS sc     yr = 2001 and qtr = 'Q4' as 2001 'Q4' 

    where (yr, qtr)
    IN (
        (2001, 'Q1') ,
        (2001, 'Q2') ,
        (2001, 'Q3') ,
        (2001, 'Q4') )
) tmp
;

# 第3次转换规则 “__FROM_PIVOT_2_3__” 对 “__FROM_PIVOT_2_2__” 的转换结果(以上)再次进行转换。  

 完成:

 (A) 对SUM开头的字段内容进行新增、位移、合并等操作,形成语法正确的字段逻辑

 (B) 剔除PIVOT关键字,移动表名到 where 语句上方

 (C) 拼接新的字段名称

 (D) 新增待人工补充部分: select ###,###,###   group by ###,###,###

 得到最终结果:

SELECT *
FROM
( 
  select ###,###,###
         SUM(case when yr=2001 and qtr='Q1' then sales else null end) AS "2001_Q1_ss1",
         SUM(case when yr=2001 and qtr='Q2' then sales else null end) AS "2001_Q2_ss1",
         SUM(case when yr=2001 and qtr='Q3' then sales else null end) AS "2001_Q3_ss1",
         SUM(case when yr=2001 and qtr='Q4' then sales else null end) AS "2001_Q4_ss1",
         SUM(case when yr=2001 and qtr='Q1' then cogs else null end) AS "2001_Q1_sc",
         SUM(case when yr=2001 and qtr='Q2' then cogs else null end) AS "2001_Q2_sc",
         SUM(case when yr=2001 and qtr='Q3' then cogs else null end) AS "2001_Q3_sc",
         SUM(case when yr=2001 and qtr='Q4' then cogs else null end) AS "2001_Q4_sc"
  from table2222
  where (yr, qtr) 
  IN (
      (2001, 'Q1') ,
      (2001, 'Q2') ,
      (2001, 'Q3') ,
      (2001, 'Q4') )
  group by ###,###,###
  
) tmp
;


### 新增待补充部分 ###,###,### 说明:

1、通过简单的配置,不能直接转换成完全可用的SQL代码,有些代码部分依然需要人工补充

2、需要人工补充的部分,已经通过 ###,###,### 明显地标注出来

3、通过工具已经完成了大部分的转换工作,可以极大减轻人工参与的工作量,规避人工修改失误的风险


源代码下载: https://gitee.com/zgl-20053779/zglanguage

相关文章
|
8天前
|
人工智能 自然语言处理 Shell
🦞 如何在 OpenClaw (Clawdbot/Moltbot) 配置阿里云百炼 API
本教程指导用户在开源AI助手Clawdbot中集成阿里云百炼API,涵盖安装Clawdbot、获取百炼API Key、配置环境变量与模型参数、验证调用等完整流程,支持Qwen3-max thinking (Qwen3-Max-2026-01-23)/Qwen - Plus等主流模型,助力本地化智能自动化。
🦞 如何在 OpenClaw (Clawdbot/Moltbot) 配置阿里云百炼 API
|
6天前
|
人工智能 JavaScript 应用服务中间件
零门槛部署本地AI助手:Windows系统Moltbot(Clawdbot)保姆级教程
Moltbot(原Clawdbot)是一款功能全面的智能体AI助手,不仅能通过聊天互动响应需求,还具备“动手”和“跑腿”能力——“手”可读写本地文件、执行代码、操控命令行,“脚”能联网搜索、访问网页并分析内容,“大脑”则可接入Qwen、OpenAI等云端API,或利用本地GPU运行模型。本教程专为Windows系统用户打造,从环境搭建到问题排查,详细拆解全流程,即使无技术基础也能顺利部署本地AI助理。
6514 13
|
4天前
|
人工智能 机器人 Linux
保姆级 OpenClaw (原 Clawdbot)飞书对接教程 手把手教你搭建 AI 助手
OpenClaw(原Clawdbot)是一款开源本地AI智能体,支持飞书等多平台对接。本教程手把手教你Linux下部署,实现数据私有、系统控制、网页浏览与代码编写,全程保姆级操作,240字内搞定专属AI助手搭建!
3794 11
保姆级 OpenClaw (原 Clawdbot)飞书对接教程 手把手教你搭建 AI 助手
|
4天前
|
存储 人工智能 机器人
OpenClaw是什么?阿里云OpenClaw(原Clawdbot/Moltbot)一键部署官方教程参考
OpenClaw是什么?OpenClaw(原Clawdbot/Moltbot)是一款实用的个人AI助理,能够24小时响应指令并执行任务,如处理文件、查询信息、自动化协同等。阿里云推出的OpenClaw一键部署方案,简化了复杂配置流程,用户无需专业技术储备,即可快速在轻量应用服务器上启用该服务,打造专属AI助理。本文将详细拆解部署全流程、进阶功能配置及常见问题解决方案,确保不改变原意且无营销表述。
4075 5
|
6天前
|
人工智能 JavaScript API
零门槛部署本地 AI 助手:Clawdbot/Meltbot 部署深度保姆级教程
Clawdbot(Moltbot)是一款智能体AI助手,具备“手”(读写文件、执行代码)、“脚”(联网搜索、分析网页)和“脑”(接入Qwen/OpenAI等API或本地GPU模型)。本指南详解Windows下从Node.js环境搭建、一键安装到Token配置的全流程,助你快速部署本地AI助理。(239字)
4209 21
|
12天前
|
人工智能 API 开发者
Claude Code 国内保姆级使用指南:实测 GLM-4.7 与 Claude Opus 4.5 全方案解
Claude Code是Anthropic推出的编程AI代理工具。2026年国内开发者可通过配置`ANTHROPIC_BASE_URL`实现本地化接入:①极速平替——用Qwen Code v0.5.0或GLM-4.7,毫秒响应,适合日常编码;②满血原版——经灵芽API中转调用Claude Opus 4.5,胜任复杂架构与深度推理。
7792 12
|
3天前
|
人工智能 安全 机器人
OpenClaw(原 Clawdbot)钉钉对接保姆级教程 手把手教你打造自己的 AI 助手
OpenClaw(原Clawdbot)是一款开源本地AI助手,支持钉钉、飞书等多平台接入。本教程手把手指导Linux下部署与钉钉机器人对接,涵盖环境配置、模型选择(如Qwen)、权限设置及调试,助你快速打造私有、安全、高权限的专属AI助理。(239字)
2544 5
OpenClaw(原 Clawdbot)钉钉对接保姆级教程 手把手教你打造自己的 AI 助手
|
4天前
|
人工智能 JavaScript API
零门槛部署本地AI助手:2026年Windows系统OpenClaw(原Clawdbot/Moltbot)保姆级教程
OpenClaw(原Clawdbot/Moltbot)是一款功能全面的智能体AI助手,不仅能通过聊天互动响应需求,还具备“动手”和“跑腿”能力——“手”可读写本地文件、执行代码、操控命令行,“脚”能联网搜索、访问网页并分析内容,“大脑”则可接入Qwen、OpenAI等云端API,或利用本地GPU运行模型。本教程专为Windows系统用户打造,从环境搭建到问题排查,详细拆解全流程,即使无技术基础也能顺利部署本地AI助理。
2994 5
|
7天前
|
人工智能 安全 Shell
在 Moltbot (Clawdbot) 里配置调用阿里云百炼 API 完整教程
Moltbot(原Clawdbot)是一款开源AI个人助手,支持通过自然语言控制设备、处理自动化任务,兼容Qwen、Claude、GPT等主流大语言模型。若需在Moltbot中调用阿里云百炼提供的模型能力(如通义千问3系列),需完成API配置、环境变量设置、配置文件编辑等步骤。本文将严格遵循原教程逻辑,用通俗易懂的语言拆解完整流程,涵盖前置条件、安装部署、API获取、配置验证等核心环节,确保不改变原意且无营销表述。
2361 6