Open SQL Part 4: SELECT SINGLE vs UP TO 1 ROWS
Read exactly one row the right way: SELECT SINGLE with the full key, UP TO 1 ROWS with ORDER BY for "the first/latest" row, existence checks, buffering effects and the ATC warnings you will see.
Explanation
📌 KEY POINTS
✅ SELECT SINGLE — use when you specify the complete primary key: one unique row.
✅ UP TO 1 ROWS with ORDER BY — use when several rows match and you want a defined one (latest, cheapest).
⚠️ SELECT SINGLE with an incomplete key returns an arbitrary matching row — not "the first".
💡 For an existence check select one small field (or a constant) — no need to read the whole row.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Parts 1–3 read sets of rows. Very often you need one row: the airline name, a customer, the latest booking.
━━━━━━━━━━━━━━━━━━━━
▶ 1. SELECT SINGLE
SELECT SINGLE carrname FROM scarr INTO lv_name WHERE carrid = p_carr.
- Complete primary key in WHERE → exactly one row or none.
- Uses the table buffer for buffered tables when the full key is specified.
- sy-subrc 0 found / 4 not found.
━━━━━━━━━━━━━━━━━━━━
▶ 2. INCOMPLETE KEY — THE PROBLEM
SELECT SINGLE * FROM sflight INTO gs_flight WHERE carrid = 'LH'.
Many rows match; the database returns any one of them. Code that assumes "the first flight" works by chance. Code inspector/ATC warns about SELECT SINGLE without full key.
━━━━━━━━━━━━━━━━━━━━
▶ 3. UP TO 1 ROWS + ORDER BY
SELECT fldate price FROM sflight INTO (lv_date, lv_price) UP TO 1 ROWS
WHERE carrid = 'LH' AND connid = '0400' ORDER BY fldate DESCENDING.
ENDSELECT.
(classic form needs ENDSELECT when INTO a work area; in strict syntax you can select INTO a work area with UP TO 1 ROWS without ENDSELECT in newer releases, or INTO TABLE and take the first row).
- Defined result: the latest flight.
━━━━━━━━━━━━━━━━━━━━
▶ 4. EXISTENCE CHECKS
- SELECT SINGLE @abap_true FROM sbook INTO @DATA(lv_exists) WHERE customid = @lv_cust. (7.40+)
- Classic: SELECT SINGLE customid FROM sbook INTO lv_cust WHERE customid = lv_cust. — select one small field.
- Or SELECT COUNT(*) … UP TO 1 ROWS.
━━━━━━━━━━━━━━━━━━━━
▶ 5. DON'T SELECT IN LOOPS
SELECT SINGLE inside a LOOP over thousands of rows means thousands of database round trips. Read all needed rows once (FOR ALL ENTRIES, JOIN) into a hashed table and READ TABLE in the loop — except for buffered tables, where SELECT SINGLE by full key is cheap.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
Run the code example: SELECT SINGLE by full key, the arbitrary row with an incomplete key, the latest flight via ORDER BY + UP TO 1 ROWS, and an existence check.
✅ CHECKPOINT: every single-row read in your code returns a defined row.
Code example
REPORT zosql_part4. DATA: gv_name TYPE s_carrname, gs_flight TYPE sflight, gv_date TYPE s_date, gv_price TYPE s_price, gv_carrid TYPE s_carr_id. PARAMETERS: p_carr TYPE s_carr_id DEFAULT 'LH', p_conn TYPE s_conn_id DEFAULT '0400'. START-OF-SELECTION.* ===== 1. SELECT SINGLE with the COMPLETE primary key ===== SELECT SINGLE carrname FROM scarr INTO gv_name WHERE carrid = p_carr. " SCARR key = MANDT + CARRID IF sy-subrc = 0. WRITE: / 'Airline:', gv_name. ENDIF. * ===== 2. WRONG: incomplete key -> arbitrary row ===== SELECT SINGLE * FROM sflight INTO gs_flight WHERE carrid = p_carr. " many flights match! WRITE: / 'SELECT SINGLE (incomplete key) returned some flight:', gs_flight-fldate. * ===== 3. RIGHT: defined row with ORDER BY + UP TO 1 ROWS ===== SELECT fldate price FROM sflight INTO (gv_date, gv_price) UP TO 1 ROWS WHERE carrid = p_carr AND connid = p_conn ORDER BY fldate DESCENDING. " latest flight ENDSELECT. IF sy-subrc = 0. WRITE: / 'Latest flight:', gv_date, gv_price. ENDIF. * ===== 4. Existence check: read as little as possible ===== SELECT SINGLE carrid FROM sbook INTO gv_carrid WHERE carrid = p_carr AND connid = p_conn. IF sy-subrc = 0. WRITE: / 'Connection has bookings'. ENDIF.* 💡 7.40+: SELECT SINGLE @abap_true FROM sbook WHERE ... INTO @DATA(lv_exists). * ===== AVOID: SELECT SINGLE inside a loop over many rows =====* LOOP AT gt_book INTO gs_book.* SELECT SINGLE name FROM scustom INTO lv_name WHERE id = gs_book-customid.* ENDLOOP.* -> read all customers once (FAE/JOIN) into a HASHED table, then READ TABLE.Real project scenario
A pricing program read "the current price" with SELECT SINGLE on a condition table using only material and customer, without the validity date. On one database the returned row happened to be the newest; after the HANA migration, a different (older) row came back, and invoices were priced wrongly for two days.
The fix used ORDER BY validity DESCENDING with UP TO 1 ROWS and a date condition, which returns a defined row on every database.
Common mistakes
- SELECT SINGLE with incomplete keys expecting "the first" row.
- Reading entire rows for existence checks.
- SELECT SINGLE inside loops on non-buffered tables.
- Forgetting ENDSELECT with UP TO 1 ROWS into a work area (classic).
- Not checking sy-subrc.
Best practices
- SELECT SINGLE only with the full primary key.
- UP TO 1 ROWS + ORDER BY for defined single rows.
- Minimal field lists for existence checks.
- Bulk reads + hashed tables instead of SELECT in loops.
- Check sy-subrc after every single read.
Interview angle
Questions: "SELECT SINGLE vs UP TO 1 ROWS?", "What happens with SELECT SINGLE and an incomplete key?", "How do you check existence efficiently?"
Strong answer: SELECT SINGLE is for reads with the complete primary key (unique row, buffer-capable); with incomplete keys any matching row is returned; UP TO 1 ROWS combined with ORDER BY returns a defined row such as the latest; existence checks select a minimal field or a constant; avoid SELECT SINGLE in loops except for buffered tables.
Practice this lesson
Quick check
1. Which statement returns the latest flight of a connection in a defined way?
2. When is SELECT SINGLE the right choice?
3. SELECT SINGLE without a fully-qualified key may return:
Interview questions
1. Explain the difference between SELECT SINGLE and SELECT ... UP TO 1 ROWS in Open SQL. When would you use each, and what are the performance and determinism implications?
Answer it in your own words first, then compare.
2. A program uses SELECT SINGLE by customer to find "the latest" order. What is wrong?
Answer it in your own words first, then compare.
Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.
More lessons in this topic
- Open SQL Part 1: How ABAP Reads the Database
- Open SQL Part 10: Open SQL in Real Reports and Interfaces
- Open SQL Part 2: SELECT Basics — Field Lists, WHERE and INTO
- Open SQL Part 3: FOR ALL ENTRIES — Correct Use
- Open SQL Part 5: JOINs — When to Use and When to Avoid
- Open SQL Part 6: Aggregates, GROUP BY and HAVING
- Open SQL Part 7: PACKAGE SIZE and Large Data Processing
- Open SQL Part 8: Performance Analysis with ST05, SAT and SQL Monitor