Парсинг столбцов SQL SELECT

Вопрос или проблема

Я хотел бы разобрать каждый столбец из SQL:

SELECT
    promzag.skl_sifra_skl skl_sifra_skl, promstavke.art_sifra_art art_sifra_art, 
    SUM(decode(d.identifikacija, '17', decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)), 0)) pockol_sta,
    SUM(decode(d.identifikacija, '17', decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst), -decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst) ) ), 0) ) pocvrij_sta, 
    SUM(decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)) ) trenkol_sta, 
    SUM(decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst), -decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst)) ) ) trenvrij_sta, 
    stanje.cij_sta cij_sta, promzag.pgod_prz prz_pgod_prz, 
    stanje.napomena_sta napomena_sta, stanje.minzal_sta minzal_sta, 
    stanje.maxzal_sta maxzal_sta, stanje.trenikol_sta trenikol_sta, 
    stanje.trenicij_sta trenicij_sta, stanje.trenivrij_sta trenivrij_sta, 
    SUM(decode(d.ul_izl_dok, 'U', decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)), 0)) kolicina_ulaz, 
    abs(SUM(decode(d.ul_izl_dok, 'I', decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)), 0))) kolicina_izlaz, 
    SUM(decode(d.ul_izl_dok, 'U', decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', promstavke.vrijed_prst, -promstavke.vrijed_prst)), 0)) vrijed_ulaz, 
    abs(SUM(decode(d.ul_izl_dok, 'I', decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', promstavke.vrijed_prst, -promstavke.vrijed_prst)), 0))) vrijed_izlaz 
FROM tablex

где результат должен быть массивом, т.е.

    promzag.skl_sifra_skl skl_sifra_skl,
    promstavke.art_sifra_art art_sifra_art, 
    SUM(decode(d.identifikacija, '17', decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)), 0)) pockol_sta,
    SUM(decode(d.identifikacija, '17', decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst), -decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst) ) ), 0) ) pocvrij_sta, 
    SUM(decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)) ) trenkol_sta, 
    SUM(decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst), -decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst)) ) ) trenvrij_sta, 
    stanje.cij_sta cij_sta,
    promzag.pgod_prz prz_pgod_prz, 
    stanje.napomena_sta napomena_sta,
    stanje.minzal_sta minzal_sta, 
    stanje.maxzal_sta maxzal_sta,
    stanje.trenikol_sta trenikol_sta, 
    stanje.trenicij_sta trenicij_sta,
    stanje.trenivrij_sta trenivrij_sta, 
    SUM(decode(d.ul_izl_dok, 'U', decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)), 0)) kolicina_ulaz, 
    abs(SUM(decode(d.ul_izl_dok, 'I', decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)), 0))) kolicina_izlaz, 
    SUM(decode(d.ul_izl_dok, 'U', decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', promstavke.vrijed_prst, -promstavke.vrijed_prst)), 0)) vrijed_ulaz, 
    abs(SUM(decode(d.ul_izl_dok, 'I', decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', promstavke.vrijed_prst, -promstavke.vrijed_prst)), 0))) vrijed_izlaz 

Я пробовал Regexp::Common, но это не дало мне именно то, что нужно.

use warnings;
use strict;
use Data::Dumper;
use Regexp::Common;

my $sql = q(
SELECT
    promzag.skl_sifra_skl skl_sifra_skl, promstavke.art_sifra_art art_sifra_art, 
    SUM(decode(d.identifikacija, '17', decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)), 0)) pockol_sta,
    SUM(decode(d.identifikacija, '17', decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst), -decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst) ) ), 0) ) pocvrij_sta, 
    SUM(decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)) ) trenkol_sta, 
    SUM(decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst), -decode(skladista.vrsta_cijene, 'NAB', promstavke.faktcij_prst - NVL(promstavke.rabat_prst, 0) + NVL(promstavke.trosz_prst, 0) + NVL(promstavke.troso_prst, 0), 'PBP', promstavke.vrijed_prst - promstavke.porezi_prst, promstavke.vrijed_prst)) ) ) trenvrij_sta, 
    stanje.cij_sta cij_sta, promzag.pgod_prz prz_pgod_prz, 
    stanje.napomena_sta napomena_sta, stanje.minzal_sta minzal_sta, 
    stanje.maxzal_sta maxzal_sta, stanje.trenikol_sta trenikol_sta, 
    stanje.trenicij_sta trenicij_sta, stanje.trenivrij_sta trenivrij_sta, 
    SUM(decode(d.ul_izl_dok, 'U', decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)), 0)) kolicina_ulaz, 
    abs(SUM(decode(d.ul_izl_dok, 'I', decode(d.knjiz_dok, '3', 0, '1', 0, decode(d.zal_dok, '+', promstavke.kolic_prst, -promstavke.kolic_prst)), 0))) kolicina_izlaz, 
    SUM(decode(d.ul_izl_dok, 'U', decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', promstavke.vrijed_prst, -promstavke.vrijed_prst)), 0)) vrijed_ulaz, 
    abs(SUM(decode(d.ul_izl_dok, 'I', decode(d.knjiz_dok, '3', 0, '0', 0, decode(d.zal_dok, '+', promstavke.vrijed_prst, -promstavke.vrijed_prst)), 0))) vrijed_izlaz 
FROM promzag, promstavke, stanje, dokumenti d, skladista WHERE promzag.skl_sifra_skl = promstavke.prz_skl_sifra_skl AND promzag.dok_sifra_dok = promstavke.prz_dok_sifra_dok AND promzag.brdok_prz = promstavke.prz_brdok_prz AND promzag.pgod_prz = promstavke.prz_pgod_prz AND promstavke.prz_skl_sifra_skl = stanje.skl_sifra_skl AND promstavke.art_sifra_art = stanje.art_sifra_art AND promstavke.prz_pgod_prz = stanje.prz_pgod_prz AND promzag.dok_sifra_dok = d.sifra_dok AND promzag.skl_sifra_skl = skladista.sifra_skl GROUP BY promzag.skl_sifra_skl, promstavke.art_sifra_art, stanje.pockol_sta, stanje.pocvrij_sta, stanje.cij_sta, promzag.pgod_prz, stanje.napomena_sta, stanje.minzal_sta, stanje.maxzal_sta, stanje.trenikol_sta, stanje.trenicij_sta, stanje.trenivrij_sta
);

my @all_parts = split /$RE{balanced}{-parens=>'()'}/x, $sql;
for (@all_parts) {
    y|\n\r| |d;
    print "$_\n\n";
}

Ответ или решение

Анализ SQL-запроса: парсинг выбранных колонок

В современном программировании часто возникает необходимость эффективно анализировать SQL-запросы, особенно в сложных системах, где используются агрегатные функции и многоуровневые операции. В данной статье мы рассмотрим подход к парсингу столбцов из указанного SQL-запроса. Этот процесс включает в себя различные аспекты, от базовых SQL-принципов до использования регулярных выражений для автоматизации анализа.

Проблема и её содержание

У нас есть SQL-запрос, который выбирает столбцы из нескольких таблиц и включает в себя агрегации и сложные условия. Нам необходимо извлечь отдельные столбцы из этого запроса и представить их в массиве. SQL-запрос может выглядеть следующим образом:

SELECT
    promzag.skl_sifra_skl skl_sifra_skl, 
    promstavke.art_sifra_art art_sifra_art, 
    SUM(decode(d.identifikacija, '17', decode(d.knjiz_dok, '3', ...))) pockol_sta,
    ...
FROM tablex

Как видно, некоторые строки представляют собой агрегатные функции (SUM, COUNT и другие), а некоторые используются для выбора отдельных столбцов, таких как promzag.skl_sifra_skl.

Алгоритм парсинга

Для успешного выполнения задачи парсинга следует придерживаться структурированного подхода. Вот шаги, которые мы можем выполнить:

  1. Определение структуры запроса: Мы сосредоточимся на секции SELECT, игнорируя FROM и WHERE.

  2. Использование регулярных выражений: Это инструмент, который поможет выделить каждую отдельную колонку из запроса. Пример регулярного выражения для этого может выглядеть так:

    my $regex = qr/(?:\s*,\s*|^)\s*([^,]+?)\s+(\w+)\s*(?=,|$)/;

    Это выражение выделит все столбцы вместе с их алиасами.

  3. Выполнение парсинга и сбор результата: Мы проходим по строке с запросом и извлекаем все соответствия, сохраняя их в массив.

Пример кода на Perl

Ниже представлен пример кода на Perl, который выполняет описанные выше шаги:

use strict;
use warnings;

my $sql = q(
SELECT
    promzag.skl_sifra_skl skl_sifra_skl, 
    promstavke.art_sifra_art art_sifra_art, 
    SUM(decode(d.identifikacija, '17', ...)) pockol_sta,
    ...
FROM tablex
);

# Регулярное выражение для извлечения колонок
my @columns;

while ($sql =~ /(\s*,\s*|^)\s*([^,]+?)\s+(\w+)\s*(?=,|\s+FROM|$)/g) {
    push @columns, $2;  # Добавляем имя колонки в массив
}

# Вывод результатов
foreach my $column (@columns) {
    print "$column\n";
}

Разбор результата

Этот код извлечет все столбцы, определенные в секции SELECT, и сохранит их в массиве. В результате вы получите массив, содержащий:

  • promzag.skl_sifra_skl
  • promstavke.art_sifra_art
  • SUM(decode(d.identifikacija, '17', ...)) pockol_sta
  • и другие…

Заключение

Парсинг SQL-запросов является важной задачей в области обработки данных. Используя регулярные выражения и подходы, аналогичные приведенному выше, мы можем эффективно извлекать необходимые компоненты из запросов. Это открывает множество возможностей для анализа, модификации и оптимизации SQL-запросов в различных системах.

Регулярное применение подобных техник улучшает качество кода и облегчает сопровождение проектов, что делает вас более эффективным IT-специалистом.

Оцените материал
Добавить комментарий

Капча загружается...