Trae + SQLazy Practice: Breathing New Life into Legacy SQL

 

I. Introduction

Almost every data team has a piece of "legacy SQL" in their codebase that no one wants to touch. A hundred or even hundreds of lines, with dozens of nested CTEs and window functions nested inside window functions. The person who wrote it has long left the company, comments are almost non-existent, no one dares to modify it, and no one can fully understand it. When a business metric needs to change, the person taking over needs to spend hours figuring out what each subquery does, then spend hours debugging after changes, terrified that changing one line might break the entire logic.

Even with AI programming, things don't improve much. Due to hallucinations, AI can only assist interpretation, and ultimately engineers need to confirm. After interpretation, you just get another document, which may not match over time. Moreover, SQL regenerated by AI based on modified requirements is likely to be completely different from the original, requiring time and effort to re-verify, and adding another piece of'legacy SQL'.

Can we crystallize AI's interpretation results into code that can be both read as documentation and compiled for execution?

This is what SQLazy scripts are for.

AI understands SQL, then translates it into structured, readable, and verifiable SQLazy (*.nspl) scripts. For handover and inheritance, you only need to use this script, and the final SQL can be compiled and generated by SQLazy at any time. SQLazy's compilation engine does not depend on large models — deterministic inputs always produce deterministic outputs. When modification needs arise in the future, you just need to modify and debug based on this readable SQLazy script, then recompile to get new SQL.

This article attempts to use Trae as the "brain," responsible for understanding SQL semantics, breaking down business logic, and generating SQLazy step-by-step scripts; then use the SQLazy IDE as the "execution layer," responsible for syntax validation, step-by-step debugging, and final code compilation. Together they form a closed loop of "AI interpretation + human review + deterministic engine compilation," bringing legacy SQL back to life.

II. Tools' Roles and Capabilities

1. Trae: The "Brain" for Understanding and Translation

Trae is an AI programming tool that can be used both as a standalone IDE and as a VS Code-style editor. Here, Trae plays three roles:

(1) Automatic loading of project knowledge base. The project deploys global specification files (plan.md) that declare the output format specification for SQLazy scripts (three-column tab-separated, single function per step), hard constraints (reserved word handling, cross-step reference rules), and loading paths for function and feature documentation. When the user enters "/sqlazy-plan" Trae automatically inherits all the above rules without needing to redeclare them.

(2) Structured four-step output. Trae is constrained to output solutions following four steps: capability review, requirement decomposition, function matching, and code implementation — rather than directly giving conclusions. This forced output process ensures the reviewability of solutions; the rationale for each step is clearly visible. The final output is a structured SQLazy script, not a chunk of hard-to-read SQL.

(3) Proactive clarification of requirement boundaries. Facing complex requirements, Trae will proactively raise key questions, such as: How should the date range be defined? How should null values be handled? Is the grouping key unique? This avoids AI "self-righteously" assuming prerequisites.

2. SQLazy: The "Hands" for Execution and Verification

SQLazy is a structured data computing tool with a dedicated IDE for writing and executing .nspl scripts. In simple terms, it breaks complex business logic into readable "operation instructions," each completing one data processing step. The SQLazy IDE receives .nspl scripts output by Trae and provides three guarantees:

(1) Single-step semantics are clear, with low audit barriers. Taking "stock consecutive rise days" as an example, the .nspl script only needs 5 steps: filter → sort → segment → summarize count → summarize max. Reading the entire script is like reading a business operation checklist.

(2) Step-by-step execution for rapid problem localization. In the IDE, you can run each step individually and view intermediate results in real time. Once a step's output doesn't meet expectations, you can immediately locate the specific logic error.

(3) One script, multi-database compilation. After verification, one-click compilation generates standard SQL for mainstream databases like MySQL, PostgreSQL, Oracle, etc., without needing to rewrite for different databases.

III. Operational Process

3.1 Environment Preparation

The project adopts the following standard directory structure:

project_root/
├── plan.md         # Global specification: format standards, loading paths
├── sqlazy
-plan.md   # Command entry: /sqlazy-plan trigger, inherits all rules from plan.md
├── nspl/            # Delivery directory: SQLazy scripts stored here
├── function/        # Function reference documentation (auto-loaded)
└──
action/          # Action reference documentation (auto-loaded)

After creating a new project in Trae, copy the sqlazy-plan.md, plan.md files and the function and action directories from the LLM directory under the SQLazy installation directory to the project root directory.

3.2 Trigger Method

Use the "/sqlazy-plan" command in the Trae chat box to trigger the task, followed by a complete business requirement description.

3.3 Verification and Correction

This is the most critical step in the entire chain:

1. Construct a small amount of representative test data and manually calculate expected results

2. Run the script step by step in the SQLazy IDE and compare intermediate results with expected values

3. When issues are found, you can directly modify the script or feed it back to Trae to regenerate

After verification passes, compile to generate SQL for the corresponding database. This step is very simple and won't be mentioned in the practical examples below.

IV. Hands-on Cases

The following five cases are presented in order of "from simple to complex, from smooth to frustrated." The first three cases demonstrate different difficulty levels of translation processes, the fourth case records the real journey of multiple corrections, and the last case is a typical failure case where "the script runs but results are wrong," showing the blind spots when AI understands business logic.

Case 1: Segmented Cumulative by Condition — Passed First Try

Original SQL functionality: The id field of the data table exam_tbl is used for sorting, the logic field is used for condition judgment, and val is used for segmented accumulation. A new calculated column output is added: when logic==true, output is set to 1; otherwise, output accumulates and takes the value of the previous row's output + val.

[Operation] type the following into the Trae chat box:

/sqlazy-plan Convert the following SQL statement to SQLazy script:
with table1 as (
	SELECT *, countif(logic) over win1 as logic_run
	FROM exam_tbl
	window win1 as (order by id rows between unbounded preceding and current row)
)
SELECT *,
	sum(val) over win2 as sum_over,
	sum(if(logic,1,val)) over win2 as output
from table1
window win2 as (partition by logic_run order by id rows between unbounded preceding and current row)

[Trae's SQL Analysis]

Trae analyzed: This SQL has two layers of windows. The first layer window win1 is sorted by id, using countif(logic) for cumulative counting — every time a row with logic=true is encountered, logic_run increments by 1, thereby dividing data into multiple 'segments'. The second layer window win2 is within the logic_run segment, sorted by id to separately sum val (sum_over) and sum the conditional expression if(logic,1,val) (output). Translating to NSPL: countif can be replaced by a two-step process of 'condition → accumulate', and partitioned accumulation uses 'accumulate + partition'.

[Generated SQLazy Script]

VariableName

Anchor

Statement

t1

exam_tbl

sort id

t2


compute if(logic then 1 else 0), as logic_flag

t3


compute logic_flag, cum, as logic_run

t4


compute if(logic then 1 else val), as logic_val

t5


compute val, cum, as sum_over; partition logic_run

t6


compute logic_val, cum, as output; partition logic_run

t7


derive id, logic, val, logic_run, sum_over, output

This is a "textbook-style" translation — the SQL window function semantics are clear, and SQLazy's"accumulate"and"partition" features naturally correspond to them. Trae generated it once and it passed in the SQLazy IDE without corrections.

Case 2: Conditional Grouping — Passed After One Syntax Correction

Original SQL functionality: The data table test_table_mm has fields id, split, cust, date_column, amount, etc. Conditional grouping needs to be performed: group by the first two fields id and split. If the date_column within the group has no duplicates, keep the record with the most recent date and replace amount with the sum of amount for the group; if dates within the group have duplicates, regroup the records by cust, keep the record with the most recent date in the current subgroup, and replace amount with the sum of amount for the current subgroup.

[Operation] type the following into the Trae chat box:

/sqlazy-plan Convert the following SQL statement to SQLazy script:
SELECT id, 
       split,
       cust,
       date_column,
       CASE num_cust
       WHEN 1
       THEN total_amount
       ELSE total_cust_amount
       END AS amount
FROM   (
  SELECT t.*,
         COUNT(DISTINCT CASE rnk WHEN 1 THEN cust END)
           OVER (PARTITION BY id, split) AS num_cust
  FROM   (
    SELECT t.*,
           DENSE_RANK() OVER (PARTITION BY id, split ORDER BY date_column DESC) AS rnk,
           SUM(amount) OVER (PARTITION BY id, split) AS total_amount,
           SUM(amount) OVER (PARTITION BY id, split, cust) AS total_cust_amount
    FROM   test_table_mm t
  ) t
  WHERE  rnk = 1
)

[Trae's SQL Analysis]

Trae analyzed: Need to first partition by id and split, use ranking to find the row with the maximum date_column (rnk=1). Simultaneously calculate two sums: total_amount grouped by id+split, and total_cust_amount grouped by id+split+cust three-key. After filtering rows with rnk=1, count the unique cust num_cust in each id+split group. Finally use a conditional function to determine: if num_cust=1 take total_amount, otherwise take total_cust_amount.

[Generated SQLazy Script]

VariableName

Anchor

Statement

t2

test_table_mm

rank date_column desc;chinese rank; partition id, split; as rnk

t3


compute amount, sum, as total_amount; partition id, split

t4


compute amount, sum, as total_cust_amount; partition id, split, cust

t5


filter (rnk = 1)

t6


compute cust, icount, as num_cust; partition id, split

t7


compute if(num_cust = 1 then total_amount else total_cust_amount), as amount

t8


derive id, split, cust, date_column, amount

[Syntax Correction]

During runtime, SQLazy reported an error: in the "rank" statement at line t2, the "option"parameter was initially written as"chinese rank"which is not a valid SQLazy keyword. The ranking function parameter in SQLazy should be"dense"(indicating Chinese ranking, where tied ranks are not skipped). After correcting"chinese rank"to"dense" in the first line of code, the script ran successfully.

Case 3: Backtracking Initial Date with Sum — Passed After One Syntax Correction

Original SQL functionality: The data table table_name records the inbound quantity of specific date plans and the cumulative inventory after inbound. Now we need to use the cumulative inventory to backtrack to the initial date — the day with zero or negative inventory — and fill in the inbound quantity UPDATED_QTY and original inventory UPDATED_CUSTQTY after each day's consumption.

[Operation] type the following into the Trae chat box:

/sqlazy-plan Convert the following SQL statement to SQLazy script:
SELECT t.*,
       LEAST(
         GREATEST(
           COALESCE(
             SUM(
               CASE WHEN needdate < TRUNC(to_date('2024-02-26')) + 1 THEN qty END
             ) OVER (PARTITION BY item, loc ORDER BY needdate DESC) - custqty,
             qty
           ),
           0
         ),
         qty
       ) AS updated_qty,
       CASE
       WHEN needdate > TRUNC(to_date('2024-02-26'))
       THEN NULL
       WHEN SUM(
              CASE WHEN needdate < TRUNC(to_date('2024-02-26')) + 1 THEN qty END
            ) OVER (
              PARTITION BY item, loc
              ORDER BY needdate DESC
              ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
            ) >= custqty
       THEN NULL
       ELSE GREATEST(
              custqty
              - SUM(
                CASE WHEN needdate < TRUNC(to_date('2024-02-26')) + 1 THEN qty END
              ) OVER (PARTITION BY item, loc ORDER BY needdate DESC),
              0
           )
       END AS updated_custqty
FROM   table_name t

[Trae's SQL Analysis]

Trae analyzed: This is an inventory calculation logic that 'uses sum to backtrack to the initial date'. Need to first sort, conditionally filter, partition and accumulate, then compare the previous row's cumulative value (prev_cumulative_qty) with custqty, and rewrite qty and custqty in three scenarios: if accumulation is insufficient, clear qty and deduct custqty; if accumulation is exactly right, take the difference; if accumulation exceeds, keep qty and clear custqty. Conditional functions need nested processing.

[Generated SQLazy Script]

VariableName

Anchor

Statement

t2

table_name

sort needdate desc

t3


compute if(needdate < date(2024-02-26) + 1 then qty else 0), as filtered_qty

t4


compute filtered_qty, cum, as cumulative_qty; partition item, loc

t5


compute cumulative_qty[-1], as prev_cumulative_qty

t6


compute if(nvl(cumulative_qty - custqty, qty) < 0 then 0, nvl(cumulative_qty - custqty, qty) > qty then qty; else nvl(cumulative_qty - custqty, qty)), as updated_qty

t7


compute if(needdate > date(2024-02-26) then null, prev_cumulative_qty >= custqty then null; else if(custqty - cumulative_qty < 0 then 0; else custqty - cumulative_qty)), as updated_custqty

t8


derive append updated_qty, updated_custqty

[Syntax Correction]

Runtime error: the date constants in lines t3 and t7 were written without quotes as date(2024-02-26). SQLazy's date function requires the date parameter to be a string constant, which must be enclosed in double quotes. After correcting date(2024-02-26) to date("2024-02-26") in the code, the script ran successfully.

Case 4: Time Interval Aggregation — Passed After Multiple Corrections

Original SQL functionality: The data table tmstmp has two columns dt and payload, storing time-series data with records spaced several seconds apart. Now we need to group and aggregate every minute, summarizing 5 minutes of data each time. For example, if 3 records are generated in the 1st, 2nd, and 3rd seconds, data for minutes 1-5, 2-6, and 3-7 are summarized respectively.

[Operation] type the following into the Trae chat box:

/sqlazy-plan Convert the following SQL statement to SQLazy script:
SELECT
    [From], DATEADD(MINUTE, 1, [To]) [To], payload
FROM (
    SELECT
        dt, MIN(dt) OVER(ORDER BY dt ROWS BETWEEN 4 PRECEDING AND CURRENT ROW) [From],
        dt [To], SUM(payload) OVER(ORDER BY dt ROWS BETWEEN 4 PRECEDING AND CURRENT ROW) payload
    FROM (
        SELECT
            DATEADD(MINUTE, DATEDIFF(MINUTE, 0, dt), 0) dt, 
SUM(payload) payload
        FROM #tmstmp
        GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, 0, dt), 0)
    ) q
) q
WHERE DATEDIFF(MINUTE, [From], [To]) > 3

[Trae's SQL Analysis]

Trae analyzed: The inner layer first truncates dt to minute-level and performs GROUP BY summation to get the payload per minute; the middle layer uses a 5-row sliding window (4 PRECEDING to CURRENT ROW) to take MIN(dt) within the window as From, current dt as To, and SUM(payload) as payload; the outer layer filters DATEDIFF(From,To)>3 and adds 1 minute to To. Translating to SQLazy: '5-row window' can be implemented using 'row reference [-4] to current row'; when data is sorted, MIN(dt) equals mt[-4] (the earliest time row).

[Generated SQLazy Script]

VariableName

Anchor

Statement

t1

tmstmp

compute datetime(dt; precision minute) as mt

t2


summarize payload total as payload; group mt

t3

t2

sort mt

t4


compute mt[-5] as from_t, mt[-1] as to_t, nvl(payload[-5],0)+payload[-4]+payload[-3]+payload[-2]+payload[-1]+payload as payload

t5


filter (interval(from from_t, to to_t; minute)> 3)

t6


derive from_t, to_t + 1/1440 as to_t, payload

[Multiple Corrections Process]

This case best demonstrates the complete closed loop of "AI first draft + human feedback + iterative correction." Trae made several types of errors, each representative:

Error Correction Records

Round

Error Symptom

Root Cause

Correction Method

Round 1

Parameter[] value setting error

Misused "total"as aggregation function keyword; should be"sum" in SQLazy

Change "total"to"sum"

Round 2

Value [from] has no matching parameter

Interval function mistakenly included parameter names "from" "to"; SQLazy requires omitting these

Remove parameter names, write as positional parameters: interval(from_t, to_t; minute)

Round 3

from_t null value rows not filtered out

When from_t is null, interval function returns null

Change to: filter (from_t not empty)

Round 4

Unrecognized expression: from_t not empty

"not empty" is not valid SQLazy syntax

Change "not empty" to "notnull"

Round 5

Time interval only 4 minutes

Window offset error; mt[-1] and mt[-5] caused window to miss one row

Change to mt (current row) and mt[-4] (previous 4 rows)

Round 6

to_t + 1/1440 value unchanged after operation

Float 1/1440 has precision loss; time addition not effective

Use SQLazy's"elapse" function: (to_t elapse 1 minute)

[Final Script]

VariableName

Anchor

Statement

t1

tmstmp

compute datetime(dt; precise minute), as mt

t2

t1

summarize payload sum as agg_payload; group mt

t3

t2

sort mt

t4


compute mt, as to_t; mt[-4], as from_t; nvl(agg_payload[-4], 0)+ nvl(agg_payload[-3], 0)+ nvl(agg_payload[-2], 0)+ nvl(agg_payload[-1], 0) + agg_payload, as payload

t5


filter (from_t notnull)

t6


derive from_t, (to_t elapse 1 minute) as to_t, payload

Six rounds of correction sounds like a lot, but each round of feedback is as simple as "paste the error message to Trae," and Trae can mostly locate and fix the issue in one round. This is the value of the "AI interpretation + human review + small data verification" process: AI does the work, humans check, and when errors occur, paste them back for AI to fix.

Case 5: Time Window Statistics — Script Runs But Results Are Wrong

Original SQL functionality: The data table main has time and value fields. The time field is the time, and the time interval is sometimes greater than 1 minute. Now we need to divide data into one-minute windows, fill in missing windows, and calculate 4 values for each window: start_value (the last record of the previous window), end_value (the last record of the current window), min (minimum value of the current window), max (maximum value of the current window). The start_value for the first minute uses the first record of the current window; if a window's data is missing, use the last record of the previous window instead (same as the current window's start_value).

[Operation] type the following into the Trae chat box:

/sqlazy-plan Convert the following SQL statement to SQLazy script:
with overview as (
    SELECT 
        distinct on (a.time) a.id, a.time, b.time as "end", a.value, 
        date_trunc('minute', a.time) as minute_start, 
        date_trunc('minute', b.time) as minute_end 
    FROM 
        main a 
    left join 
        main b 
    on 
        a."time"<b."time" and a.id = b.id 
    order by 
        a.time, b.time asc
    ),
overview2 as (
    select 
        id, value, true as backfill,
        date_trunc('minute', "end") as time, 
        date_trunc('minute', "end") as minute
    from 
        overview 
    where 
        minute_start <> minute_end
    UNION ALL
    select 
        id, time, value, false as backfill,
        date_trunc('minute', time) as minute
    from 
        overview
    ),  
overview3 as (
    select 
        * 
    from 
        overview2 
    UNION ALL (
        Select 
            distinct on (a.missingminute) 
            c.id, 
            a.missingminute as time, 
            a.missingminute as minute, 
            c.value, 
            true as backfill 
        from (
            SELECT 
                date_trunc('minute', time.time) as missingminute
            FROM 
                generate_series((select min(minute) from overview2),(select max(minute) from overview2),'1 minute'::interval) time 
            left join (
                select distinct 
                    minute 
                from 
                    overview2
                ) b 
            on 
                date_trunc('minute', time) = b.minute 
            where 
                b.minute isnull
            ) a 
        left join 
            main c 
        on 
            a.missingminute > c.time 
        order by 
            a.missingminute, 
            c.time desc
        ) 
    order by 
        time
    )
select 
    t1.id, 
    t1.minute as minute_start, 
    t1.minute + interval '1 minute' as minute_end, 
    t1.backfill as start_backfill,
    t1.start, 
    t2.end, 
    coalesce(t3.min, t1.start) as min, 
    coalesce(t3.max, t1.start) as max 
from 
    (select distinct on (id, minute) id, minute, value as start, backfill from overview3 order by id, minute, time asc) t1 
left join
    (select distinct on (id, minute) id, minute, value as end from overview3 order by id, minute, time desc) t2 on t1.id = t2.id and t1.minute = t2.minute 
left join
    (select id, minute, min(value) min, max(value) max from overview2 group by id,minute) t3 on t1.id = t3.id and t1.minute = t3.minute

[Trae's SQL Analysis]

Trae analyzed: This SQL's overview uses a self-join to find the next time point, overview2 splits records spanning minute boundaries and marks backfill, overview3 uses generate_series to fill missing minutes, and finally outputs start, end, min, max for each minute. Trae translated this understanding into a 23-step SQLazy script.

[Generated SQLazy Script (Key Steps Excerpt)]

VariableName

Anchor

Statement

t1

main

sort 'time'

t2


compute # as id, 'time'[1] as next_time

t3


compute datetime('time'; precision minute) as mt, datetime(next_time; precision minute) as mt_end

t4


filter (mt <> mt_end)

t5


derive id, mt_end as 'time', value, true as backfill, mt_end as mt

t6

t3

derive id, 'time', value, false as backfill, mt

t7

t6

set union; t5

...


(intermediate steps omitted, total 23 steps)

t9

t7

summarize value min as vmin, value max as vmax; group by mt

t23


derive filled_id as id, mt as minute_start, ... nvl(vmin, filled_start) as vmin, nvl(vmax, filled_start) as vmax

[Problem: Script Runs But Results Are Wrong]

After multiple rounds of syntax corrections, it finally ran successfully, but when comparing with test data, the results didn't match expectations. Trae had a semantic deviation in understanding the SQL during translation.

[Deep Analysis of Trae's Understanding Deviation]

Deviation Analysis

Deviation

Trae's Understanding

Actual SQL Logic

Deviation 1: Mistook "id" as row number

Calculated "# as id" (row number) in line t2

a.id in SQL is a real data column in the main table, a "sequence/grouping key" (multiple records with the same id form a time series). SQL groups and deduplicates by (id, minute) throughout. Using row number as id completely loses the "sequence by id" semantics, causing all sequences to be mixed in the same minute bucket for aggregation.

Deviation 2: Used "next row" instead of "next event of same id"

Used 'time'[1] in line t2 — only the next row after sorting by time, without id constraint

SQL's self-join condition is a.time<b.time AND a.id=b.id — filter by id first before taking the next record. After sorting multi-id data by time, adjacent rows likely belong to different ids, so the'next event of another id'is treated as the'next event of this id,' generating incorrect backfill rows.

Deviation 3: "Previous value leakage" in min/max

Directly aggregated min/max from overview2

SQL's overview2 mixes'previous value continuation backfill rows'with'real events', and the final query's t3 directly aggregates min/max from overview2 — causing 'previous value continuation values' to leak into the extreme value statistics.

[Lesson Learned]

This case reveals an important fact: AI can mechanically "translate" SQL syntax, but may not accurately understand the business intent behind SQL. When the SQL itself has "semantic mixing" in its design (e.g., overview2 contains both previous value continuation rows and real events, and aggregates extreme values from them), AI will faithfully carry this "design flaw" into SQLazy, causing incorrect results. This situation cannot be fixed by "pasting errors" alone — because the script doesn't error — it just"calculates incorrectly."

V. Summary: Process, Experience, and Boundaries

1. Standard Process for Solving Legacy SQL

Through the practical operation of the above five cases, we can extract a standard process for "converting legacy SQL to SQLazy":

Step 1: Initiate command. Send the SQL code to Trae, with the attached "/sqlazy-plan Convert the following SQL statement to SQLazy script" command.

Step 2: Generate first draft. Trae outputs the initial SQLazy script following a four-step process (capability review → requirement decomposition → function matching → code implementation).

Step 3: Test and verify. Import test data in the SQLazy IDE, run the script step by step, and compare intermediate results with expected values.

Step 4: Feedback and correct. If there are syntax or logic errors, feed the error message back to Trae for correction. Repeat until it runs correctly.

Step 5: Compile and deliver. After verification passes, one-click compilation generates SQL for the target database for production use.

Save this SQLazy script for future modification and handover, without needing to keep the hard-to-understand SQL script.

2. Experience Summary

Through the operation of these cases, we can draw a relatively optimistic but sober conclusion:

Most SQL statements can be correctly translated to readable, easily verifiable SQLazy code. From Case 1 passed first try, to Cases 2 and 3 passed after one correction, to Case 4 passed after 6 rounds of correction, these cases cover typical scenarios like segmented conditions, conditional grouping, inventory backtracking, and time interval aggregation. Trae ultimately delivered correct answers. SQLazy scripts'"single-step semantics are clear" feature allows business logic originally buried in SQL nesting to be exposed to sunlight, significantly lowering the barrier for human review.

But there are a few very complex SQL statements where Trae may deviate in understanding business logic, leading to incorrect results. Case 5 is a typical counterexample — the script doesn't error, but the results are wrong.

3. Advanced Strategy for Handling Complex SQL

Facing complex SQL like Case 5, simply "sending SQL to Trae for translation" is no longer sufficient. A more reliable approach is:

First, let Trae analyze the SQL's functionality step by step to assist engineers in reading and understanding SQL. For example, you can ask Trae:"Please analyze what query requirements this SQL statement completes"— let Trae explain what overview, overview2, and overview3 each do layer by layer, and what the final output is. The purpose of this step is to let humans (not AI) first understand the SQL's true intent.

After understanding the SQL's true intent, submit the"requirement description"(rather than the original SQL) to Trae, letting it write the SQLazy script based on the requirement description. This avoids the trap of"SQL itself has design flaws, and AI faithfully carries the flaws over"— because you describe"what should be done,"not"how SQL does it," allowing AI to use more straightforward algorithms to write the SQLazy script.

Ultimately, AI is a productivity amplifier, not an "automatic vending machine" that replaces human judgment. Where should legacy SQL go? The answer is not "throw it to AI for automatic translation," but a three-way collaboration of "humans understand intent, AI converts scripts, engines verify execution." Only then can legacy SQL transform from a "time bomb no one dares to touch" into a "business asset readable by everyone."