Blog JSystems - uwalniamy wiedzę!

Szukaj
Refaktoryzacja i konwersja dialektów: zrzuty z ChatGPT i SQL Server Management Studio z części 6 przewodnika AI w SQL
Część 6 przewodnika AI w SQL. Na obrazie trzy prawdziwe zrzuty z tej części.

W skrócieAI dobrze przepisuje stary SQL na czytelny i tłumaczy zapytania między dialektami, ale wynik trzeba udowodnić na bazie. Pokazujemy refaktoryzację zapytania z dowodem przez EXCEPT i sumę kontrolną oraz trzy konwersje do PostgreSQL: z Oracle, SQL Server i MySQL, każdą z tym samym wynikiem w obu bazach.

To część 6 z 8 przewodnika AI w SQL. Wszystkie przykłady powstały na bazie DemoShop w SQL Server 2022: fikcyjnym sklepie internetowym z 2,4 mln zamówień. Polecenia wpisujemy do ChatGPT, ale te same możesz podać Microsoft Copilotowi, Claude albo Gemini. Przy skryptach korzystających z mechanizmów serwera w małej szarej ramce znajdziesz ich odpowiedniki dla Oracle i PostgreSQL.

Pliki do tej części

Skrypt bazy uruchamiasz w SSMS na serwerze SQL Server 2019 lub nowszym. Tworzy bazę DemoShop, na której powstały wszystkie przykłady.

Refaktoryzacja starego SQL z AI

Refaktoryzacja to przebudowa kodu bez zmiany tego, co kod robi. W SQL oznacza to zwykle: złączenia zapisane jawnie przez JOIN zamiast przecinków w FROM, logikę rozbitą na nazwane kroki CTE, czytelne aliasy, komentarze tam, gdzie reguła nie jest oczywista, i usunięte powtórzenia. AI robi to szybko i zwykle dobrze. Trudność jest gdzie indziej: trzeba udowodnić, że wynik się nie zmienił, bo „przepisane ładniej” nie może oznaczać „liczy trochę inaczej”.

Wzięliśmy zapytanie w stylu, który zna każdy, kto przejmował raporty po poprzednikach: aliasy jednoliterowe, złączenia po przecinku, warunek z podzapytaniem w IN, to samo wyrażenie na wartość pozycji w dwóch miejscach i polskie nazwy kolumn bez wielkich liter.

select x.rok, x.mies, x.seg, count(*) ile_klientow, sum(x.wart) wartosc,
  sum(case when x.ile_zam>1 then 1 else 0 end) powracajacy,
  round(sum(x.wart)/count(*),2) srednio_na_klienta,
  round(100.0*sum(case when x.ile_zam>1 then 1 else 0 end)/count(*),1) proc_powracajacych
from (select year(a.OrderDate) rok, month(a.OrderDate) mies, b.Segment seg, a.CustomerID kl,
        count(distinct a.OrderID) ile_zam,
        sum(c.Quantity*c.UnitPrice*(100-c.DiscountPct)/100) wart
      from dbo.Orders a, dbo.Customers b, dbo.OrderItems c
      where a.CustomerID=b.CustomerID and c.OrderID=a.OrderID and a.Status<>'CANCELLED'
        and a.OrderDate>='20250101' and a.OrderDate<'20260101'
        and a.CustomerID in (select d.CustomerID from dbo.Orders d, dbo.OrderItems e
                             where e.OrderID=d.OrderID and d.Status<>'CANCELLED'
                               and d.OrderDate>='20250101' and d.OrderDate<'20260101'
                             group by d.CustomerID
                             having sum(e.Quantity*e.UnitPrice*(100-e.DiscountPct)/100)>1000)
      group by year(a.OrderDate), month(a.OrderDate), b.Segment, a.CustomerID) x
group by x.rok, x.mies, x.seg
order by 1,2,3
Stare zapytanie T-SQL z aliasami jednoliterowymi i złączeniami po przecinku uruchomione w SSMS: 24 wiersze raportu miesięcznego według segmentu
Stare zapytanie działa i zwraca 24 wiersze: 12 miesięcy razy dwa segmenty. To jest wynik, którego refaktoryzacja nie może zmienić.

Polecenie do AI ma trzy części: co poprawić w formie, twardy warunek „wynik identyczny co do kolumny i wiersza” i prośbę, żeby podejrzane miejsca w logice opisać, a nie poprawiać. Ostatnia część jest ważna. Refaktoryzacja i naprawa błędów to dwie różne zmiany i mieszanie ich w jednym kroku sprawia, że nie da się już udowodnić, że wynik jest ten sam.

Refaktoryzuj to stare zapytanie T-SQL (SQL Server 2022) tak, żeby było czytelne i łatwe w utrzymaniu: zamień złączenia po przecinku na JOIN, rozbij logikę na nazwane kroki CTE z komentarzami, nadaj aliasom znaczące nazwy i usuń powtórzenia wyrażeń. Wynik musi pozostać identyczny: te same kolumny pod tymi samymi nazwami, te same wartości, ta sama kolejność wierszy. Jeśli zauważysz w logice coś podejrzanego, nie poprawiaj tego, tylko opisz pod kodem.

[stare zapytanie]

ChatGPT refaktoryzuje stare zapytanie na trzy nazwane kroki CTE z komentarzami: klienci powyżej progu, wyniki klientów i wskaźniki, z jawnymi JOIN
Wersja od AI: trzy kroki CTE z komentarzami, jawne JOIN-y, warunek IN zamieniony na złączenie z listą klientów powyżej progu, nazwy kolumn wyniku zachowane.

Najcenniejsza część odpowiedzi jest pod kodem. ChatGPT zauważył dwie rzeczy, które w starym zapytaniu łatwo przeoczyć. Kolumna powracajacy nie liczy klientów, którzy wrócili po wcześniejszych zakupach, tylko tych, którzy złożyli więcej niż jedno zamówienie w danym miesiącu, więc nazwa wprowadza w błąd. Próg 1000 zł liczony jest za cały rok, więc klient, który przekroczył go dopiero zakupami z grudnia, trafia także do statystyk styczniowych. Obie uwagi są trafne i obie dotyczą znaczenia raportu, a nie składni. Zgodnie z poleceniem AI ich nie poprawiło, tylko opisało, co zostawia decyzję właścicielowi raportu.

Jedno zalecenie z polecenia AI spełniło tylko częściowo: wyrażenie na wartość pozycji nadal występuje w dwóch krokach. Nie zmienia to wyniku, ale pokazuje, że listę oczekiwań warto po odpowiedzi przejść punkt po punkcie.

Dowód, że wynik się nie zmienił

Do sprawdzenia równoważności używamy tego samego szablonu co w sekcji o AI jako nauczycielu, rozszerzonego o drugą kontrolę. Pierwsze zapytanie zwraca wiersze, które są tylko w jednej z wersji (EXCEPT w obie strony). Drugie porównuje liczbę wierszy i sumę kontrolną CHECKSUM_AGG(CHECKSUM(*)), która wyłapie także różnicę w liczbie powtórzeń tego samego wiersza, czego EXCEPT nie widzi.

Cały skrypt dowodu ma 223 linie, bo zawiera obie wersje raportu, więc nie wklejamy go tutaj. Do skopiowania jest w pliku refaktoryzacja_dowod_rownowaznosci.sql.

Dowód równoważności w SSMS: zero wierszy różnicy EXCEPT oraz identyczna liczba wierszy 24 i identyczna suma kontrolna starej i nowej wersji zapytania
Zero wierszy różnicy, 24 wiersze w obu wersjach i identyczna suma kontrolna. Dodatkowo porównaliśmy oba wyniki wiersz po wierszu, z kolejnością: są identyczne.
WITH
-- Krok 1: klienci, których łączna wartość nieanulowanych zamówień
-- w 2025 roku przekracza 1000.
KlienciPowyzejProgu AS
(
    SELECT
        Orders.CustomerID
    FROM dbo.Orders AS Orders
    INNER JOIN dbo.OrderItems AS OrderItems
        ON OrderItems.OrderID = Orders.OrderID
    WHERE Orders.Status <> 'CANCELLED'
      AND Orders.OrderDate >= '20250101'
      AND Orders.OrderDate <  '20260101'
    GROUP BY
        Orders.CustomerID
    HAVING
        SUM(
            OrderItems.Quantity
            * OrderItems.UnitPrice
            * (100 - OrderItems.DiscountPct)
            / 100
        ) > 1000
),

-- Krok 2: agregacja na poziomie klienta, miesiąca i segmentu.
WynikiKlientow AS
(
    SELECT
        YEAR(Orders.OrderDate)  AS rok,
        MONTH(Orders.OrderDate) AS mies,
        Customers.Segment      AS seg,
        Orders.CustomerID      AS kl,
        COUNT(DISTINCT Orders.OrderID) AS ile_zam,
        SUM(
            OrderItems.Quantity
            * OrderItems.UnitPrice
            * (100 - OrderItems.DiscountPct)
            / 100
        ) AS wart
    FROM dbo.Orders AS Orders
    INNER JOIN dbo.Customers AS Customers
        ON Customers.CustomerID = Orders.CustomerID
    INNER JOIN dbo.OrderItems AS OrderItems
        ON OrderItems.OrderID = Orders.OrderID
    INNER JOIN KlienciPowyzejProgu AS KwalifikowaniKlienci
        ON KwalifikowaniKlienci.CustomerID = Orders.CustomerID
    WHERE Orders.Status <> 'CANCELLED'
      AND Orders.OrderDate >= '20250101'
      AND Orders.OrderDate <  '20260101'
    GROUP BY
        YEAR(Orders.OrderDate),
        MONTH(Orders.OrderDate),
        Customers.Segment,
        Orders.CustomerID
),

-- Krok 3: obliczenia pomocnicze używane w agregacji końcowej.
WynikiKlientowZWskaznikami AS
(
    SELECT
        rok,
        mies,
        seg,
        wart,
        CASE
            WHEN ile_zam > 1 THEN 1
            ELSE 0
        END AS czy_powracajacy
    FROM WynikiKlientow
)

SELECT
    rok,
    mies,
    seg,
    COUNT(*) AS ile_klientow,
    SUM(wart) AS wartosc,
    SUM(czy_powracajacy) AS powracajacy,
    ROUND(SUM(wart) / COUNT(*), 2) AS srednio_na_klienta,
    ROUND(
        100.0 * SUM(czy_powracajacy) / COUNT(*),
        1
    ) AS proc_powracajacych
FROM WynikiKlientowZWskaznikami
GROUP BY
    rok,
    mies,
    seg
ORDER BY
    1,
    2,
    3;
Wersja zapytania po refaktoryzacji przez AI uruchomiona w SSMS, z krokami CTE KlienciPowyzejProgu i WynikiKlientow, zwraca te same 24 wiersze
Nowa wersja w SSMS: ten sam wynik, a kod da się czytać od góry do dołu i uruchamiać krok po kroku.
Kolejność pracy przy refaktoryzacji z AI: zapisz wynik starej wersji, poproś o refaktoryzację z zakazem poprawiania logiki, uruchom dowód równoważności, a dopiero potem, osobną zmianą, popraw to, co AI opisało jako podejrzane. Każdą zmianę logiki zatwierdza właściciel raportu, bo zmieni ona liczby, które ktoś już raportował.

Konwersja między dialektami: Oracle, SQL Server i MySQL do PostgreSQL

Przenoszenie zapytań między bazami to zadanie, w którym AI oszczędza najwięcej czasu, bo zna mapowania funkcji i składni wszystkich popularnych silników. Ryzyko leży w szczegółach, które nie powodują błędu, tylko zmieniają wynik: kolejność wierszy przy remisach, zaokrąglenia, sposób liczenia różnicy dat, traktowanie NULL i pustego tekstu, wielkość liter w nazwach. Dlatego każdą konwersję sprawdziliśmy tak samo: zapytanie źródłowe uruchomione w jego własnej bazie, wersja od AI uruchomiona w PostgreSQL, obie na tych samych danych z 2025 roku, wyniki porównane wiersz po wierszu, łącznie z kolejnością.

Polecenie do AI w każdym przypadku zawierało trzy informacje, które decydują o jakości konwersji: wersję docelowej bazy, sposób zapisu nazw tabel w PostgreSQL (małe litery, bez cudzysłowów) i wymóg identycznego wyniku. Do tego prośba o listę zamienionych konstrukcji, która później ułatwia przegląd kodu.

Oracle do PostgreSQL: CONNECT BY, NVL, DECODE i ORDER SIBLINGS BY

Zapytanie hierarchiczne to najtrudniejszy przypadek przy przenoszeniu kodu z Oracle, bo CONNECT BY nie ma w PostgreSQL odpowiednika jeden do jednego. Nasze zapytanie buduje drzewo pracowników z wcięciami, ścieżką przełożonych, liczbą zamówień z grudnia i sortowaniem rodzeństwa po nazwisku:

SELECT LPAD(' ', 2 * (LEVEL - 1)) || e.FirstName || ' ' || e.LastName AS Pracownik,
       e.JobTitle AS Stanowisko,
       LEVEL AS Poziom,
       SYS_CONNECT_BY_PATH(e.LastName, '/') AS Sciezka,
       NVL((SELECT COUNT(*) FROM Orders o
             WHERE o.EmployeeID = e.EmployeeID
               AND o.OrderDate >= DATE '2025-12-01'
               AND o.OrderDate < DATE '2026-01-01'), 0) AS ZamowieniaGrudzien,
       DECODE(e.ManagerID, NULL, 'zarząd', 'zespół') AS Rola,
       TO_CHAR(e.HireDate, 'YYYY-MM') AS Zatrudniony
FROM Employees e
START WITH e.ManagerID IS NULL
CONNECT BY PRIOR e.EmployeeID = e.ManagerID
ORDER SIBLINGS BY e.LastName;

Przekonwertuj to zapytanie z Oracle Database na PostgreSQL 15. Tabele i kolumny w PostgreSQL mają te same nazwy, zapisane małymi literami i bez cudzysłowów (employees, orders). Wynik w PostgreSQL ma być identyczny, łącznie z kolejnością wierszy. Pod kodem wypisz każdą konstrukcję Oracle, którą zamieniłeś, i na co.

[zapytanie]

ChatGPT zamienia hierarchiczne zapytanie Oracle z CONNECT BY na rekurencyjne CTE w PostgreSQL z klauzulą SEARCH DEPTH FIRST BY
ChatGPT zamienia CONNECT BY na rekurencyjne CTE, a ORDER SIBLINGS BY na klauzulę SEARCH DEPTH FIRST BY lastname, która istnieje w PostgreSQL od wersji 14.

To rozwiązanie jest lepsze od tego, co zwykle widać w starszych przewodnikach, gdzie kolejność drzewa odtwarza się sortowaniem po sklejonej ścieżce tekstowej. Klauzula SEARCH DEPTH FIRST BY robi dokładnie to, co ORDER SIBLINGS BY w Oracle. AI dodało też uczciwe zastrzeżenie: gdy dwie osoby z tym samym przełożonym mają identyczne nazwisko, kolejność między nimi nie jest określona w żadnej z baz i dla pewności warto dodać drugi klucz sortowania.

Wersja dla PostgreSQL od ChatGPT do skopiowania, bez zmian, dokładnie ta, którą uruchomiliśmy:

WITH RECURSIVE hierarchia (
    employeeid,
    firstname,
    lastname,
    jobtitle,
    managerid,
    hiredate,
    poziom,
    sciezka
) AS (
    -- START WITH e.ManagerID IS NULL
    SELECT
        e.employeeid,
        e.firstname,
        e.lastname,
        e.jobtitle,
        e.managerid,
        e.hiredate,
        1 AS poziom,
        '/' || e.lastname AS sciezka
    FROM employees e
    WHERE e.managerid IS NULL

    UNION ALL

    -- CONNECT BY PRIOR e.EmployeeID = e.ManagerID
    SELECT
        e.employeeid,
        e.firstname,
        e.lastname,
        e.jobtitle,
        e.managerid,
        e.hiredate,
        h.poziom + 1,
        h.sciezka || '/' || e.lastname
    FROM employees e
    JOIN hierarchia h
      ON h.employeeid = e.managerid
)
SEARCH DEPTH FIRST BY lastname SET kolejnosc
SELECT
    LPAD(' ', 2 * (poziom - 1)) || firstname || ' ' || lastname AS pracownik,
    jobtitle AS stanowisko,
    poziom,
    sciezka,
    COALESCE(
        (
            SELECT COUNT(*)
            FROM orders o
            WHERE o.employeeid = hierarchia.employeeid
              AND o.orderdate >= DATE '2025-12-01'
              AND o.orderdate <  DATE '2026-01-01'
        ),
        0
    ) AS zamowieniagrudzien,
    CASE
        WHEN managerid IS NULL THEN 'zarząd'
        ELSE 'zespół'
    END AS rola,
    TO_CHAR(hiredate, 'YYYY-MM') AS zatrudniony
FROM hierarchia
ORDER BY kolejnosc;
Wynik zapytania hierarchicznego w Oracle SQL*Plus i wersji od AI w PostgreSQL psql: to samo drzewo pracowników z wcięciami i ścieżkami
Oracle 26ai Free (SQL*Plus) i PostgreSQL 15 (psql), pierwsze wiersze wyniku. Oba zapytania zwróciły po 48 wierszy, identycznych łącznie z kolejnością; suma zamówień z grudnia w obu bazach to 23 703.

SQL Server do PostgreSQL: TOP, CROSS APPLY, FORMAT, DATEDIFF i IIF

Zapytanie w T-SQL wybiera dziesięciu najaktywniejszych klientów indywidualnych 2025 roku z datą ostatniego zamówienia, liczbą dni aktywności i statusem ostatniego zamówienia pobranym przez CROSS APPLY:

SELECT TOP (10)
       c.CustomerID,
       c.FirstName + N' ' + c.LastName AS Klient,
       ISNULL(c.Country, 'PL') AS Kraj,
       COUNT(*) AS Zamowienia,
       FORMAT(MAX(o.OrderDate), 'yyyy-MM-dd') AS OstatnieZamowienie,
       DATEDIFF(DAY, MIN(o.OrderDate), MAX(o.OrderDate)) AS DniAktywnosci,
       IIF(COUNT(*) >= 20, N'stały', N'okazjonalny') AS Typ,
       ls.LastStatus
FROM dbo.Customers AS c
JOIN dbo.Orders AS o ON o.CustomerID = c.CustomerID
CROSS APPLY (SELECT TOP (1) o2.Status AS LastStatus
             FROM dbo.Orders AS o2
             WHERE o2.CustomerID = c.CustomerID
               AND o2.OrderDate >= '20250101' AND o2.OrderDate < '20260101'
             ORDER BY o2.OrderDate DESC) AS ls
WHERE o.OrderDate >= '20250101' AND o.OrderDate < '20260101'
  AND c.Segment = 'B2C'
GROUP BY c.CustomerID, c.FirstName, c.LastName, c.Country, ls.LastStatus
ORDER BY Zamowienia DESC, c.CustomerID;
ChatGPT konwertuje zapytanie T-SQL na PostgreSQL: CROSS APPLY na CROSS JOIN LATERAL, TOP na LIMIT, FORMAT na TO_CHAR, DATEDIFF na odejmowanie dat
Wersja dla PostgreSQL: CROSS JOIN LATERAL zamiast CROSS APPLY, LIMIT zamiast TOP, TO_CHAR zamiast FORMAT, CASE zamiast IIF i odejmowanie dat rzutowanych na date zamiast DATEDIFF.

Dwa szczegóły z tej odpowiedzi warto zapamiętać. Pierwszy to DATEDIFF(DAY, ...): SQL Server liczy w nim przekroczone granice dni, a nie pełne doby, więc odpowiednikiem nie jest różnica znaczników czasu, tylko różnica dat po rzutowaniu na date, i dokładnie tak AI to zapisało. Drugi to aliasy kolumn w cudzysłowach (AS "Klient"): bez nich PostgreSQL zwróciłby nagłówki małymi literami, co przy aplikacji czytającej kolumny po nazwie może mieć znaczenie.

Wersja dla PostgreSQL od ChatGPT do skopiowania, bez zmian, dokładnie ta, którą uruchomiliśmy:

SELECT
       c.customerid AS "CustomerID",
       c.firstname || ' ' || c.lastname AS "Klient",
       COALESCE(c.country, 'PL') AS "Kraj",
       COUNT(*) AS "Zamowienia",
       TO_CHAR(MAX(o.orderdate), 'YYYY-MM-DD') AS "OstatnieZamowienie",
       (MAX(o.orderdate)::date - MIN(o.orderdate)::date) AS "DniAktywnosci",
       CASE
           WHEN COUNT(*) >= 20 THEN 'stały'
           ELSE 'okazjonalny'
       END AS "Typ",
       ls.laststatus AS "LastStatus"
FROM customers AS c
JOIN orders AS o
  ON o.customerid = c.customerid
CROSS JOIN LATERAL (
    SELECT o2.status AS laststatus
    FROM orders AS o2
    WHERE o2.customerid = c.customerid
      AND o2.orderdate >= TIMESTAMP '2025-01-01 00:00:00'
      AND o2.orderdate <  TIMESTAMP '2026-01-01 00:00:00'
    ORDER BY o2.orderdate DESC
    LIMIT 1
) AS ls
WHERE o.orderdate >= TIMESTAMP '2025-01-01 00:00:00'
  AND o.orderdate <  TIMESTAMP '2026-01-01 00:00:00'
  AND c.segment = 'B2C'
GROUP BY
       c.customerid,
       c.firstname,
       c.lastname,
       c.country,
       ls.laststatus
ORDER BY "Zamowienia" DESC, c.customerid
LIMIT 10;
Wynik zapytania T-SQL w sqlcmd i jego wersji od AI w PostgreSQL: ci sami klienci, liczby zamówień, daty i statusy
SQL Server (sqlcmd) i PostgreSQL (psql): ci sami klienci, te same liczby zamówień, daty i statusy. Wyniki identyczne łącznie z kolejnością.

MySQL do PostgreSQL: GROUP_CONCAT, IFNULL, DATE_FORMAT i LIMIT z przesunięciem

SELECT p.CategoryID,
       COUNT(DISTINCT p.ProductID) AS Produkty,
       GROUP_CONCAT(DISTINCT o.Channel ORDER BY o.Channel SEPARATOR ', ') AS Kanaly,
       IFNULL(ROUND(SUM(oi.Quantity * oi.UnitPrice * (100 - oi.DiscountPct) / 100), 2), 0) AS Sprzedaz,
       DATE_FORMAT(MAX(o.OrderDate), '%Y-%m-%d') AS OstatnieZamowienie
FROM `Products` p
JOIN `OrderItems` oi ON oi.ProductID = p.ProductID
JOIN `Orders` o ON o.OrderID = oi.OrderID
WHERE p.CategoryID IN (53, 54)
  AND o.Status <> 'CANCELLED'
GROUP BY p.CategoryID
ORDER BY Sprzedaz DESC
LIMIT 0, 5;
ChatGPT konwertuje zapytanie MySQL na PostgreSQL: GROUP_CONCAT na STRING_AGG, IFNULL na COALESCE, DATE_FORMAT na TO_CHAR, LIMIT 0, 5 na LIMIT 5 OFFSET 0
Zamiany MySQL: GROUP_CONCAT z SEPARATOR na STRING_AGG z ORDER BY, IFNULL na COALESCE, DATE_FORMAT na TO_CHAR, backticki usunięte, LIMIT 0, 5 na LIMIT 5 OFFSET 0.

Wersja dla PostgreSQL od ChatGPT do skopiowania, bez zmian, dokładnie ta, którą uruchomiliśmy:

SELECT p.categoryid,
       COUNT(DISTINCT p.productid) AS produkty,
       STRING_AGG(DISTINCT o.channel, ', ' ORDER BY o.channel) AS kanaly,
       COALESCE(
           ROUND(SUM(oi.quantity * oi.unitprice * (100 - oi.discountpct) / 100), 2),
           0
       ) AS sprzedaz,
       TO_CHAR(MAX(o.orderdate), 'YYYY-MM-DD') AS ostatniezamowienie
FROM products p
JOIN orderitems oi ON oi.productid = p.productid
JOIN orders o ON o.orderid = oi.orderid
WHERE p.categoryid IN (53, 54)
  AND o.status <> 'CANCELLED'
GROUP BY p.categoryid
ORDER BY sprzedaz DESC
LIMIT 5 OFFSET 0;
Wynik zapytania MySQL w kliencie mysql i jego wersji od AI w PostgreSQL psql: dwie kategorie z tą samą liczbą produktów, kanałami i sprzedażą
MySQL 8.0 i PostgreSQL 15: te same dwie kategorie, liczby produktów, listy kanałów i sprzedaż co do grosza. Różnią się tylko nagłówki: AI zapisało aliasy małymi literami, czego tu nie wymagaliśmy.

Na co uważać przy konwersji z AI

ObszarPułapkaJak sprawdzić
Wielkość liter w nazwachPostgreSQL zamienia nazwy bez cudzysłowów na małe litery; tabele utworzone jako "Orders" wymagają cudzysłowów zawszePodaj AI, jak nazwano tabele w bazie docelowej
Kolejność wierszyRemisy w ORDER BY rozstrzygane różnie w różnych silnikachPorównanie wyników z kolejnością, dodatkowy klucz sortowania
Daty i czasDATEDIFF liczy granice, odejmowanie znaczników czasu liczy doby; różne domyślne formaty i strefyPrzypadki na granicach dni i miesięcy
NULL i pusty tekstOracle traktuje '' jak NULL, PostgreSQL i SQL Server nieDane testowe z pustymi tekstami
Typy liczboweDzielenie całkowite i różna precyzja wyników dzieleniaSumy kontrolne na wynikach liczbowych
Sortowanie tekstuRóżne collation dają różną kolejność polskich znakówPorównanie kolejności dla nazw z ogonkami

Wszystkie trzy konwersje dały wynik identyczny ze źródłem. To dobry wynik, ale nie powód, żeby rezygnować z porównania. Te zapytania liczyły się na danych bez remisów i bez pustych tekstów, a pułapki z tabeli wychodzą właśnie na takich przypadkach. Do ich wyszukania przydają się testy z części o testach SQL z AI.

✕Powiększony zrzut ekranu z przewodnika AI w SQL
Szkolenie Język SQL ze wsparciem AI

Szkolenie Język SQL ze wsparciem AI

Najbliższy termin gwarantowany: 28.10.2026

Sprawdź terminy

Najczęściej zadawane pytania

Jak bezpiecznie refaktoryzować stare zapytania SQL z AI?
Najpierw zapisz wynik starej wersji, potem poproś AI o przepisanie bez zmiany logiki i o opisanie podejrzanych miejsc. Równoważność sprawdź operatorem EXCEPT w obie strony, liczbą wierszy i sumą kontrolną CHECKSUM_AGG.
Czy AI potrafi przekonwertować zapytanie z Oracle do PostgreSQL?
Tak, zna mapowania funkcji i składni, na przykład CONNECT BY na rekurencyjne CTE, NVL na COALESCE i DECODE na CASE. Ryzyko leży w szczegółach, które nie powodują błędu, tylko zmieniają wynik, więc wynik porównuje się w obu bazach.
Na co uważać przy konwersji SQL między dialektami?
Na różnice w sortowaniu tekstu i wartości NULL, typach dat, dzieleniu liczb całkowitych, wielkości liter w nazwach i funkcjach zaokrąglania. Każdą konwersję uruchom w bazie źródłowej i docelowej i porównaj wyniki wiersz po wierszu.
Dlaczego refaktoryzacja i naprawa błędów to dwie osobne zmiany?
Bo po połączeniu ich w jednym kroku nie da się udowodnić, że wynik się nie zmienił. Najpierw refaktoryzacja z dowodem równoważności, a dopiero potem osobną zmianą poprawka logiki zatwierdzona przez właściciela raportu.

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...