AMDP selects false records contrary to OpenSQL - abap

I am learning AMDP and I found out that the result obtained from this is very different from normal select query in ABAP AS.
I am using below code in AMDP:
ex_gt_data = select a.vbeln,
a.kunnr,
a.bukrs_vf,
b.erdat,
b.lsmeng,
b.posnr,
b.matnr
from vbak as a
join vbap as b
on a.vbeln = b.vbeln;
followed by APPLY_FILTER function.
This query return multiple values in BUKRS_VF field. If I use normal select query like below:
SELECT a~vbeln,
a~bukrs_vf,
a~kunnr,
b~erdat,
b~lsmeng,
b~posnr,
b~matnr
FROM vbak AS a
JOIN vbap AS b
ON a~vbeln = b~vbeln
INTO TABLE #DATA(lt_vbak)
WHERE a~vbeln IN #s_vbeln.
it generates required result.
Can anybody tell me why this difference between AMDP and normal select query?

I just found out that adding
MANDT
field
solves the issue. i have added an pass by value parameter in method and used in query as
where a.mandt = im_mandt.
Dont know whether this is the correct solution.Please advise.

Many discrete useful pieces were given, but I am here to give a comprehensive answer to the question.
First of all, ABAP CDS views do not respect client data automatically like it is done in OpenSQL. BTW, the same is true for HANA CDS but judging on indirect indicators of your question it was about ABAP CDS based on HANA backend, rather that HANA CDS. Ya?
What is the proper way of client handling in ABAP CDS views?
#ClientHandling.type #CLIENT_DEPENDENT annotation must be added to view.
Default type is #INHERITED but for more straightforwardness it's better make it explicitly dependent.
#ClientHandling.algorithm is an optional field and can be omitted. There is a complex set of rules which determines how the client is calculated but in your case you can just don't specify it, implicit #AUTOMATED way will be used and client column will be implicitly added to ON conditions of your JOIN.
Client column must exist in view and should be either
selected via SELECT statement with either name or alias
have MANDT name manually set
if the latter is absent CLIENT column is used
if neither CLIENT nor MANDT column is not found the syntax error is thrown
No other actions needed, client is addressed implicitly like in OpenSQL case.
But! Here we are speaking about AMDP procedure, not simple CDS, so the things are more tricky.
The first and foremost, for all this to work a special CDS SESSION CLIENT CURRENT AMDP declaration is mandatory in a method signature:
AMDP OPTIONS READ-ONLY
CDS SESSION CLIENT CURRENT
the declaration makes implicit passing of $session.client var into the implementation of AMDP procedure. In the default CURRENT syntax variant it is equal to sy-mandt value of ABAP AS.
After that you can use $session.client explicitly with tables inside AMDP
SELECT * FROM vbak WHERE vbak.mandt = $session.client;
or implicitly with client-dependent views
lt_vbak = APPLY_FILTER ("Z_CDS_VIEW", :iv_where);

You don't HAVE to add the MANDT parameter to get the client number in AMDP/generated SQL script. Rather, you can use SESSION_CONTEXT('CLIENT')
So, your above query would look like the following:
ex_gt_data = select a.vbeln,
a.kunnr,
a.bukrs_vf,
b.erdat,
b.lsmeng,
b.posnr,
b.matnr
from vbak as a
join vbap as b
on a.vbeln = b.vbeln
and a.mandt = SESSION_CONTEXT('CLIENT');
There are many more things you can achieve using SESSION_CONTEXT. Used properly, it's a powerful tool at your disposal.
Best Regards,
Gopal Nair.

Related

cl_demo_output=>display data type not yet supported

In ABAP 7.4 OR above, We can use ASTERISK as much the same way as we use in SELECT *.
Following inner join is an example of new syntax which we can use.
SELECT scarr~carrname, spfli~*, scarr~url
FROM scarr INNER JOIN spfli ON scarr~carrid = spfli~carrid
INTO TABLE #DATA(t_result).
I am facing error when trying to display output by using below statement.
cl_demo_output=>display( t_result ).
The error message is "data type not yet supported"
Can anyone explain the reason ?
what could be the better solution?
In release 7.40, or even in ABAP 7.52, cl_demo_output=>display can only display an internal table with a list of elementary components (string, i, c, etc.)
In your case, the internal table t_result is automatically declared with three components, the second one being a structure, which is not an elementary type.
It's a structure because you used ~*. Instead, declare each column explicitly (spfli~carrid, spfli~connid, ...)
NB: the class cl_demo_output should not be used productively. If you need a generic tool, create your own tool, for instance based on the class cl_salv_table.

what is the use of ? in select distinct query

I was going through the code, I found one query where "?"mentioned.
query is
select distinct from A inner join B ON A.c =B.a and A.x=B.f and A.x=?
here what is the meaning of A.x=? , not able to understand.
is it something with runtime value, if yes then how ? will take runtime parameter.
I'm guessing this is from SSIS.
When you use a parameterised query over anything but ADO.NET, the parameters are defined with question marks. The first question mark is parameter 1, the second is parameter 2 etc. The problem with this is that each parameter can only be used once.
With ADO.NET you can specify parameter names which (in my view) is much better.

CDS LIKE filter from view parameter

How to create a CDS that select all KUNNR from table KNA1 that Customer Number starts for example with A%.
I could use LIKE in the where clause but the RHS of the condition have to be static. It should depend on the input parameter from CDS.
Is it possible to do it with CDS?
I see two options.
You get rid of your CDS input parameter handling and move the logic to ABAP. Write your OPEN SQL select on your CDS with like statement.
Use CDS Table function and AMDP by pushing the like statement down to HANA native. Just follow my post here.
Hope it helps.

Join tablevariable in a loop

I'm using SAP HANA and would like to join the output results of a procedure call inside a loop, is there anyway to do this?
Something similar to this: But the problem is the duplicate attribute name
FOR i IN 1..:nYEARS DO
CALL FUTUREREVENUES (:i,resulttemp);
result = SELECT * FROM :result t1
INNER JOIN :resulttemp t2
ON t1.ID = t2.ID
END FOR;
Nope, the main problem is not the duplicate attribute name; SAP HANA actually allows that in a projection, as long as the attribute is uniquely identifiable.
What you are trying to do here is not a good idea in any statically typed language, such as SQL. Basically, the structure of your return type result depends on the input, i.e. how often the loop gets executed.
What you would need here is some way of dynamic SQL that adjusts the projected column names with each iteration. While this appears to be a straightforward approach, it's actually the opposite.
Every consumer of the result data is forced to accept whatever the table comes out of this loop, without even knowing how the projected columns would be named.
That's hard to handle and makes the solution very little reusable.
An alternative approach could be to have a fixed output table structure, say 5 years forecast (if you can even predict anything that far with any certainty), and no dynamic column names.
Instead, you could e.g. name the columns FC+Year1, FC+Year2, ...
That way, the output structure stays the same and all the client application has to do, is to match the output labels according to the baseline year (the input into your prediction).

How to find table related with an alias in Doctrine ORM query?

I'm using Doctrine ORM 1.2 and Symfony 1.4 and I want to create method in myUser class which will extend Doctrine_Query instance passed as an argument with some additional left joins and conditions. The trick is that I don't always want these these left joins to be made with root component of the query and I need to know with what table (record class) the alias corresponds - in some cases I would like to pass an alias of another component and expect it to be supplemented with some extra left joins and conditions.
My question is how can I check what component (essentially table) represents given alias? Suppose I create a Doctrine_Query instance:
$query = Doctrine_Query::create();
$query->from('Folder f')->leftJoin('f.ChildFolders cf');
Now I want my method in myUser class to add some joins to the table with alias 'cf' but varying depending on table which 'cf' aliases. I want to call it this way:
$this->getUser()->limitQueryResultsWithSomeCondition($query, 'cf');
That should return query with additional elements. How can I find out what table is symbolized by 'cf' alias and whether it exists at all in given query?
It is quite straightforward when it is root table of a query that needs to be extended, but I cannot find a way to do it in other cases.
I guess I found my own solution to the problem. To find out to which table/record given alias corresponds one has to use getQueryComponent method. Suppose the query is same as in question above. The solution then reads as follows:
$alias = 'cf';
$query->getSqlQuery();
$component = $query->getQueryComponent($alias);
$recordClass = get_class($component['table']->getRecordInstance());
The trick is that before method getSqlQuery (or some method which is called inside of this method) is called the component will not be found and exception will be thrown.