'Using SELECT TOP 1 in subquery in outer SELECT list (SAP ASE 16)
I have a query that works in Sybase SQL Anywhere 11 that I need to compile in SAP Adaptive Server Enterprise 16. The code doesn't want to compile in ASE though, stating that
SELECT TOP
is not allowed in a subquery.
Here's the query:
SELECT a.value,
Bcode = (SELECT TOP 1 b.code
FROM Btable b
WHERE b.value = a.value
AND b.deleted_flag = 'N'
ORDER BY b.start_date DESC, b.start_time DESC),
Bdesc = CASE
WHEN Bcode = 'a' THEN 'Alpha'
WHEN Bcode = 'b' THEN 'Beta'
WHEN Bcode = 'c' THEN 'Cappa'
WHEN Bcode = 'd' THEN 'Delta'
ELSE 'Epsilon'
END,
a.category,
a.status,
a.start_date,
a.start_time
FROM Atable a
WHERE a.deleted_flag = 'N'
AND a.start_date BETWEEN @a_datefrom AND @a_dateto
AND a.end_date IS NULL
ORDER BY a.start_date`
What can I do to get the same result? Would the data need to be selected into a temp table and then manipulated via a set of atomic statements? Thanks in advance for your time and effort.
Solution 1:[1]
There's a Native SQL feature in SAP which you can use to execute your statement, however it must be adapted according to the link.
If you want to use SAP SQL I would do something like the following:
FORM load using p_date1 type datum p_date2 type datum.
DATA: it_atable type standard table of ty_atable,
it_btable type standard table of ty_btable,
wa_btable like line of it_btable
wa_atable like line of it_atable,
lv_index type sy-tabix.
SELECT value
category
status
start_date
start_time
end_date " Include end_date to delete nulls later
FROM atable
INTO CORRESPONDING FIELDS OF TABLE it_atable
WHERE deleted_flag = 'N'
AND start_date between lv_date1 and lv_date2.
CHECK SY-SUBRC EQ 0. " No data? Do not continue.
SELECT value code " I wouldn't get the TOP n. Just take the data and order it
FROM btable
INTO CORRESPONDING FIELDS OF TABLE it_btable
FOR ALL ENTRIES IN it_atable
WHERE value = it_atable-value
deleted_flag = 'N'
ORDER BY start_date DESC start_time DESC.
LOOP AT it_atable INTO wa_atable.
lv_index = sy-tabix.
CHECK wa_atable-end_date is not initial.
* Get the first row
READ TABLE it_btable INTO wa_btable WITH KEY value = wa_atable.
IF SY-SUBRC IS INITIAL.
CASE wa_btable-code.
WHEN 'a'.
wa_atable-bdesc = 'Alpha'.
WHEN 'b'.
wa_atable-bdesc = 'Beta'.
WHEN 'c'.
wa_atable-bdesc = 'Cappa'.
WHEN 'd'.
wa_atable-bdesc = 'Delta'.
OTHERS
wa_atable-bdesc = 'Epsilon'.
ENDCASE.
wa_atable-bcode = wa_btable-code.
ENDIF.
MODIFY it_atable FROM wa_atable INDEX lv_index.
ENDLOOP.
DELETE it_atable WHERE end_date IS INITIAL. " Delete the null dates
ENDFORM.
I didn't test the code because I'm not connected to SAP right now.
Finally, there's no "TOP n" statement in SAP SQL. You must use "UP TO n ROWS". Check this link.
Hope it helps.
Solution 2:[2]
I think what you need is to use HAVING.
Bcode = (SELECT MIN(code)
FROM Btable
WHERE value = a.value
AND deleted_flag = 'N'
HAVING start_date = MIN(start_date)
AND start_time = MIN(start_time)
AND deleted_flag = 'N'
),
repeating the deleted_flag = 'N' test in the HAVING clause might not be necessary.
You probably need that MIN(code) because there might be more than one row in the correlated join to Btable for each row in Atable that fulfill the "has minimum date and time", and assuming they have different codes you must MIN() them.
I suspect this might still not work in that you have distinct date and time fields and the record with minimum date might not have the minimum time. I don't know what their types are but if they are a DATE and TIME, then I think you'll need to convert them to strings, concatenate, and convert back to DATETIME, all in a single expression, and run the HAVING condition on that. Otherwise change to using a DATETIME.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Nelson Miranda |
Solution 2 | Abe Crabtree |