ABAP On Hana
ABAP On Hana
Column store:
If we are fetching table data frequently or if we are fetching particular fields data only then
Columnar store will be good.
HANA is memory database: Data will store in RAM. Fetching data from RAM is faster than
fetching data from Database. If the system is shutdown or restarted, then also data won’t remove.
Analytic means, combines the OLTP & OLAP process
Appliance means combines hardware and software technology & change the way of developing
&executing application.
In S4HANA, a few tables merged into single table and a few transactions merged into one
transaction.
XK01/XD01/FK01/FD01 Converted into one new transaction BP.
MB01/MB11/MB1B transactions are absolute and replaced with MIGO transaction.
MSEG/MKPF/MARD/MBEW/MARC (total material tables) are merged into one new table
MATDOC.
A few tables converted into views like BSIK, BSAK.
A few cluster table / pooled tables converted into transparent table.
SAP has created CDS views for a few tables. If we want to get to know that CDS view name for
the particular table we can find out like this.
Click on Extras (menu button) Replacement Object.
In Application Layer, there will be ‘Database Abstraction’. It can get to know that to which DB
we have connected. Whatever we are writing the code in ABAP layer it will convert into Native
SQL (Database understandable format).
For example, we have written the code in the Application layer in Native SQL (Database
understandable format). It is working fine. After a few days, I want to migrate to another
database to DB2. Now the DB2 syntax will be different. If we migrate the programs to DB2, It
will through errors.
Provide name (_SJF), description (Looping statement), Pattern, click on Apply button. In Pattern I’m
maintaining like this.
loop at it_ into _wa.
write:/ wa_ , wa_ , wa_ .
endloop.
Click on Ok button. Now you can use this template anywhere in our programs.
In middle of the program I’m giving like _SJF & click on enter. Automatically the pattern data will paste
here.
Open the program click on Program menu button Check Code Inspector.
Here we are not maintaining where condition for VBAK table. We can see that in code inspector.
If we extend all errors in code inspector, we can get to know the performance issues.
If we want to check more than one program at a time, then we need to execute SCI T.Code.
I’m taking one more example for PO information. We will check performance check (SCI) for
previous program (ZSO) and the current program (ZPO).
REPORT ZPO.
select * from ekko into table @data(lt_ekko).
In select Object Set tab, deselect the Class/Interface checkbox & Function Group checkbox.
Click on Free Obj choice tab.
In the check variant, provide the name as PERFORMANCE_DB (we are checking the
performance). We have created one object set named as ZTEST_SO_PO. In that one we have
mentioned 2 program names (ZPO & ZSO). Just paste that object set name here.
If we want to activate the trace for particular user or particular table, click on Activate Trace with
Filter button. Otherwise click on Activate Trace. Click on enter button. We can get the status as
below.
Select the ‘Get names for internal tables’ check box. Provide the variant name and click on
‘New’ button which will be under that variant name.
Click on Hit List tab. We can see for each statement how much time is consuming.
Instead of SE30 transaction, we are using SAT transaction now.
ST12
Execute ST12 transaction. Click on ‘current mode’ button. Select the radio button program and
provide the program name. Click on ‘Execute / start trace’ button. It will execute the program.
Click on back button. Select our log as shown in the below image.
Open SQL
ECC is 3-tier architecture (Presentation Server, Application Server and Database Server). We
will write something code in the Application server to fetch data from Database. We will write
OPEN SQL syntax in application server. DB Interface will convert this OPEN SQL syntax into
Native SQL, fetch the data and send it to Application server.
This is also 3-tier architecture. In presentation server, we will use SAP FIORI and Database as
HANA. In Application server lot of changes are there. We have to follow New Open SQL
syntax, create CDS Views and AMDP. If we create and activate CDS view, automatically
HANA view will create in DB layer. If we create, activate and run the AMDP, automatically
Stored Procedure will create in DB layer.
Data Integration
Select Query
Loop
Calculation
End loop
Medium data
Huge data
transfer transfer
How to save move the Information Model (Hana Modelling Views) from DEV to QAS
Need to create the Information Model (Calculation View) in one package. Need to create
Delivery Unit. Open Hana Modeller Perspective. Click on Windows → Show View → others →
type ‘Quick View’ in search bar click on enter button. Click on Quick View Option. One
sunscreen will display at right side of your screen. Click on ‘Delivery Unit’. Select the user name,
click on next button. It will display all Delivery Units. If you want to use existing one, need select
the Delivery Unit name otherwise click on ‘New’ button. If ‘New’ button is appearing, expand the
window width. Click on ‘New’ button. Provide the name (Delivery Unit Name), click on ‘OK’
button. Select our Delivery Unit name, Click on ‘Add’ button. Select our package where we have
saved the Information Model. Click on ‘Finish’ button.
Click on New button (down arrow button), click on Other. Search for Hana Transport Container.
Click on Hana Transport Container, click on ‘Next’ button. Provide the Hana Delivery Unit
Name. Click on ‘Next’ button, Select the TR, Click on Finish button. Click on ‘Take snap shop
and save’. Now the Delivery unit will save in TR.
Attribute View: It will contains Data foundation & Semantics. Data foundation means we can
provide tables with selections, joins & condition in this area. Semantics means it will contain
more information about this data model like mentioning key fields, hierarchies
Content: It is collection of packages which we add different development objects including
information models.
Analytical view
Analytical views are the
multidimensional views or OLAP
cubes. Using analytic views you can
analyze values from a single fact
table that is based on the related
attributes from data foundation and attribute views
Creation of Analytical view: Right click on the package New Analytic view. Provide
name, label and click on finish button.
Calculated Column: Calculated columns are used to add one column to the output with the
values which are calculated by a formula.
Select new calculated column folder as shown in the above image. Provide name, label, data
type, length, scale, column type, formula. Click on validate syntax. It will show one message
either it is success or failure also. If it is success, click on ok button.
Here I’m giving the column name as US_CUST_NETPRICE. If the condition satisfy, then only I
want to display the NETWR in the new column.
Calculation Views:
Calculation views are used to achieve multiple star schemas means multiple fact tables
surrounded by multiple dimension tables.
How to create Calculation views:
Right click on package New Calculation view. Provide Calculation view name, label and
type as Graphical, select Data Category as Dimension. Click on Finish button.
Here, Data category is containing as Dimension, Cube, Cube with Star join. First we will try with
Dimension.
In the Join also we can add 2 tables / attribute / analytical / calculation views. If we want join more
tables, then we have to drag and drop one more join. In that join we have to take one more table &
link from second join to first join. In each & every join we have to select the fields. If we want to
add the fields to semantics in a single shot, right click on that field Propagate to semantics
I can take two projections also in a single Dimension Calculation view. By default one projection
will come while creation of a Dimension Calculation view. Now I can add Second projection also.
Here, we can add Filter. This is the main difference between Primary and secondary projections.
Here we can drag and drop the Union also. Union can support more than one table / view. But it
will combine all sources information in a single place.
If we want add any tables, we can drag and drop join or projection or aggregation.
Rank:
Rank is used to give ranks to the output data. My requirement is, I want to give ranks based on net
value in sales order wise.
Drag and drop the Rank to the main area. Provide table or view in that rant.
Provide Package name, Name of the view, description, Hana View as ‘package.view_name’
(click on browse, provide attribute or analytical / calculation view). Click on Next button.
Click on Finish button, click on Activate button.
Anonymous Block means, we can use it for testing purpose just use and through. It will not
contain any name. It will not save anywhere in server and no name assigned to it. If we execute
it, it will compile every time so it will take some time for execution.
Procedure means, it will store permanently in database with something name. It will be very fast
execution. Because it will compile procedure for the first time, second time on wards it will not
compile, directly execute the procedure.
UDF means, we can write aggregate functions here.
Anonymous Block:
DO ( OUT X INT => ? )
BEGIN
DECLARE A INT = 10;
DECLARE B INT = 2;
DECLARE C INT = 0;
C = A + B;
X = C;
END;
Here I’ve started with ‘DO’ statement. If we have any input parameters or output parameters we
have to maintain here only DO ( IN A INT => ? OUT C INT => ? ).
‘DECLARE’ is the statement to declare variables.
If we don’t maintain variable value like
Declare A INT;
system will consider as ‘A’ is one integer data type variable. It will contain null value. We can’t
execute any line will null value. It will not show any error message if we pass null value. Output
will display like ‘?’.
By using the above syntax, we can give input parameters (as parameter).
Procedure
drop procedure lr_pr1;
create or replace procedure lr_pr1( out c int )
language sqlscript
default schema "HANAUSER"
reads SQL DATA
as begin
declare a int = 10;
declare b int = 20;
c = :a + :b;
end;
Do While in a procedure
create or replace procedure lr_pr3( in a int, out result nvarchar(10) )
as begin
declare b int = 0 ;
result = 0;
while ( b < a ) do b = :b + 1 ;
result = :result + :b ;
end while;
end;
If we don’t write ‘RESULT = 0’ in 4th line, the output will display like ‘?’. Because we are using
that ‘result’ field as input as well as output. If we are using it as input, then the initial value
should be null. So we need to pass something value to it.
Table Types declaration for a procedure:
drop type tt_kna1;
create type tt_kna1 as table ( kunnr nvarchar(10),
name1 nvarchar(35),
ort01 nvarchar(35) );
‘Create or replace type’ option is not there. So first we are dropping (deleting) the ‘type’ then
creating the ‘type’.
We can see this table type under schema name Procedure Table types.
Use table type in a procedure:
In the 3rd line, I’ve mentioned like Result1 = select query. But I didn’t declare this temporary
table (internal table in SAP terms). Automatically system will create one temporary table (like
inline declaration) and store the result.
In the 4th line, I didn’t mention result = result1. It should not work here. One more time I’m
writing select query on top of temporary table. That is why I’ve mentioned ‘from table’ like
‘:result1’.
call lr_pr8( ? );
Here by using this syntax, we can maunually fill internal table line by line.
:it_emp.insert( (1, 'Gayatri'), 1 );
If we want to fill internal table by using another internal table(select query data), we can write
like this
:it_emp.insert ( ( :lt_emp.emp_id[i], :lt_emp.emp_name[i] ), i );
Session_context(client) is the system variable which will contain the current client number.
Session_contest(applicationuser) is the system variable which will contain current user
name.
Exception Handling
create or replace procedure lg_pr7( in x int, in y int, out z int )
as
begin
If we divide any value with zero it will go to dump in ABAP editor. In SQL also, it will not show
any output. To skip it or to handle this exception we can write the code as above procedure.
DECLARE EXIT HANDLER FOR SQLEXCEPTION
By using the above statement system will handle the exception. If we want to display the
exception code, exception message we can write like
SELECT ::SQL_ERROR_CODE as ERROR_CODE, ::SQL_ERROR_MESSAGE as
ERROR_MSG from DUMMY;
Update internal table based on index number (read table index)
CREATE OR REPLACE PROCEDURE LG_PR1( OUT IT_KNA1 TT_CUST )
AS BEGIN
DECLARE LV_IND INT;
IT_KNA1 = SELECT KUNNR, NAME1, ORT01 FROM KNA1;
lv_ind = :IT_KNA1.SEARCH( (KUNNR), '0010100004' );
IT_KNA1.ORT01[LV_IND] = 'CHENNAI';
END;
Cursor
CREATE or replace procedure proc_test7( in p_land1 nvarchar(3), out lt_kna1
table ( kunnr nvarchar(10), name1 nvarchar(35), ort01 nvarchar(35) ) )
as begin
declare ev_kunnr nvarchar(10);
declare ev_name1 nvarchar(35);
declare ev_ort01 nvarchar(35);
declare lv_ind int ;
--declare cursor
declare cursor c1
for select kunnr, name1, ort01 from saphanadb.kna1
where land1 = :P_LAND1;
--open cursor
open c1;
--fetch data
for lv_ind in 1..500 do
fetch c1 into ev_kunnr, ev_name1, ev_ort01;
if c1::NOTFOUND THEN
return;
end if;
lt_kna1.kunnr[lv_ind] = ev_kunnr;
lt_kna1.name1[lv_ind] = ev_name1;
lt_kna1.ort01[lv_ind] = ev_ort01;
end for;
/*fetch c1 into ev_kunnr, ev_name1, ev_ort01;
Here IS_EMPTY is fixed variable. We can’t change this name to check the internal table is
empty or not.
Create a table from procedure
CREATE procedure lg_pr3
as begin
drop table comp_info;
create table comp_info(bukrs varchar(4), butxt varchar(40), ort01 varchar(40)
);
insert into comp_info values( '1000', 'Cognizant', 'Bangalore' );
insert into comp_info values( '2000', 'CGI', 'Bangalore' );
insert into comp_info values( '3000', 'TCS', 'Bangalore' );
end;
we can insert particular field information in the table (by using internal table) as below.
insert into comp_info( BUKRS, BUTXT ) select BUKRS, BUTXT from :lt_t001;
Upsert will work like if key data is available in the table, it will modify the data. If the key field
value is not available then it will insert the data into table.
How to export Procedure to ABAP layer (Application server)
We can export Procedure to Application server in 2 ways
ADBC (ABAP Data Base Connectivity)
Database Procedure Proxy
PUBLIC SECTION.
TYPES: tt_kna1 TYPE TABLE OF kna1.
INTERFACES: if_amdp_marker_hdb.
METHODS: get_customer
IMPORTING VALUE(imp_kunnr) TYPE kna1-kunnr
EXPORTING VALUE(it_kna1) TYPE tt_kna1.
ENDCLASS.
AMDP can read, modify, update the data in the DB level. So we need to mention that we are
reading data or modifying data. If we are modifying, not required to mention this ‘Options’ here.
USING kna1.
We are using KNA1 table in the method implantation. We need to mention all table names or
view names, which are using in the method implementation.
obj_kna1->get_customer(
EXPORTING
imp_kunnr = p_kunnr
IMPORTING
it_kna1 = lt_kna1 ).
try.
call METHOD cl_salv_table=>factory
IMPORTING
r_salv_table = data(obj_final)
CHANGING
t_table = lt_kna1 .
CATCH cx_salv_msg.
endtry.
We are calling the AMDP method. Now the database procedure is created in the db.
I’m taking one more example for inner join taking source from another method.
CLASS zamdp_sales DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES: if_amdp_marker_hdb.
types: BEGIN OF ty_vbak,
vbeln type vbak-vbeln,
audat type vbak-audat,
kunnr type kunnr,
end of ty_vbak,
tt_vbak type TABLE of ty_vbak,
lt_vbak1 type TABLE of ty_vbak,
BEGIN OF ty_vbap,
vbeln type vbap-vbeln,
audat type vbak-audat,
kunnr type kunnr,
posnr type vbap-posnr,
matnr type vbap-matnr,
end of ty_vbap,
tt_vbap type table of ty_vbap.
methods: get_vbak IMPORTING VALUE(i_vbeln) type vbak-vbeln EXPORTING VALUE(lt_vbak)
TYPE tt_vbak,
get_vbap IMPORTING VALUE(IMP_VBELN) type VBAK-VBELN EXPORTING VALUE(lt_vbap)
type tt_vbap.
ENDCLASS.
method get_vbap BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY
USING ZAMDP_SALES=>GET_VBAK vbap .
call "ZAMDP_SALES=>GET_VBAK" (I_VBELN => :IMP_VBELN, LT_VBAK => :LT_VBAK1);
lt_vbap = select a.vbeln, a.audat, a.kunnr, b.posnr, b.matnr from :lt_vbak1 as a
inner join vbap as b on
a.vbeln = b.vbeln;
endmethod.
ENDCLASS.
Here get_vbak is the method to fetch data from VBAK table. I’m calling this method in get_vbap
method to get header information and doing inner join.
We are giving invalid input and fetching a single record. Then data will not fetch and it will go to
dump. To avoid this one, we can go thorough like this
select vbtyp into lv_vbtyp1 DEFAULT NULL from vbak ;
Here I’ve mentioned like ‘DEFAULT NULL’. It means, if the data is not fetching from table,
then the value should be null.
We can declare any variable by using ABAP data element as shown in the above syntax.
If we don’t want to fetch some records, we can write the code like this
LT_VBAK = SELECT VBELN, AUDAT, VBTYP FROM VBAK
except
select vbeln, audat, vbtyp from vbak where vbtyp = 'B';
Here, I’ve mentioned like ‘EXCEPT’ means, it will fetch all records from VBAK then it will
remove all the records which record type ‘B’ from the table.
In the above syntax, filling LT_VBAK internal table first. Then passing all the data to
LV_SALES internal table. Then one more time writing select query with false condition. At that
time, whatever the data is available in the internal table, all data will remove.
Otherwise we can write the code as below.
lt_vbak = select null as vbeln, null as audat, null as vbtyp from dummy where
1 = 2;
Select-options in AMDP:
1. Declare Select-options in the program
2. Convert the select-options values into a string
3. Pass the string into procedures using import parameters
4. In Procedure use APPLY_FILTER into the string values which got received
REPORT zp_amdp2.
types: BEGIN OF ty_kna1,
kunnr type kna1-kunnr,
name1 type kna1-name1,
ort01 type kna1-ort01,
end of ty_kna1.
data it_kna1 type table of ty_kna1.
data lv_kunnr1 type kunnr.
select-OPTIONS: s_kunnr for lv_kunnr1.
*Convert s_kunnr to string
data(lv_kunnr) = cl_shdb_seltab=>combine_seltabs(
it_named_seltabs = value #( ( name = 'KUNNR' dref = ref #
( s_kunnr[] ) ) ) ).
zcl_amdp2=>get_data(
EXPORTING
i_kunnr = 'abc'
im_kunnr = lv_kunnr
IMPORTING
et_kna1 = it_kna1[]
).
In the above program I’m just converting select-options into string. Name = ‘KUNNR’ passing
in the IT_NAMED_SELTABS, it means we need to pass the where condition field (it field
should be in the select query and should not provide alias name with different name. for example
ENDCLASS.
CLASS zcl_amdp2 IMPLEMENTATION.
method get_data BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY using kna1 .
et_kna1 = select kunnr, name1, ort01 from kna1;
et_kna1 = APPLY_FILTER ( :et_kna1, :im_kunnr );
endmethod.
ENDCLASS.
PUBLIC SECTION.
types tt_mard type table of zmard.
interfaces if_amdp_marker_hdb.
class-methods upd_cust EXPORTING VALUE(et_mard) type tt_mard.
ENDCLASS.
for I in 1..lv_count do
:et_mard1.insert ( ( :lt_mard.mandt[I],
:lt_mard.matnr[I],
AMDP Function Method can’t execute directly. We need to call this Function method in another
method. We need to execute this method.
PUBLIC SECTION.
types: tt_kna1 type table of kna1 with DEFAULT KEY.
INTERFACES IF_AMDP_MARKER_HDB.
class-methods: get_kna1 EXPORTING VALUE(lt_kna1) TYPE tt_kna1.
class-methods: get_customer IMPORTING VALUE(LV_KUNNR) TYPE KUNNR
returning VALUE(lt_kna1) type tt_kna1.
ENDCLASS.
PUBLIC SECTION.
INTERFACES if_amdp_marker_hdb.
types: BEGIN OF ty_so,
vbeln type vbeln_va,
posnr type posnr_va,
audat type audat,
matnr type matnr,
kwmeng type vbap-kwmeng,
end of ty_so,
BEGIN OF ty_bill,
vbeln type lips-vbeln,
posnr type lips-posnr,
lfdat type likp-lfdat,
lfimg type lips-lfimg,
vgbel type lips-vgbel,
vgpos type lips-vgpos,
end of ty_bill,
BEGIN OF ty_final,
vbeln type vbeln_va,
posnr type posnr_va,
audat type audat,
matnr type matnr,
kwmeng type kwmeng,
bill1 type lips-vbeln,
bill1_dt type audat,
bill1_qty type lips-lfimg,
bill2 type lips-vbeln,
bill2_dt type audat,
bill2_qty type lips-lfimg,
bill3 type lips-vbeln,
bill3_dt type audat,
bill3_qty type lips-lfimg,
tot_bill_qty type lips-lfimg,
pend_qty type lips-lfimg,
end of ty_final.
types: tt_so type table of ty_so,
tt_bill type table of ty_bill,
tt_final type table of ty_final.
class-methods: get_so EXPORTING VALUE(lt_so) type tt_so,
get_bill EXPORTING VALUE(lt_bill) type tt_bill,
-- Get SO info
call "ZCL_FOLK3=>GET_SO"( LT_SO => :LT_SO1 );
LV_SO_REC = RECORD_COUNT( :LT_SO1 ); -- No of records in LT_SO1
LV_VBELN = :LT_SO1.VBELN[ I ];
LV_POSNR = :LT_SO1.POSNR[ I ];
LT_TEMP_BILL = SELECT VBELN, POSNR, LFDAT, LFIMG, VGBEL, VGPOS FROM :LT_BILL1
WHERE VGBEL =
LV_VBELN
AND VGPOS =
LV_POSNR;
if is_empty( :lt_temp_bill ) then
else
ELSEIF( M = 2 ) THEN
LT_FINAL.BILL2[ I ] = :LT_TEMP_BILL.VBELN[ M ];
LT_FINAL.BILL2_DT[ I ] = :LT_TEMP_BILL.LFDAT[ M ];
LT_FINAL.BILL2_QTY[ I ] = :LT_TEMP_BILL.LFIMG[ M ];
SUB_BILL_QTY = :SUB_BILL_QTY + :LT_TEMP_BILL.LFIMG[ M ];
ELSEIF( M = 3 ) THEN
LT_FINAL.BILL3[ I ] = :LT_TEMP_BILL.VBELN[ M ];
LT_FINAL.BILL3_DT[ I ] = :LT_TEMP_BILL.LFDAT[ M ];
LT_FINAL.BILL3_QTY[ I ] = :LT_TEMP_BILL.LFIMG[ M ];
SUB_BILL_QTY = :SUB_BILL_QTY + :LT_TEMP_BILL.LFIMG[ M ];
END IF;
END FOR;
LT_FINAL.TOT_BILL_QTY[ I ] = SUB_BILL_QTY;
LT_FINAL.PEND_QTY[ I ] = ( :LT_SO1.KWMENG[ I ] - SUB_BILL_QTY );
sub_bill_qty = 0;
end if;
END FOR;
endmethod.
ENDCLASS.
Click on system status. We can get above screen and we can see default schema name.
PUBLIC SECTION.
TYPES: BEGIN OF TY_SO,
VBELN TYPE VBELN_VA,
KUNNR TYPE KUNNR,
VBTYP TYPE VBTYP,
END OF TY_SO.
Note: ABAP CDS view will support read data only & not for modify or write data.
Difference between ABAP dictionary view & CDS
ABAP Dictionary View CDS View
Support on all DBMS Yes Yes
Support combining queries Inner join Inner, outer, union
Calculation No Yes
Nested view No Yes
There is no editor for DDL source code in classical ABAP work bench. That is why the new type
of repository object can be analyzed and developed in ADT (ABAP Development Tool). After
Right click on your user id New Other ABAP Repository Object Expand Code Data
Services Select Data Definition Click on Next Button Provide the Package name, CDS
view name, Description.
For checking the code, shortcut is Ctrl + F2, for activating the view shortcut is Ctrl + F3, for
executing the view the shortcut is F8. You can see the shortcut buttons in the above image.
After execute the CDS view, it will display in this format. You can add filters, you can restrict
maximum number records to display and you can get to know how many records displayed. If
you want to know the background SQL syntax for the displaying the output, you can click on
SQL Console.
If you want to open the SQL View in SAP GUI, Select the SQL View name, click on F3 button.
It will navigate to SAP GUI. But you can’t edit SQL view in SAP GUI.
If you want to know that CDS view is used in any object or not (Where used list in SAP GUI),
select the CDS view in the left panel, Right click on it Open with Dependency Analyzer.
Note: CDS is a just view as DDIC view. By using CDS, we can add some extra features. If we
want to save this CDS view in DB layer, then we need to use the below annotation.
@AbapCatalog.sqlViewName:
By using the above annotation, we can save the CDS view in Database layer. Off course this is
mandatory annotation for every CDS view, otherwise system will through error.
By using @EndUserText.label annotation, we can display the description in ABAP Layer,
otherwise it will display the standard description.
Note: By default, CDS view is client dependent. If you want to make it as client independent,
then you have to pass one annotation as @clientdependent: false
In the output we can see the alias names instead of technical names.
If we want display the space in between of two words in field names, we can go for annotations.
Note: If we have parameters in CDS view, we can display it in SE11 but can’t execute (can’t
display the output).
If we are doing any calculation, input fields and output fields must and should be same data type.
So, need to convert it to float data type. For that we need to apply like this
cast (netwr as abap.fltp) * 0.30 as new_amt
Directly select-options will not work in CDS views. Instead of that one, we can apply only one
range as select-options by using between operator.
If you want to use system fields, then we have to write like this $session.client (if we click on
Ctrl + space after $session, it will display all system fields)
I’ve used Union all here. The output will come like this.
In VBAK one record is available and in VBAP two records are available. By using Union all
total records are coming as 3 in the output. Here it will not delete the duplicate records. If we use
Union then in output only one record will come.
If we use Union then it will remove the duplicate entries. That is the difference between union
and union all.
Associations
Association are three types. 1.Ad-hoc, 2.Exposed 3.Filtered Association
@AbapCatalog.sqlViewName: 'ZCDS_SQL_EX7'
@EndUserText.label: 'Associations'
define view ZCDS_DDL_EX7 as select from vbak as k association to vbap as p
on k.vbeln = p.vbeln
{
k.vbeln,
k.audat,
k.kunnr,
p.posnr, //ad-hoc association
p.matnr //ad-hoc association
}
I’m using the above code for Exposed association. If we check SQL code for this one,
CREATE OR REPLACE VIEW "ZCDS_SQL_EX7" AS SELECT
"K"."MANDT" AS "MANDT",
"K"."VBELN",
"K"."AUDAT",
"K"."KUNNR"
FROM "VBAK" "K"
It is not creating any join here. If we execute this view, it will display only VBAK table fields (3
fields).
If we want to display VBAP table information for particularly one record, Right click on the
record in the output.
Here, I’m adding fields from VBAP table. If we check the SQL code,
CREATE OR REPLACE VIEW "ZCDS_SQL_EX8" AS SELECT
"A"."MANDT" AS "MANDT",
"A"."VBELN",
"A"."AUDAT",
Note: If we are using associations, we have to note one point. We have to mention all fields in
the select statement which are mentioned in the ON Condition.
Note: By default, Association will apply Left Outer Join. We can change it to other joins as
below CDS view.
@AbapCatalog.sqlViewName: 'ZCDS_SQL_EX16'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Associations'
define view ZCDS_DDL_EX16
as select from vbak as k
association to vbap as p on k.vbeln = p.vbeln
{
key k.vbeln,
k.audat,
p[inner].matnr
}
Note: If we are using associations, we are selecting common fields, then need not to mention
alias_name.field_name. Automatically it will pick the value from left side table. If we are
selecting other than common fields from right side table, then we need to mention
alias_name.fieldname. For left side tables, not required to mention alias_name.fieldname.
In the above CDS View, I’ve mentioned _sitem (it’s public). In SE38 (ABAP editor), I’m
selecting the fields like this from _sitem.
select so_number,
customer,
document_type,
\_sitem-posnr as so_item,
\_sitem-matnr as material
from zcds_so
into TABLE @data(lt_so).
cl_demo_output=>display(
EXPORTING
data = lt_so
).
Here, I’ve mentioned ‘from ZCDS_SO’ If we take SQL view (SE11 view), it will throw error. If
we are not taking fields from _sitem , then it will not throw any error. We are selecting some
fields from _sitem and we need to avoid error. In this case we should use DDL view (CDS View
name which has given in Hana Studio / Eclipse).
Path Expression
@AbapCatalog.sqlViewName: 'ZSQL_SO'
define view zcds_so as select from vbak as _sheader
association [1..*] to vbap as _sitem on _sheader.vbeln = _sitem.vbeln
association [1..1] to kna1 as _customer on _sheader.kunnr = _customer.kunnr
{
key _sheader.vbeln as so_number,
_sheader.kunnr as customer,
_sheader.vbtyp as document_type,
_sitem,
_customer.name1 as CUSTOMER_NAME
}
I want to display customer name(should not disturb other field values) for only a specific
customer number (here I’m considering 0017100001). Then we can apply path expression.
I’m just doing some modification here for the first CDS view.
@AbapCatalog.sqlViewName: 'ZSQL_SO'
define view zcds_so as select from vbak as _sheader
association [1..*] to vbap as _sitem on _sheader.vbeln = _sitem.vbeln
association [1..1] to kna1 as _customer on _sheader.kunnr = _customer.kunnr
{
key _sheader.vbeln as so_number,
_sheader.kunnr as customer,
_sheader.vbtyp as document_type,
_sitem,
_customer
}
Aggregate Functions
@AbapCatalog.sqlViewName: 'ZSQL_AGGR_FUN'
define view zcds_aggr_fun as select from vbap {
key vbeln,
sum( netwr ) as sum_netwr,
min( netwr ) as min_netwr,
max( netwr ) as max_newr,
avg( netwr ) as avg_newr,
count(*) as count_num
} group by vbeln
If we are using Sum or min or max or avg or count any aggregate function then we must take
group by with non-aggregate function fields.
@AbapCatalog.sqlViewName: 'ZSQL_AGGR_FUN'
define view zcds_aggr_fun as select from vbap {
count(*) as num,
count(distinct vbeln ) as count_num
} where vbeln = '0000000165'
and matnr = '000000000000000140'
In Count(*) we can see the duplicates but in count(distinct <field_name>) duplicates will
remove.
@AbapCatalog.sqlViewName: 'ZSQL_HAVING'
define view ZCDS_having as select from kna1 as c inner join vbak as h on
c.kunnr = h.kunnr {
key c.kunnr as customer,
count(distinct h.vbeln) as count_so,
sum(h.netwr) as sum_amt
}group by c.kunnr
having sum(h.netwr) >= 2250000.00
Extend View
Extend view is nothing but enhancement. If we want to add any field in standard or custom CDS
view without disturbing the view, we can go for Extend View.
Here I’m taking one CDS View name as ZCDS_DDL_EX2. In the 3rd line, we can see square
symbol. That symbol indicates that, this is enhanced with another view. If we open it in ABAP
Workbench, enhanced fields will add by using APPEND structure.
We can add associations, concatenates in the Extend View. Joins will not support in the Extend
View.
I’ll take one more example.
@AbapCatalog.sqlViewName: 'ZS_AGR_FUN2'
@EndUserText.label: 'aggreage functions'
define view zc_agr_fun2 as select from vbap {
vbeln,
count(*) as count_vbeln,
sum(netwr)as sum_netwr
} group by vbeln
I’m just maintain aggregate functions in CDS view. Now I’ll create one extension view for the
above view.
System is not allowing to add extension view for the view which has implemented with
aggregate functions.
By adding one annotation we can overcome in this issue.
@AbapCatalog.sqlViewName: 'ZS_AGR_FUN2'
@EndUserText.label: 'aggreage functions'
@AbapCatalog.viewEnhancementCategory: [ #PROJECTION_LIST, #GROUP_BY]
define view zc_agr_fun2 as select from vbap {
vbeln,
count(*) as count_vbeln,
sum(netwr)as sum_netwr
} group by vbeln
SQL Functions:
@AbapCatalog.sqlViewName: 'ZCDS_SQL_EX20'
@EndUserText.label: 'inbuilt functions'
define view zsql_fun2 as select from vbak {
netwr as net_price,
ceil(10.2) as ceil_netwr,
floor(20.9) as floor_netwr,
abs(-200) as abs_val,
div(9,2) as div_val,
round(netwr,0) as round_num,
division(10,3,2) as division_num,
mod(9,2) as mod_val,
cast(vbeln as char30) as cast_vbeln
}
Ceil will take lowest nearest value, Floor will consider highest nearest value.
ABS will remove negative symbols.
Round will nearest low or high value (low will consider for <.4 value. High will conider for >=.5
value).
Div display only numeric value not float value.
Division will consider floating value depend given digits.
Mod will work like numeric only.
@AbapCatalog.sqlViewName: 'ZSQL_AF_FUN'
define view zcds_ag_fun as select from kna1 {
kunnr,
name1,
ort01,
land1,
// Length
length(name1) as len_name,
// Concatenate two fields
concat(land1, ort01) as con_name,
// Concatenate two fields with space
concat_with_space(land1, ort01, 1) as con_name_sp,
// Nested Concatenate
concat_with_space(concat_with_space(land1, '-', 1), ort01, 1) as
nest_con,
// Ltrim
ltrim(kunnr,'0') as ltrim_kunnr,
// Rtrim
rtrim('123.00', '0') as rtrim_num,
// Nested Rtrim
rtrim(rtrim('123.00', '0'), '.') as nest_rtrim
}
@AbapCatalog.sqlViewName: 'ZSQL_FUN1'
define view zcds_sql_fun1 as select from kna1 {
kunnr,
name1,
land1,
upper(name1) as upper_name,
lower(name1) as lower_name,
left(name1,5) as left_name,
right(name1,5) as right_name,
lpad(land1, 20, 'INDIA - ') as lpad_land1,
rpad(land1, 20, 'IN - ') as rpad_land1
}
@AbapCatalog.sqlViewName: 'ZSQL_SPL_FUN'
If we want to convert float value to decimal by using CAST, it will not support. We can convert
it by using FLTP_TO_DEC. We can convert to currency, quantity also by using this.
@AbapCatalog.sqlViewName: 'ZSQL_FUN30'
define view zsql_fun3 as select from mara {
matnr,
ntgew,
gewei,
unit_conversion( quantity => ntgew,
source_unit => gewei,
target_unit => cast('G' as abap.unit( 3 ))) as unit_conv
} where ntgew <> 0
If we want to convert one currency to another currency, we can use above query.
@AbapCatalog.sqlViewName: 'ZSQL_FUN4'
define view zcds_sql_fun4 as select from vbak {
vbeln,
erdat,
dats_days_between(cast('20220101' as abap.dats), cast('20220112' as
abap.dats)) as day_between,
dats_days_between(erdat, audat) as days_between,
dats_add_days(erdat, 30, 'INITIAL') as days_add,
dats_add_months(erdat, 4, 'INITIAL') as months_add
}
We can find out number of days in between of two days, can add number of days to a particular
day, can add months to a particular day as shown in the above CDS View.
@AbapCatalog.sqlViewName: 'ZSQL_MAT_DET'
define view zcds_mat_det as select from mara {
key matnr as material,
@EndUserText.label: 'Material Type'
@EndUserText.quickInfo: 'Type of Material'
mtart as material_type
}
If the user wants to display the heading of the field with out under square ( _ ), then we can go
for @EndUser.Text.label
We can see the output in a program. In CDS view execute we can’t see the output like this.
Create a program in SE38 transaction with below code and execute.
cl_salv_gui_table_ida=>create_for_cds_view( 'ZCDS_MAT_DET' )->fullscreen( )-
>display( ).
We can’t see the heading in CDS view but we can see it in ABAP program output as shown in
above image.
@AbapCatalog.sqlViewName: 'ZCDS_SQL_EX13'
@AbapCatalog.preserveKey: true
define view ZCDS_DDL_EX13 as select from vbak {
key vbeln,
audat,
$session.client as clint,
$session.system_language as language,
$session.user as curr_user,
$session.system_date as sys_date
}
If we give ‘key’ prefix to the field in the view (non-key fields from table also) system will
consider as key field. We can check it in SE11 view by using SQL View name.
If we are not using this annotation or if we are passing the value as ‘False’, Then system will
consider key fields as in table (if I give ‘key’ to the non-key field and I’m not using the
annotation, then system will not consider it as key field. You can check in SE11 view).
When we are creating data base table (SE11), we can give buffering options like this in technical
settings.
@AbapCatalog.dbHints: [{
dbSystem: #HDB / #DB2 / #DB6 / #ORA ,
hint: ''
}]
CDS View can create on top of any database for example HANA (HDB), DB2, DB4, DB, Oracle
(ORA), etc. Just we are telling to the system that, which database we are using as of now and just
giving something hint for it.
Enhancement category:
Here #PROJECTION_LIST is nothing but allow a few more fields from extend view.
@AbapCatalog.sqlViewName: 'ZCDS_SQL_EX14'
@ClientHandling.type: #INHERITED
define view ZCDS_DDL_EX14 as select from zvbak1 inner join vbap
on zvbak1.vbeln = vbap.vbeln {
key vbap.vbeln,
audat,
vbap.posnr,
vbap.matnr
}
In the above view, I’ve used one more extra annotation @ClientHandling.type: #INHERITED
By default CDS View is Client Dependent. Not required to add this annotation externally as
@ClientHandling.type: #CLIENT_DEPENDENT. If we use this annotation as
#CLIENT_DEPENDENT there is no issue.
This is the view in SE11. Automatically MANDT will consider because VBAP table is client
dependent.
ODATA : @OData.publish: true
By using ‘@OData.publish: true’ annotation, we can expose CDS view to External system like
FIORI, UI5 etc.
@AbapCatalog.sqlViewName: 'ZCDS_SQL_EX22'
@OData.publish: true
define view ZCDS_DDL_EX22 as select from
vbak as k association[0..*] to vbap as p
on $projection.Sales_order = p.vbeln
{
key k.vbeln as Sales_order,
key p.posnr,
p.matnr,
k.kunnr
}
In the above CDS view, in ‘ON’ condition, used $PROJECTION. If we use it, we need to add
the alias name instead of field name. It will be helpful in a few cases to understand the logic.
Used ‘@OData.publish: true’ annotation also. It means, we are sending the result of CDS view to
external system. But before that one, we need to activate the service (service means connection
between CDS to view to external system).
Provide the system alias name, Technical service name. Technical Service Name we need to pass
as CDS view is proposing. Click on enter button.
We can see that service was created and metadata was loaded successfully. It means, Service is created
successfully.
Click on back button click on filter button, provide the external service name as our newly created
service name (ZCDS_DDL_EX22_CDS), click on contnue button.
Stuts code is coming as 200. It means there is no error. This connection will trigger in correct way.
We can see that one XML format also. If we want to display it in JSON format as shown in in the above
image select $format = json option. Click on enter button, click on execute button.
Instead of XML format SAP is preferring JSON format. Because it is light weight content means, JSON
format will contain memory compare to XML format.
If we want to provide authorization for a particular user or for one condition, we have to create
one role (Access Control DCL). In that role, we have to mention the CDS view which we want to
apply the authorization check.
Creation of Access Control: Right click on Core Data Services in the left panel
In the above Access Control, I’m provide the CDS view name (ZCDS_DDL_EX11) then
providing condition land1 = ‘IN’, means the CDS view will display only Indian Companies.
@AbapCatalog.sqlViewName: 'ZCDS_SQL_EX11'
@AccessControl.authorizationCheck: #CHECK
define view ZCDS_DDL_EX11 as select from t001 {
key bukrs,
butxt,
ort01,
land1 }
In the above CDS view, we are fetching data from T001 table. It will fetch only Indian
companies because of authorization check. We have to apply one annotation
@AccessControl.authorizationCheck: #CHECK
By adding ‘With Privileged Access’ in the select query, we can bypass the authorization check
value.
If we don’t want to apply this authorization check even though you have created Access control
for the CDS view, then we have to pass annotation like this.
@AccessControl.authorizationCheck: #NOT_ALLOWED
If we are passing like authorization check = Not Allowed, it will not consider the ‘Role’ even
though we have created Role.
@AccessControl.authorizationCheck: #NOT_REQUIRED
Means, it will work like #CHECK only. The difference is, if we don’t have any role and we are
applying authorization as #CHECK, then it will through warning message. If we apply
authorization as #NOT_REQUIRED, then it will not through any warning message.
@AccessControl.authorizationCheck: #PRIVILEGED_ONLY
Means, if we expose data to another environment like OData, data will not expose there. By
using association in another CDS view or file path we can expose. But directly we can’t send
data to another environment.
If we use the CDS view which authorization check applied in another CDS view, authorization
check will not apply in that CDS view.
@AbapCatalog.sqlViewName: 'ZCDS_SQL_EX12'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Authorization check'
define view ZCDS_DDL_EX12 as select from ZCDS_DDL_EX11 {
key bukrs,
butxt,
ort01,
land1 }
In the above CDS view, we are fetching the data from another CDS view (authorization check
applied). But this CDS view will fetch all records from T001 table and it authorization check will
apply here.
If we want to get to know where used list of a CDS view, we can check in the below steps.
Right click on CDS view Get where-used list (Ctrl + Shift + G). We can see the list of
programs / views / roles which are used that base CDS view.
By using the below annotations, we can improve the performance of CDS view.
@ObjectModel.usageType.serviceQuality: #A
@objectmodel.usagetype.sizeCategory: #L
@objectmodel.usagetype.dataClass: #TRANSACTIONAL
@ObjectModel.usageType.serviceQuality: #A/B/C/D/P/X
Note: DDHEADANNO is the table to store all annotations used in a CDS view.
Semantics Annotations
@Semantics.amount.currencyCode: 'waerk'
@Semantics.quantity.unitOfMeasure: 'vrkme'
If we are working on amount and quantity fields in CDS, we need to link the currency type and
unit of measurement type fields as show in the below CDS view. These annotations are
mandatory in CDS View Entity.
@AbapCatalog.sqlViewName: 'ZSQL_FOLK24'
define view zcds_folk24 as select from vbap {
vbeln,
posnr,
matnr,
waerk,
@Semantics.amount.currencyCode: 'waerk'
netwr,
vrkme,
@Semantics.quantity.unitOfMeasure: 'vrkme'
kwmeng
}
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'test'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity zcds_folk23 as select from vbak {
vbeln,
audat,
kunnr
}
@VDM.viewType: #CONSUMPTION
@Analytics.query: true
@VDM.viewType: #COMPOSITE
@Analytics.dataCategory: #CUBE
SAP is recommended to create Basic views on top of tables. We can create on top of another
CDS view also, but SAP will not recommend it. Composite view should create on top of Basic
view. On top of database table also we can create Composite view, but SAP will not recommend
it. Consumption view should create on top of Composite view. We can create Consumption view
on top of database table and Basic view also, but it is not recommended.
Data Category types:
#Dimension: This annotation is telling to the system that, you need to allow master data.
#Fact: This annotation telling to the system that, you need to allow transaction data.
#Cube: This annotation is telling to the system that, you need to allow transaction data and
master data.
For Basic view and composite view we need to mention that @Analytics.dataCategory:
#DIMENSION / #FACT .
@AbapCatalog.sqlViewName: 'ZSQL_FOLK26'
@EndUserText.label: 'testing'
@VDM.viewType: #BASIC
@Analytics.dataCategory: #DIMENSION
define view zcds_folk26 as select from mara association[1..*] to makt on
mara.MATNR = MAKT.matnr {
key matnr,
mtart,
matkl,
makt.maktx
}
@AbapCatalog.sqlViewName: 'ZSQL_FOLK27'
@EndUserText.label: 'testing'
@VDM.viewType: #BASIC
@Analytics.dataCategory: #FACT
define view zcds_folk27 as select from vbak association to vbap on vbak.vbeln
= VBAP.vbeln {
key vbeln,
key vbap.posnr,
audat,
kunnr,
vbap.matnr,
vbap.kwmeng,
vbap.netwr
}
@AbapCatalog.sqlViewName: 'ZSQL_FOLK28'
@EndUserText.label: 'TESTING'
@VDM.viewType: #COMPOSITE
@Analytics.dataCategory: #CUBE
define view ZCDS_FOLK28 as select from zcds_folk27 as SO association to
zcds_folk25 as CUST on SO.kunnr = CUST.kunnr
association to
zcds_folk26 as MAT on SO.matnr = MAT.matnr {
key SO.vbeln,
key SO.posnr,
SO.audat,
SO.kunnr,
SO.matnr,
SO.kwmeng,
@AbapCatalog.sqlViewName: 'ZSQL_FOLK29'
@EndUserText.label: 'TESTING'
@VDM.viewType: #CONSUMPTION
@Analytics.query: true
define view ZCDS_FOLK29 as select from ZCDS_FOLK28 {
key vbeln,
key posnr,
audat,
kunnr,
matnr,
@DefaultAggregation: #SUM
@AnalyticsDetails.query.axis: #COLUMNS
kwmeng,
@DefaultAggregation: #SUM
@AnalyticsDetails.query.axis: #COLUMNS
netwr,
name1,
@AnalyticsDetails.query.axis: #ROWS
ort01,
@AnalyticsDetails.query.axis: #ROWS
land1,
maktx
}
If we want add rows or columns automatically in RSRT transaction, we need to add the
annotations: @AnalyticsDetails.query.axis: #ROWS / #COLUMNS
Pass the SQL view name from CDS view. Add ‘2C’ as the prefix to the SQL view name, click
on execute button.
}
implemented by method zcl_tab_fun=>get_data;
In table function we must use return parameters (CDS view consumable fields) and mention
Class name and method name which will fill the return parameters.
There is no mandatory semantics for table function and don’t provide SQL name also.
ENDMETHOD.
ENDCLASS.
}
implemented by method zcl_aoh2_amdp7=>final_output;
PUBLIC SECTION.
INTERFACES if_amdp_marker_hdb.
class-METHODS: final_output FOR TABLE FUNCTION ZAOH2_CDS24. " EXPORTING
VALUE(lt_final) type tt_final.
ENDCLASS.
);
for I in 1..lv_so_count do
LT_FINAL.client[ I ] = SEssion_context( 'CLIENT' );
LT_FINAL.VBELN[ I ] = :lt_sales.vbeln[ I ];
lt_final.posnr[ I ] = :lt_sales.posnr[ I ];
lt_final.audat[ I ] = :lt_sales.audat[ I ];
lt_final.matnr[ I ] = :lt_sales.matnr[ I ];
lt_final.kwmeng[ I ] = :lt_sales.kwmeng[ I ];
lt_final.VRKME[ I ] = :lt_sales.VRKME[ I ];
LV_VBELN = :LT_FINAL.VBELN[ I ];
LV_POSNR = :LT_FINAL.POSNR[ I ];
else
LV_DEL_COUNT = RECORD_COUNT( :LT_TEM_DEL ); -- No of recoreds
in Delivery IT
for M in 1..lv_del_count do
if M = 1 then
lt_final.del_num1[ I ] = :lt_tem_del.vbeln[ M ];
lt_final.del_item1[ I ] = :lt_tem_del.posnr[ M ];
elseif M = 2 then
lt_final.del_num2[ I ] = :lt_tem_del.vbeln[ M ];
lt_final.del_item2[ I ] = :lt_tem_del.posnr[ M ];
lt_final.del_date2[ I ] = :lt_tem_del.lfdat[ M ];
lt_final.del_qty2[ I ] = :lt_tem_del.lfimg[ M ];
lv_del_qty = lv_del_qty + :lt_tem_del.lfimg[ M ];
elseif M = 3 then
lt_final.del_num3[ I ] = :lt_tem_del.vbeln[ M ];
lt_final.del_item3[ I ] = :lt_tem_del.posnr[ M ];
lt_final.del_date3[ I ] = :lt_tem_del.lfdat[ M ];
lt_final.del_qty3[ I ] = :lt_tem_del.lfimg[ M ];
lv_del_qty = lv_del_qty + :lt_tem_del.lfimg[ M ];
end if;
end for;
lt_final.tot_del_qty[ I ] = lv_del_qty;
lt_final.pend_qty[ I ] = :lt_sales.kwmeng[ I ] - :lt_final.tot_del_qty[ I ]
;
lv_del_qty = 0;
lt_tem_del = select * from :lt_tem_del where 1 = 2;
end if;
END FOR ;
RETURN :LT_FINAL;
ENDMETHOD.
ENDCLASS.
Once the method is completed, we can use this Table Function in any number of CDS views.
@AbapCatalog.sqlViewName: 'ZAOH2_SQL25'
@EndUserText.label: 'TESTING'
define view zaoh2_cds25 as select from zaoh2_cds24{
*
}
Here I’m using ‘KUNNR’ as data element. Let me create entries for it.
I’ve given something customer name (not full name). It is displaying something in one popup
related to the input field. How it is coming. For that data element, one search help is created. Let
me check that one.
One collective search created. Click on ‘Included search helps’ tab. We can see one more search
help. Double click on that search help. It will contain one more search help.
We can see that Autosuggest in input fields check box and Multi-column full text search
(database-specific) check box selected. And Accuracy value for error-tolerant full test search is
In the search help, I’m not selecting checkboxes so that percentage is also in disable mode now.
Let me try to enter data in table level.
I’m trying to enter ‘CIP’ in customer number, it is not showing anything even though I’ve
created search help.
Here, I’m giving ‘CIP’ in customer number, it is showing related values in popup.
This is called here FUZZY SEARCH, means if we provide something input, system will check
for related values and it will show for select.
Let me provide ‘Accuracy Value for Error-Tolerant Full Text Search’ as ‘1,0’ means ‘1.0’
nothing but 100%.
I’m just giving as ‘CIP’ in the customer number. System is not showing related values here. Let
me give some more characters here.
I’ve given ‘CIPLA’ then system is showing one related value, means if we give correct word
then only it will show something output.
Search help & fuzzy or exact search is not coming for NAME1 and ORT01. If we want to apply
search help, need to create search help for it and need to create index for that field to apply fuzzy
or exact search.
Click on execute button. It will show one success message. We need to check index is created or
not for that field in table level.
Open the table click on ‘Utilities’ menu button Database Object Display
Search help is coming for NAME1 field. We have to do the above steps for ORT01 also.
Coming to Linguistic search, if we give something word like ‘DO’, then system will check for
‘DO’, ‘DID’, ‘DONE’, ‘DOING’, ‘DONOT’, ‘DID NOT’. It may search for a few more words
which meaning nearly equal to ‘DO’. This is called Linguistic Search. But in ABAP layer it is
not possible. In HANA DB we can do it.
We have one more search in in Hana database that is ‘FULL TEXT’ SEARCH.
We can see the index name and field added to the index.
Here, I’m fetching all records ZCUST_INFO1-NAME1 which will contain the letters as
‘SATHI’.
In this statement, I’ve used ‘FUZZY’. If we want to apply EXACT & LINGUISTIC we can
apply that one also here.
From 7.4
data(lv_matnr) = '123'.
In the above line lv_matnr = 123 will come the data type and length should be char3.
Because we are providing 3 characters. But I want to consider as char40(data element of
MATNR is char40) even though I pass 3 characters.
data(lv_matnr1) = new matnr( '123' ).
Here just I’m using reference of matnr. It will consider the data type and length from
MATNR data element.
data(lv_netwr) = new netwr('123.11').
Here also lv_netwr data type length should consider from NETWR data element.
From 7.4
SELECT SINGLE * FROM mara
INTO @DATA(wa_mara) WHERE matnr = '0001'.
From 7.4
SELECT matnr, mtart, meins
FROM mara
INTO TABLE @DATA(it_mara)
WHERE mtart = 'FERT'.
From 7.5
SELECT FROM mara
FIELDS matnr, mtart, meins
Here I’ve taken FIELDS <f1>, <f2> . By writing like this we have one advantage. By clicking CTRL
+ Space, it will display the fields from that table. This feature is not available before 7.5 version.
After into table <IT Name>, system will not accept where condition. If you want to give where
condition, you can give before into table <IT Name>.
4. Joins
Before 7.4
TYPES: BEGIN OF ty_materials,
matnr TYPE matnr,
mtart TYPE mtart,
maktx TYPE maktx,
spras TYPE spras,
END OF ty_materials.
DATA: it_materials TYPE TABLE OF ty_materials,
wa_materials TYPE ty_materials.
SELECT mara~matnr mara~mtart makt~maktx makt~spras
INTO TABLE it_materials
FROM mara INNER JOIN makt ON mara~matnr = makt~matnr
WHERE mara~mtart = 'FERT'
AND makt~spras = ' '.
From 7.4
SELECT mara~matnr, mara~mtart, makt~maktx, makt~spras
FROM mara INNER JOIN makt ON mara~matnr = makt~matnr
WHERE mara~mtart = @lv_mtart
AND makt~spras = @lv_spras
INTO TABLE @DATA(it_materials).
Right outer join is not possible before ABAP 7.4. From ABAP 7.4 onwards it will work. In place of
Join, keep Right Outer Join or Left Outer Join. It will work accordingly.
5. Using for all entries
Before 7.4
TYPES: BEGIN OF ty_mara,
matnr TYPE matnr,
mtart TYPE mtart,
END OF ty_mara,
BEGIN OF ty_makt,
matnr TYPE matnr,
maktx TYPE maktx,
END OF ty_makt.
DATA: it_mara TYPE TABLE OF ty_mara,
it_makt TYPE TABLE OF ty_makt.
SELECT matnr mtart FROM mara INTO TABLE it_mara
WHERE mtart = 'FERT'.
IF it_mara IS NOT INITIAL.
SELECT matnr maktx FROM makt INTO TABLE it_makt
FOR ALL ENTRIES IN it_mara
WHERE matnr = it_mara-matnr.
ENDIF.
From 7.4
DATA: lv_fert TYPE text30 VALUE 'Finished Products',
lv_halb TYPE text30 VALUE 'Semifinished Products',
lv_other TYPE text30 VALUE 'Other Material Type'.
From 7.4
TYPES: BEGIN OF ty_mara,
matnr TYPE mara-matnr,
mtart TYPE mara-mtart,
END OF ty_mara.
From 7.4
TYPES: BEGIN OF ty_mara,
matnr TYPE mara-matnr,
mtart TYPE mara-mtart,
END OF ty_mara.
DATA: it_mara TYPE TABLE OF ty_mara.
In the above syntax we have written like VALUE #(. We are declaring the internal table and using
here. If write VALUE #(, it will consider the IT_MARA structure.
For example, if we are not declaring the internal table, just filling the values like table type we
can write like this.
TYPES: BEGIN OF ty_mara,
matnr TYPE mara-matnr,
mtart TYPE mara-mtart,
END OF ty_mara.
types: tt_mara TYPE TABLE OF ty_mara WITH EMPTY KEY.
data(lt_mara) = VALUE tt_mara( ( matnr = 0001 mtart = 'FERT' )
( matnr = 0001 mtart = 'HALB' )
( matnr = 0003 mtart = 'HAWA' )
).
I’ve mentioned like VALUE TT_MARA, means we are using the structure TT_MARA.
types: tt_mara TYPE TABLE OF ty_mara WITH EMPTY KEY.
Here, we need to mention WITH EMPTY KEY at the end of that statement. Otherwise, it will
show error.
If we want to fill internal table by using different internal tables, we can follow the below syntax.
it_final = value #( for wa_mara in lt_mara where ( mtart = 'HAWA' )
FOR WA_MARD IN LT_MARD WHERE ( MATNR = WA_MARA-
MATNR )
FOR WA_MARC IN LT_MARC WHERE ( MATNR = WA_MARA-
MATNR )
( MATNR = WA_MARA-MATNR
MATKL = WA_MARA-MATKL
WERKS = WA_MARD-WERKS
LGORT = WA_MARD-LGORT
PSTAT = WA_MARC-PSTAT ) ).
If we want to get to know the index number in for loop, we can write like this.
Just assume we are filling internal table with 3 records. If try to insert into that same internal
table with a few more data, then the previous data will erase and new data will insert. To
overcome it, we can follow the below steps.
TYPES: BEGIN OF ty_mara,
matnr TYPE mara-matnr,
mtart TYPE mara-mtart,
END OF ty_mara.
types: tt_mara TYPE TABLE OF ty_mara WITH EMPTY KEY.
data(lt_mara) = VALUE tt_mara( ( matnr = 0001 mtart = 'FERT' )
( matnr = 0001 mtart = 'HALB' )
( matnr = 0003 mtart = 'HAWA' )
).
9. Move corresponding fields from one internal table to another internal table
Before 7.4
move-CORRESPONDING lt_kna1 to it_kna1.
From 7.4
Here, if the name is same in both internal tables, those data only will move.
From 7.4
types: BEGIN OF ty_kna1,
kunnr type kunnr,
xyz type char35,
end of ty_kna1.
data it_kna1 type TABLE of ty_kna1.
From 7.4
it_final = VALUE #( for ls_vbak in lt_vbak ( vbeln = ls_vbak-vbeln
audat = ls_vbak-audat
kunnr = ls_vbak-kunnr
name1 = VALUE #( lt_kna1[
kunnr = ls_vbak-kunnr ]-name1 OPTIONAL ) ) ).
From 7.4
DATA(wa_mara) = it_mara[ 2 ]. "Read index 2 from IT_MARA
Here SY-SUBRC won’t work. So we have to take as below
TRY .
DATA(wa_mara) = it_mara[ 51 ]. "Read 51 index will fail because onl
y 50 records are there
CATCH cx_sy_itab_line_not_found.
WRITE:/ 'Error Reading Record'.
ENDTRY.
WRITE:/ wa_mara-matnr.
From 7.4
TRY .
DATA(wa_mara) = it_mara[ matnr = '0001' mtart = 'FERT' ].
CATCH cx_sy_itab_line_not_found.
WRITE:/ 'Error Reading Record'.
ENDTRY.
Here we are using Try, Catch blocks. If we are not getting the data to the work area it will
through error. That is why we have used Try, Catch blocks.
If we don’t want to use this Try and Catch blocks, we can use the below syntax.
By using the above syntax, if data is not available in internal table with given condition, then it
will not go to dump
We can apply the below syntax also.
data(wa_mara2) = value #( it_mara[ 10000 ] DEFAULT abap_false ).
In the above case, if the value is not available then by defalt abap_false value will come to the
work area.
Endif.
If the value is not available, system will show sy-subrc value ‘4’ in the above case.
If we want to read a single record from internal table, we can write like this.
data(lv_matkl) = value #( lt_mara[ matnr = 'T09' ]-matkl optional ).
if lv_matkl is not INITIAL.
Endif.
From 7.4
IF line_exists( it_mara[ matnr = '0001' mtart = 'FERT' ] ).
WRITE:/ 'Records Exists'.
ENDIF.
From 7.4
data(lv_ind) = line_index( it_vbap[ vbeln = '4' ] ).
From 7.4
parameters p_vbeln type vbeln.
SELECT SINGLE @abap_true FROM vbak INTO @DATA(lv_check) WHERE vbeln = @
p_vbeln.
IF lv_check = abap_true.
ELSE.
ENDIF.
16. Sub query
Before 7.4
Before ABAP 7.4, there is no concept of sub query.
From 7.4
parameters p_kunnr type kunnr.
select vbeln, aedat, kunnr from vbak into TABLE @data(lt_vbak)
where kunnr = ( select kunnr from kna1 where kunnr = @p_kunnr ).
From 7.4
SELECT vbeln, vbtyp, kunnr
* CASE vbtyp
* WHEN 'A'
* THEN 'SO'
* WHEN 'C'
* THEN 'Inquery'
* END AS doc_type
FROM vbak INTO TABLE @DATA(it_vbak).
From 7.4
select mara~matnr,
mard~lgort,
count( mard~matnr ) as count_mat,
count( mard~werks ) as count_plant,
sum( mard~labst ) as unrest,
sum( mard~insme ) as qua_insp_stock
from mara inner join mard
on mara~matnr = mard~matnr
GROUP BY mara~matnr, mard~lgort
into TABLE @data(it_mat).
Note:
Aggregate functions are not possible with for all entries concept.
We can apply aggregate functions for one internal table with out for all entries. By using that
internal table, we can write select query and for all entries with another table.
select matnr, lgort, count_mat from @it_mat as mat_data into TABLE @data
(lt_material).
Here I’ve mentioned alias name as mat_data. It’s mandatory here. If we don’t maintain, it
will through error.
If we are working on aggregate functions, where condition will not work. Instead of that one,
we need to pass having condition.
DATA lv_kunnr TYPE kunnr.
SELECT-OPTIONS s_kunnr FOR lv_kunnr.
SELECT kunnr, SUM( netwr ) AS net_value FROM vbak
INTO TABLE @DATA(lt_vbak)
GROUP BY kunnr HAVING kunnr IN @s_kunnr.
cl_demo_output=>display(
EXPORTING
data = lt_vbap " Text or Data
).
From 7.4
data lv_kunnr type kunnr.
select-OPTIONS s_kunnr for lv_kunnr.
select kunnr,
name1,
kunnr && ':' && name1 as customer
from kna1 where kunnr in @s_kunnr into table @data(lt_kna1).
21. Concatenate variables
Before 7.4
data lv_str type char100.
concatenate lv_text lv_text1 into lv_str.
From 7.4
data(lv_text) = 'Shree Janani Foundation'.
data(lv_text1) = 'SJF'.
data(lv_op) = lv_text && lv_text1 .
data(lv_op1) = |{ 'Shree Janani' } { 'Foundation' }|.
data(lv_op2) = |{ 'Shree Janani' } { ' ' }| && lv_text1.
22. Union all in select query
Before 7.5
Before AS ABAP 7.4, there is no Union all concept. Instead of it we were using append
statement for inserting data in the same (2nd IT) internal table.
From 7.5
TABLES VBAK.
SELECT-OPTIONS S_VBELN FOR VBAK-VBELN.
SELECT FROM VBAP
FIELDS VBELN,
POSNR,
MATNR,
matkl
From 7.4
data(obj_mat1) = new zcl_material( ).
24. Internal declaration for importing data from a method
Before 7.4
data it_mara type table of mara.
obj_mat->get_mat(
EXPORTING
iv_matnr = p_matnr
IMPORTING
lt_mara = it_mara
).
From 7.4
obj_mat->get_mat(
EXPORTING
iv_matnr = p_matnr
IMPORTING
lt_mara = data(it_mara)
).
25. Type compatibility convert
Before 7.4
There is no option to convert type compatibility variable before AS ABAP 7.4
From 7.4
parameter p_matnr type char5.
data it_mara type table of mara.
obj_mat->get_mat(
EXPORTING
iv_matnr = conv #( p_matnr )
Here I’ve mentioned inner join but the functionality will work as cross join only. Because
I’ve mentioned ‘On’ condition as 1 = 1. This condition always true. So it pick the values
from both tables.
From 7.4
Cross join will pick all records from left hand side table and right hand side table.
Table1 Table2
F1 F2 F3 F4
1 000 EN Material
2 100 DE owievli
Output
F1 F2 F3 F4
1 000 EN Material
1 000 DE Owievli
2 100 EN Material
2 100 DE owievli
Requirement:
For each client display the list of possible messages.
From 7.51
DATA: BEGIN OF wa_final,
kunnr TYPE kunnr,
name1 TYPE name1,
END OF wa_final.
DATA it_final LIKE TABLE OF wa_final.
it_final = VALUE #( ( kunnr = ' 123' name1 = ' Shree Janani Foundation'
) ).
SELECT
concat( kunnr, name1 ) AS canc,
left( name1, 5 ) AS left_name1,
length( kunnr ) AS leng_kunnr,
lower( name1 ) AS low_name1,
lpad( kunnr, 10, 'A' ) AS lpad_kunnr,
ltrim( kunnr, ' ' ) AS ltrim_kunnr,
replace( kunnr, '12', 'mn' ) AS replace_kunnr,
substring( name1, 6, 6 ) AS substr_name1,
upper( name1 ) AS upper_name1,
rpad( kunnr, 10, 'M' ) AS rpad_kunnr,
rtrim( kunnr, '3' ) AS rtrim_kunnnr
FROM @it_final AS final INTO TABLE @DATA(it_final1).
28. Table Expression (change internal table value without work area)
Before 7.4
Before 7.4 this is not possible.
After 7.4
lt_kna1[ kunnr = '0010100002' ]-ort01 = 'Bangalore'.
TRY.
lt_kna1[ kunnr = '10100002' ]-ort01 = 'Bangalore' .
CATCH cx_sy_itab_line_not_found.
ENDTRY.
After 7.4
* data(lv_doc_type) = SWITCH #( ls_vbak-vbtyp when 'A' then 'Inquiry'
data(lv_doc_type) = SWITCH string( ls_vbak-
vbtyp when 'A' then 'Inquiry'
when 'B' then 'Quetation'
when 'C' then 'Order' ).
Here I’m mentioning like SWITCH STRING( ). If we don’t maintain ‘string’ here, it will
pick the first when condition data type and length for ‘lv_doc_type’. That is why I’ve
commented SWITCH #( ).
After 7.4
lt_mat = VALUE #( ( matnr = '123' mtart = 'HALB' matkl = '001' )
( matnr = '124' mtart = 'ROH' matkl = '002' )
( matnr = '125' mtart = 'FERT' matkl = '006' )
( matnr = '126' mtart = 'ROH' matkl = '009' )
( matnr = '127' mtart = 'FERT' matkl = '001' )
After 7.4
TYPES: BEGIN OF ty_std,
name TYPE char20,
marks TYPE i,
END OF ty_std.
DATA lt_std TYPE TABLE OF ty_std.
By default the ‘X’ variable will contain integer. If we want to convert with decimal, we can
write in this way.
32. Filter
Before 7.4
This option was not there before ABAP 7.4
After 7.4
data: lt_marc_all type STANDARD TABLE OF marc
with NON-UNIQUE SORTED KEY werks COMPONENTS werks,
lt_marc type STANDARD TABLE OF marc.
While declaring the internal table, we need to maintain type of standard table and uniq or non
uniq key fields we need to declare. Other wise it will throw error.
33. Condense
Before 7.4
data(lv_name1) = condense( lv_name ).
After 7.4
data(lv_name) = ' XXShree Janani FoundatioXnn '.
data(lv_name1) = condense( lv_name ).
data(lv_name2) = condense( VAL = lv_name1 del = 'X' from = 'n' to = '2'
).
If we pass condense( variable_name), then it will remove the space at starting of the variable
value and at last of the variable value.
If we pass condense( VAL = lv_name1 del = 'X' from = 'n' to = '2' ).
It will remove the space at the starting and ending of the variable value. Del = ‘X’ means it
will remove ‘X’ character from the beginning and ending of the variable (if ‘X’ is available
at beginning and ending of that variable value.
From means it will check is there any letter (From value letter) in that variable, if it is there it
will replace with ‘To’ letter. (Here letters only will modify. Not words and sentences)
From 7.4
SELECT FROM vbak
FIELDS vbeln, kunnr, vbtyp, audat, CAST( ' ' AS CHAR( 30 ) ) AS date_stat,
CAST( ' ' AS CHAR( 30 ) ) AS ord_type
WHERE vbeln IN @s_vbeln
INTO TABLE @DATA(lt_vbak).
‘LET’ is used to declare one variable in middle of program and we need to assign something
value to it.
data(lv_matnr) = '123'
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = lv_matnr
IMPORTING
OUTPUT = data(lv_matnr2).
PERFORM xyz.
PERFORM mno.
FORM xyz.
DATA(lv_kunnr) = '123'.
ENDFORM.
FORM mno.
DATA(lv_kunnr1) = lv_kunnr.
ENDFORM.
In ‘XYZ’ form, I’m declaring LV_KUNNR variable. We have to use it in that form only
we can’t use it in another form. If try to use it in out side of that form, it will through
error.
Today we have food, clothes, shelter. Because of we are employees. But lot of people don’t
have these much of facilities. I mean orphan children, handicapped children, destitute
senior citizens are suffering with minimum facilities. A few children are begging in the bus
stops, platforms... a few people will left their old age parents at bus stops also. Orphan
homes or Old age home people take care of them. They are running their organizations
without providing the food three times per day. They can provide when they have fund. In
remaining days they may provide 1 time or 2 times per day.
We are providing food, clothes, medicine, shelter to the orphanages (depend on their
requirement). We started to give training on software courses to the students & for
unemployees with free of cost. We will upload the training videos in YouTube:
https://www.youtube.com/@sathishreddymn
If you want to join with us, you can call: 9866079202 / 8332999399
General Secretary
M N Sathish Kumar Reddy
Mail id: satishkumarreddy.mn@gmail.com
Mobile: 9866079202