Перейти до вмісту

ABAP SQL

ABAP SQL — підмножина SQL, вбудована в ABAP і незалежна від СКБД. Одна й та сама команда працює на HANA, Oracle, DB2. Ядро перекладає ABAP SQL у Native SQL конкретної бази і автоматично обробляє client handling, буферизацію, access control.

Ця сторінка — швидкий лук-ап основного синтаксису. Повний перелік нюансів — ABAP Keyword Documentation.

" Окремі поля → внутрішня таблиця
SELECT carrid, connid, fltime
FROM zdemo_abap_flsch
WHERE carrid = 'LH'
INTO TABLE @DATA(flights).
" Усі поля → структура (перший рядок)
SELECT SINGLE *
FROM zdemo_abap_carr
WHERE carrid = 'LH'
INTO @DATA(carrier).
" Агрегація
SELECT carrid, COUNT(*) AS cnt, SUM( fltime ) AS total
FROM zdemo_abap_flsch
GROUP BY carrid
INTO TABLE @DATA(stats).
ФормаЩо робить
INTO TABLE @itabПовна заміна внутрішньої таблиці
APPENDING TABLE @itabДодає до наявної
INTO @struct (+SINGLE)Один рядок
INTO (@v1, @v2, ...)Окремі поля у окремі змінні
INTO CORRESPONDING FIELDS OF TABLE @itabМапить по іменах (не всі поля SELECT мають бути у цілі)
INTO NEW @DATA(ref) / INTO TABLE NEW @DATA(ref)Створює анонімний data object, повертає data reference
PACKAGE SIZE nЧитання батчами — відкриває цикл, у тілі обробляється чергова порція

Inline-оголошення: INTO TABLE @DATA(result) — тип виводиться з SELECT-list.

" PACKAGE SIZE — батчева обробка великих наборів
SELECT carrid, connid FROM zdemo_abap_flsch
INTO TABLE @DATA(batch) PACKAGE SIZE 100.
" тіло циклу: обробляємо batch
ENDSELECT.
SELECT carrid, connid, fltime
FROM zdemo_abap_flsch
WHERE carrid IN ('LH', 'AA')
AND fltime > 200
GROUP BY carrid, connid, fltime " якщо є аґреґати — усі неаґреґовані обовʼязкові
HAVING SUM( fltime ) > 1000 " фільтр після GROUP BY
ORDER BY carrid, fltime DESCENDING
INTO TABLE @DATA(res)
UP TO 50 ROWS. " обмеження кількості

UP TO n ROWS і OFFSET n — для пагінації (працюють у парі з ORDER BY). FOR ALL ENTRIES IN @itab — альтернатива IN для великих списків, але з нюансами дедуплікації.

SELECT f.carrid, f.connid, c.carrname, p.price
FROM zdemo_abap_flsch AS f
INNER JOIN zdemo_abap_carr AS c ON c.carrid = f.carrid
LEFT OUTER JOIN zdemo_abap_fli AS p
ON p.carrid = f.carrid AND p.connid = f.connid
INTO TABLE @DATA(joined).

Підтримуються INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN. Для CDS view entity з асоціаціями — path expressions (\_carr-carrname), див. CDS View Entities.

SELECT carrid FROM zdemo_abap_carr
UNION
SELECT carrid FROM zdemo_abap_flsch
INTO TABLE @DATA(all_carriers).

UNION — обʼєднання без дублікатів, UNION ALL — з дублікатами, INTERSECT — перетин, EXCEPT — різниця.

WITH дозволяє оголосити іменовані допоміжні запити:

WITH
+heavy_flights AS ( SELECT carrid, connid FROM zdemo_abap_flsch
WHERE fltime > 500 ),
+result AS ( SELECT c.carrid, c.carrname
FROM zdemo_abap_carr AS c
INNER JOIN +heavy_flights AS h ON h.carrid = c.carrid )
SELECT * FROM +result INTO TABLE @DATA(out).

Імена CTE починаються з +. Можна явно перелічити колонки: +heavy_flights( c, cn ) AS ( SELECT carrid, connid FROM ... ). У парі з PACKAGE SIZE цикл закривається ENDWITH. замість ENDSELECT.. Для ієрархій — WITH HIERARCHY, див. Ієрархії.

У SELECT-list можна рахувати на стороні бази:

SELECT carrid,
seatsocc + seatsmax AS total,
seatsocc / seatsmax * 100 AS rate,
CASE WHEN fltime > 300 THEN 'LONG' ELSE 'SHORT' END AS category,
COALESCE( cityto, 'N/A' ) AS city_to,
CAST( fltime AS DEC( 8, 2 ) ) AS fltime_dec
FROM zdemo_abap_flsch
INTO TABLE @DATA(res).

Арифметика: +, -, *, /; CAST; CASE (simple і complex); COALESCE, NULLIF.

Вбудовані функції:

  • Рядкові: CONCAT, CONCAT_WITH_SPACE, INITCAP, UPPER, LOWER, LEFT, RIGHT, SUBSTRING, LENGTH, LPAD, RPAD, LTRIM, RTRIM, REPLACE, INSTR, LOCATE.
  • Regex: LIKE_REGEXPR, LOCATE_REGEXPR, OCCURRENCES_REGEXPR, REPLACE_REGEXPR, SUBSTRING_REGEXPR.
  • Числові: ABS, CEIL, FLOOR, ROUND, DIV, DIVISION, MOD.
  • Дата/час: ADD_DAYS, ADD_MONTHS, IS_VALID.
  • Конвертація: CURRENCY_CONVERSION, UNIT_CONVERSION, BINTOHEX, HEXTOBIN, TO_BLOB, TO_CLOB.
  • Aggregate / спец: COUNT, SUM, AVG, MIN, MAX, STRING_AGG, UUID.
SELECT carrid,
char`X` AS flag,
int4`42` AS magic,
numc`007` AS code
FROM zdemo_abap_carr
WHERE carrid = char`LH`
INTO TABLE @DATA(res).

Формат: typenamevalue“. Типовані літерали — рекомендовані замість нетипованих ('X', 42), бо їх тип перевіряється на етапі активації.

" Вставка з однієї структури / таблиці
INSERT INTO zdemo_abap_tab VALUES @new_row.
INSERT zdemo_abap_tab FROM TABLE @new_rows.
" ACCEPTING DUPLICATE KEYS — не падати на дублях, а пропускати
INSERT zdemo_abap_tab FROM TABLE @new_rows ACCEPTING DUPLICATE KEYS.
" Вставка результату SELECT (subquery)
INSERT zdemo_abap_tab FROM ( SELECT * FROM other_tab WHERE carrid = 'LH' ).
" Оновлення за WHERE
UPDATE zdemo_abap_tab SET field1 = 'X' WHERE carrid = 'LH'.
" Точкове — через структуру (оновлює усі не-ключові поля)
UPDATE zdemo_abap_tab FROM @row.
" MODIFY — UPSERT (INSERT якщо немає, UPDATE якщо є)
MODIFY zdemo_abap_tab FROM TABLE @rows.
" Видалення
DELETE FROM zdemo_abap_tab WHERE carrid = 'AA'.
DELETE zdemo_abap_tab FROM TABLE @to_delete.

Результат — у sy-subrc (0 — успіх, 4 — нічого не змінилось). Кількість рядків — у sy-dbcnt.

MERGE — upsert на основі іншого джерела

Section titled “MERGE — upsert на основі іншого джерела”

MERGE модифікує таблицю, звіряючи її з іншим джерелом даних (таблицею, CDS view, підзапитом). Для кожного рядка джерела — якщо збіг за ключем знайдено, робиться UPDATE; якщо ні — INSERT.

MERGE zdemo_abap_target
USING @source_table AS s
ON zdemo_abap_target~carrid = s~carrid
WHEN MATCHED THEN
UPDATE SET carrname = s~carrname
WHEN NOT MATCHED THEN
INSERT ( carrid, carrname ) VALUES ( s~carrid, s~carrname ).

Відрізняється від ABAP-ного MODIFY FROM TABLE @rows тим, що джерело — SQL-запит або host-таблиця, а логіка upsert — декларативна через WHEN MATCHED / WHEN NOT MATCHED.

Імена таблиць/полів/умови як рядки чи таблиці рядків:

DATA(tabname) = 'ZDEMO_ABAP_CARR'.
DATA(fieldlist) = VALUE string_table( ( `carrid` ) ( `carrname` ) ).
DATA(where_cond) = |carrid = 'LH'|.
SELECT (fieldlist) FROM (tabname)
WHERE (where_cond)
INTO TABLE @DATA(res).

Коли треба селект за списком, що сидить у internal table:

IF carriers IS NOT INITIAL.
SELECT carrid, connid FROM zdemo_abap_flsch
FOR ALL ENTRIES IN @carriers
WHERE carrid = @carriers-carrid
INTO TABLE @DATA(res).
ENDIF.

Альтернатива у modern ABAP — використовувати internal table безпосередньо як джерело даних у WHERE / JOIN (наприклад, WHERE fld IN @itab).

Адаптовано з 03_ABAP_SQL.md (Apache 2.0). Повний перелік нюансів — в оригіналі.