DEV Community

zgl-20053779
zgl-20053779

Posted on

Open-source tool: Practical experience in converting large quantities of SQL code syntax : 'PIVOT' function rewrite (Case 2)

Background : In migration projects involving different databases, incompatibility of SQL syntax is often encountered.

Question : If there is a large amount of code that needs to be rewritten, manual processing would be time-consuming and prone to errors. Is it possible to achieve automatic conversion of code syntax in large quantities through tools?

Solution : The open-source tool ZGLanguage can be utilized to perform automated conversion of SQL code in large batches.

For example:

Suppose SQL PIVOT function is as follows :

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
;
Enter fullscreen mode Exit fullscreen mode

Using ZGLanguage conversion rules, execute the conversion to obtain the result :

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
;
Enter fullscreen mode Exit fullscreen mode

The conversion rules is as follows :

__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                  | '

Enter fullscreen mode Exit fullscreen mode

Detailed explanation of conversion rules :

The conversion rules of 'PIVOT' function mentioned above are quite complex, it cannot be converted all at once, needs to be completed through 3 conversions :

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
Enter fullscreen mode Exit fullscreen mode

The first conversion, trigger the rule 'FROM_PIVOT_2_1' to converts source code.

To complete :
(A) One-to-one mapping between value "(yr, qtr)" and enumeration values "Q1,Q2,Q3,Q4"
(B) Add 'where' structure(Converted from 'FOR' structure)

The result were obtained as follows :

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
;
Enter fullscreen mode Exit fullscreen mode

The 2nd conversion, trigger the rule 'FROM_PIVOT_2_2' to convert the above conversion result again.

To complete :

(A) Cartesian product of "SUM" columns and "qtr" columns
(B) Extract enumeration values to prepare for generating new field aliases

And the result is as follows :

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
;
Enter fullscreen mode Exit fullscreen mode

The 3rd conversion, trigger the rule 'FROM_PIVOT_2_3' to convert the result of 'FROM_PIVOT_2_2' again.

To complete :
(A) Perform operations such as adding, shifting, and merging on the field content starting with SUM to form a syntactically correct field code
(B) Remove key word 'PIVOT', move table name above 'where' statement
(C) Concatenate to create new field names
(D) Newly added parts to be manually supplemented: select ###,###,###   group by ###,###,###

Obtain the finally result :

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
;
Enter fullscreen mode Exit fullscreen mode

Description of "###,###,###" :

  1. It cannot obtains the fully available SQL code through syntax conversion, some code sections still require manual supplementation
  2. The parts that require manual supplementation have been clearly marked with "###,###,###"
  3. Most of the conversion work has been completed through tool, greatly reduces the workload of manual participation, avoids the risk of errors caused by manual modification.

Top comments (0)