Using FOR ALL ENTRIES for validation multiple lines - validation

I have a question concerning the For all Entries statement in ABAP.
I know that it functions like a Select Distinct and deletes duplicate entries.
In my case, I want to write a validation for table inputs. As you can enter more than one line, I have to check every single one of them.
Loop with Select is not an Option. The alternative is For all Entries. Sadly if f.e. the same company code needs to be validated, FoE just gives back one entry. So I have no chance to identify where the error was (if there is one).
Here is the Code for the validation:
LOOP AT extract.
IF <xact> NE empty.
READ TABLE total WITH KEY <vim_xextract_key>.
IF sy-subcs EQ 0.
MOVE <vim_total_struc> TO ls_y.
APPEND ls_y TO lt_y.
ENDIF.
ENDIF.
ENDLOOP.
SELECT bukrs
FROM t001
FOR ALL ENTRIES IN #lt_y
WHERE bukrs = #lt_y-bukrs
INTO TABLE #DATA(lt_check_bukrs).
IF lt_check_bukrs IS INITIAL.
MESSAGE 'Error in company code' TYPE 'S' DISPLAY LIKE 'E'.
vim_abort_saving = abap_true.
ENDIF.
Maybe one of you has an approach or an idea.
Thank you for all answers!

Considering that the company code table should not be too long (in any sanely configured system), I would load it into the application server and do the comparison on the ABAP layer instead of the database layer.
SELECT bukrs
FROM t001
INTO TABLE #DATA(lt_all_bukrs).
LOOP AT lt_check_bukrs REFERENCE INTO DATA #(lr_check_bukrs).
IF NOT line_exists( lt_all_bukrs[ lr_check_burks->bukrs ] )
MESSAGE |Document { lv_check_bukrs->belnr } has invalid company code { lr_check_burks->bukrs }| TYPE 'S' DISPLAY LIKE 'E'.
ENDIF.
ENLOOP.
In a different case where this is not viable because the table you want to compare with is so large it would cause a TSV_TNEW_PAGE_ALLOC_FAILED, then I would go back to where you acquired the original data and perform an OUTER JOIN with the comparison table:
SELECT bkpf~opbel,
bkpf~bukrs
FROM bseg
LEFT OUTER JOIN t001 ON bkpf-burks = t001~bukrs
INTO TABLE
WHERE t001~bukrs IS NULL.
The result table should be all financial document numbers with invalid company codes.
Should this also be impossible because the source data doesn't come from the database (manual entry, read from a file, received from a webservice, whatever...) then the last option would be to pass that data to an ABAP-Managed Database Procedure. Because SQLScript can do JOINs between database tables and tables in memory. But that does require that you are using a SAP HANA database.

Related

How to make a dynamic select based on a result set from previous step on Pentaho Kettle?

I want to execute a select statement based on a result set from a previous step, something like this:
select column from table where column in (previous step);
Basically this step (filter rows) will split a group of ids based on a condition. I want to make a select with those who tested false but i don't know how to select only those. The table in question, which I want to select, it's very big and it is very expensive to select all records and join with the result set, so I wish to select just the group that I need, is this even possible ?
https://i.stack.imgur.com/Xu1qt.png
Ok, let me try to be more specific.
Basically I Have 3 steps as my print shows.
First step is a table input, which I select from a table.
Second step is a database lookup, which I look on other table to get some fields that I want.
And third step it's a filter rows, where I kinda make a if else statement.
After my third step (filter rows) I have 2 streams: True or False.
Each stream returns me a group of ids and other fields too but it's not that important here, I guess.
I want to make a select statement based on those ids returned from previous step (Filter rows 3° step).
Basically the behaviour that I want its similar to this query:
select *
from table
where id in ("previous step");
Where table will always be the same table, so I don't think this will be a problem or something.
And "previous step" means all ids returned after the 3° step (filter rows).
What i am doing right now is: I have another table input on the other side which I make a merge join with this result set(from 3° step). But I have to make a select of the entire table and then, join with my result set, what is very expensive, and I'm wondering if i can get the same result, but with more performance.
I don't know if I am being clear enough, but I apologize right now because english it's not my main language, but I hope you guys can understand me now, thanks.
You can use three steps to achive this.
First, use a Memory group by step to group ids as a field.The aggregate tyoe should beConcatenate strings separated by ,
Second,use a User defined java expression step to generate a new field contains the SQL we need.The expression may like"SELECT id,created FROM test WHERE order_id IN ("+ ids +")" and ids is the group result from last step.
At last,we can use a Dynamic SQL row step to look up datas by the specified SQL.

How to recreate SAP queries in Oracle?

I need to recreate some SAP stored procedures in Oracle. I've been trying to find tutorials, similar questions, examples, etc about this but apparently no one had to do this before
What Oracle SQL query can be similar to this SAP query ?
SELECT * FROM A
INTO CORRESPONDING FIELDS OF TABLE B
FOR ALL ENTRIES IN C
WHERE a = C-a
AND x = y.
LOOP AT B INTO D.
D-b = E-b.
INSERT c FROM D.
IF SY-SUBRC <> 0.
WRITE: / 'error on insert', D-b, D-a.
ENDIF.
Any help will be appreciated, Thanks.
I recommend you to use transaction 'ST05' to trace your program. This tool will show details of the queries on the database including the exact SQL executed.
EDIT:
As a demonstration of the queries generated by SAP for Oracle let's execute this code and trace it with transaction 'ST05'. Remember to run 'ST05' before executing the program.
tables: mara.
data: it_mara type standard table of mara,
it_eina type standard table of eina.
select-options so_matnr for mara-matnr.
start-of-selection.
select matnr from mara into corresponding fields of table it_mara
up to 100 rows where matnr in so_matnr.
check sy-subrc eq 0.
select * from eina into table it_eina for all entries in it_mara
where matnr eq it_mara-matnr.
After execution check the output in transaction 'ST05':
If you want more details select an SQL statement in the screen and then click the button 'Explain'. You will see the following:
For better reference on transaction 'ST05' check this link.
Hope it helps.
The FOR ALL ENTRIES statement usually produces many queries which results are then grouped by UNION or UNION ALL.
Here is a really nice analysis for Microsoft SQL Server.
Because of the fact that UNION and UNION ALL are part of SQL standard I think it is implemented exactly the same for any other SQL database.
[EDIT]
As Mr Miranda stated it looks differently when it comes to Oracle database. I googled a bit and found this article where it is said that IN-LISTs are used which seems also to be plausible.

How to see Table detail when writing query?

How to see Table detail when writing query?
Hi, i am new to using Embarcadero DBArtisan for Oracle and Syabase queries executions.
but i am unable to see the tables and fields information when i write queries.
Forexample:
Databasname.User.Table.Fields
Suppose if i write first Database name and write .(dot) it should show me all users and when i pick one user and write .(dot) agian it should show me all tables inside and when i pick one table and write .(dot) it should show me all the fields inside.
But it is not doing that way. every time i have to describe table to find the specific field in the table.
I am woundering if i have to choose some option to see this information.
Thank you very much for your help.
Sybase, there is no User.
I think you have to write a cursor to loop over the DBs on a server.
For the rest of your question:
select db_name() 'databasename', b.name 'table', a.name 'fields'
from syscolumns a, sysobjects b
where a.id = b.id
-- and b.type = 'U' -- User tables only
It seems that there is a setting in Code Workbench. Please see page 733 in the DBArtisan User Guide.
From the Manual,
In the ISQL Window, when Enable Auto Replacement is selected on the Setting Tab,
the application uses "dot completion" auto population to display the list of columns
for the target table.

Process SQL result set entirely

I need to work with a SQL result set in order to do some processing for each column (medians, standard deviations, several control statements included)
The SQL is dynamic so I don't know the number of columns, rows.
First I tried to use temporary tables, views, etc to store the results, however I did not manage to overcome the 30 character limit of Oracle columns when using the below sql:
create table (or view or global temporary table) as select * from (
SELECT
DMTTBF_MAT_MATURATO_BILL_POS.MAT_V_COD_ANNOMESE,
SUM(DMTTBF_MAT_MATURATO_BILL_POS.MAT_N_NUM_EVENTI_CHZ +DMTTBF_MAT_MATURATO_BILL_POS. MAT_N_NUM_EVENTI) <-- exceeds the 30 character limit
FROM DMTTBF_MAT_MATURATO_BILL_POS
WHERE DMTTBF_MAT_MATURATO_BILL_POS.MAT_V_COD_ANNOMESE >= '201301'
GROUP BY DMTTBF_MAT_MATURATO_BILL_POS.MAT_V_COD_ANNOMESE
)
Second choice was to use some PL/SQL types to store the entire table information, so I could call it like in other programming languages (e.g. a matrix result[i][j]) but I could not find anything similar.
Third variant, using files for reading and writing: i did not try it yet; i'm still expecting a more elegant pl/sql solution
It's possible that I have the wrong approach here so any advice is more than welcome.
UPDATE: Modifying the input SQL is not an option. The program has to accept any select statement.
Note that you can alias both tables and fields. Using a table alias keeps references to it from producing walls of text in the query. Using one for a field gives it a new name in the output.
SELECT A.LONG_FIELD_NAME_HERE AS SHORTNAME
FROM REALLY_LONG_TABLE_NAME_HERE A
The auto naming adds _1 and _2 etc to differentiate the same column name coming from different table references. This often puts a field already borderline over the limit. Giving the fields names yourself bypasses this.
You can put the alias also in dynamic SQL:
sqlstr := 'create table (or view or global temporary table) as select * from (
SELECT
DMTTBF_MAT_MATURATO_BILL_POS.MAT_V_COD_ANNOMESE,
SUM(DMTTBF_MAT_MATURATO_BILL_POS.MAT_N_NUM_EVENTI_CHZ + DMTTBF_MAT_MATURATO_BILL_POS.MAT_N_NUM_EVENTI) AS '||SUBSTR('SUM(DMTTBF_MAT_MATURATO_BILL_POS.MAT_N_NUM_EVENTI_CHZ +DMTTBF_MAT_MATURATO_BILL_POS.MAT_N_NUM_EVENTI)', 1, 30)
||' FROM DMTTBF_MAT_MATURATO_BILL_POS
WHERE DMTTBF_MAT_MATURATO_BILL_POS.MAT_V_COD_ANNOMESE >= ''201301''
GROUP BY DMTTBF_MAT_MATURATO_BILL_POS.MAT_V_COD_ANNOMESE
)'

inline view query

I wanted to delete some records which i added recently, from this table mytemp, please tell me what is wrong with this query,
data in selected column had been populated using cursor
DELETE FROM (SELECT ROWNUM RM, S from mytemp) where rm > 20;
error is:
ORA-01732: data manipulation operation not legal on this view
Edited for accuracy...
Here's the description of the error you are getting:
http://ora-01732.ora-code.com/
An attempt was made to use an UPDATE, INSERT, or DELETE statement on a
view that contains expressions or functions or was derived from more
than one table. If a join operation was used to create the view or the
view contains virtual columns derived from functions or expressions,
then the view may only be queried.
So it looks like an updateable view can be substituted for a table, as long as it doesn't join more than one table or use virtual columns. In your case, the problem is the virtual ROWNUM column.
It's the rownum>20 statement.
ROWNUM>x, where x values greater than a positive integer are always false.
select * from ANYTABLE where rownum>(ANY POSITIVE INTEGER)
doesn't return any record.
The first row fetched is assigned a ROWNUM of 1 and makes the condition false. The second row to be fetched is now the first row and is also assigned a ROWNUM of 1 and makes the condition false. All rows subsequently fail to satisfy the condition, so no rows are returned.
Check THIS for further info.
You can do the following:
delete from (select amount from TABLE t where t.amount=1000)
but it's the same as
delete from TABLE where amount=1000

Resources