Download as pdf or txt
Download as pdf or txt
You are on page 1of 31

INTRODUCTION TO SQLSCRIPT

DEV161

Exercises / Solutions
Rich Heilman, SAP Labs, LLC.
Katharina Schell, SAP SE
Andreas Bader, SAP SE
DEV161

Contents

Exercise 1- Create Package & Schema ..................................................................... 3


Exercise 2- Creating Stored Procedures .................................................................... 7
Create a Simple Procedure & Execute.................................................................... 7
Parallel Processing and Parameters ..................................................................... 10
Intermediate Table Variables ................................................................................ 12
Exercise 3 – Create & Consume a Scalar Function.................................................. 14
Exercise 4 – Create & Consume a Table Function ................................................... 19
Exercise 5 – Debug a Procedure .............................................................................. 23
Exercise 6 – Anonymous Blocks .............................................................................. 28

2
DEV161

EXERCISE 1- CREATE PACKAGE & SCHEMA


The following steps are prerequisites for the next exercises.
We will …
- Access WEB IDE (steps 1-2)
- Create several packages (steps 3-7 & 13-14)
- Create a database schema (steps 8-11)
- Assign our user the necessary privileges (step 12)
- Access the reference solution (step 15)

Explanation Screenshot

1. Open the SAP HANA Web


Based Development
Workbench by entering the
following URL in the browser.

http://lt5069.wdf.sap.corp:801
0/sap/hana/ide/editor/

2. Enter your user id and


password. Enter your user id
as DEV161_XXX where XXX
is your group number. DO
NOT USE 000. The password
will be provided by the
instructor.

3. Expand the “dev161” package,


then right click on the
“exercises” package and
choose “New”, then
“Package”.

3
DEV161

4. Enter the package name as


gXXX where XXX is your
group number. DO NOT USE
g000. Enter a description and
click “Create”.

5. Next, right click on your group


package and choose “New”,
then “Package”.

6. Enter the name of the


package as “data”, and click
“Create”.

7. Right-click on the “data”


package and choose “New”,
then “File”.

4
DEV161

8. Enter the name of the file as


“HANA_DEV161_XXX.hdbsch
ema” where XXX is your group
number. DO NOT USE 000.
Click “Create”.

9. Once the editor is opened,


click the “Insert Snippet”
button.

10.Enter the name of the schema


as “HANA_DEV161_XXX”
where XXX is your group
number. DO NOT USE 000.

11.Click “Save”.

12.Click the “Assign execution


authorization” button to grant
access to the new schema.

5
DEV161

13.Next, right click on your group


package and choose “New”,
then “Package”.

14.Enter the name of the


package as “procedures”, and
click “Create”.

15. Finally, before we begin


writing code, we want to make
you aware of a solutions
webpage which contains all of
the source solutions for this
exercise document. You can
access this page via the
following URL. If you do not
wish to type the code, you
may cut/paste it from this
page.

http://lt5069.wdf.sap.corp:801
0/workshop/admin/ui/exercise
Master/index.html?workshop=
dev161

Be advised, simply blindly


cutting and pasting code will
not give you the same
experience as typing it by
hand. You will learn a lot
more by typing. However, if
you do fall behind, you are
encouraged to copy/paste, but
make sure you understand the
code before moving forward.

6
DEV161

EXERCISE 2- CREATING STORED PROCEDURES


Create a Simple Procedure & Execute

In this exercise we will create a small procedure “get_po_header_data” with two implicit SELECT
queries.

We will …
- Create an empty HDB Procedure “get_po_header_data” (steps 1-5)
- Add two implicit SELECT statements to the procedure (steps 6-8)
- Call the procedure (steps 9-12)

Explanation Screenshot

1. Right click on the “procedures”


package and choose “New”,
then “HDB Procedure”.

2. Enter the name of the


procedure as
“get_po_header_data”. Click
the drop down box for
“Schema”.

7
DEV161

3. Enter “HANA_DEV161_XXX”
(where XXX is your group
number) in the search box.
Select your schema which you
created earlier. DO NOT USE
HANA_DEV161_000. Click
“Ok”.

4. Click “Create”.

5. The editor will then be shown.

6. Between the BEGIN and END


statements, insert the
SELECT statements as
shown. These are implicit
select statements whose
results sets are passed to the
caller.

8
DEV161

7. The completed code should PROCEDURE


"HANA_DEV161_<group_number>"."dev161.exercises.g<group_num
look similar to this. ber>.procedures::get_po_header_data" ( )
LANGUAGE SQLSCRIPT
If you do not wish to type this SQL SECURITY INVOKER
code, you can reference the --DEFAULT SCHEMA <default_schema_name>
READS SQL DATA AS
solution web page at BEGIN
http://lt5069.wdf.sap.corp:801
0/workshop/admin/ui/exercise SELECT COUNT(*) AS CREATE_CNT,
Master/index.html?workshop= "HISTORY.CREATEDBY.EMPLOYEEID"
FROM
dev161 "SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO
.Header" WHERE PURCHASEORDERID IN (
SELECT PURCHASEORDERID
FROM
"sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
GROUP BY "HISTORY.CREATEDBY.EMPLOYEEID";

SELECT COUNT(*) AS CHANGE_CNT,


"HISTORY.CHANGEDBY.EMPLOYEEID"
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO
.Header" WHERE PURCHASEORDERID IN (
SELECT PURCHASEORDERID
FROM
"sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
GROUP BY "HISTORY.CHANGEDBY.EMPLOYEEID";

END

8. Save the procedure.

9. Invoke the procedure by


selecting the file and choosing
“Invoke Procedure”.

10.A new “SQL” tab is opened


which contains the CALL
statement. Click the “Run”
button.

11.The two results are then


shown in another tab.

9
DEV161

12.Take note of the execution


time. Should be around
800ms. These SQL
statements are being
executed sequentially.

Parallel Processing and Parameters

In this exercise we will modify the code of procedure “get_po_header_data” so that it takes full
advantage of the parallel processing within HANA by using table variables.

We will …
- Define two tabular output parameter that matches the result structure of the implicit queries
(steps 1-2)
- Assign the queries to the newly created output parameters (steps 3-5)
- Call the procedure (steps 6-8)

Explanation Screenshot

1. Return to your procedure


called “get_po_header_data”.

2. Define two tabular output


parameters which will be used
to explicitly pass the results of
the SELECT statements to the
caller.

3. Next, assign SELECT


statements to the output
parameters as shown here.

10
DEV161

4. The completed code should PROCEDURE


"HANA_DEV161_<group_number>"."dev161.exercises.g<group_num
be similar to this. ber>.procedures::get_po_header_data" (
OUT EX_PO_CREATE_CNT TABLE(
If you do not wish to type this CREATE_CNT INTEGER,
code, you can reference the "HISTORY.CREATEDBY.EMPLOYEEID" NVARCHAR(10)),
OUT EX_PO_CHANGE_CNT TABLE(
solution web page at CHANGE_CNT INTEGER,
http://lt5069.wdf.sap.corp:801 "HISTORY.CHANGEDBY.EMPLOYEEID" NVARCHAR(10)) )
0/workshop/admin/ui/exercise LANGUAGE SQLSCRIPT
Master/index.html?workshop= SQL SECURITY INVOKER
--DEFAULT SCHEMA <default_schema_name>
dev161 READS SQL DATA AS
BEGIN

ex_po_create_cnt = SELECT COUNT(*) AS CREATE_CNT,


"HISTORY.CREATEDBY.EMPLOYEEID"
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO
.Header" WHERE PURCHASEORDERID IN (
SELECT PURCHASEORDERID
FROM
"sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
GROUP BY "HISTORY.CREATEDBY.EMPLOYEEID";

ex_po_change_cnt = SELECT COUNT(*) AS CHANGE_CNT,


"HISTORY.CHANGEDBY.EMPLOYEEID"
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO
.Header" WHERE PURCHASEORDERID IN (
SELECT PURCHASEORDERID
FROM
"sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
GROUP BY "HISTORY.CHANGEDBY.EMPLOYEEID";

END

5. Save the procedure.

6. Next, choose “Invoke


Procedure”.

7. A new SQL tab will be


opened. Click the “Run”
button.

8. Check the execution time


again, you may notice that it is
a bit faster this time. The
reason is that these SQL
statements are now executed
in parallel.

11
DEV161

Intermediate Table Variables

In this exercise you will modify the code of procedure “get_po_header_data” again to use a single
tabular output. Existing queries will be reused based on intermediate table variables.

We will …
- Remove the existing tabular output parameters (steps 1-2)
- Add the new table output parameter to the signature of the procedure (step 3)
- Rename the existing table variables to “PO_CREATE_CNT” & “PO_CHANGE_CNT” and
enrich the queries by an alias for employee id column (steps 4-5)
- Add a query that joins employee master data with the data from the two existing table
variables and assign the result to the new output parameter
“EX_TOP_3_EMP_PO_COMBINED_CNT” (step 6)
- Call the procedure (steps 9-11)

Explanation Screenshot

1. Return to your procedure


called “get_po_header_data”.

2. Delete the output parameters


which you defined in the last
section.

3. Define a new output


parameter as shown.

12
DEV161

4. Rename
EX_PO_CREATE_CNT to
PO_CREATE_CNT. Also
rename
EX_PO_CHANGE_CNT to
PO_CHANGE_CNT.

5. Modify the two SELECT


statements and add “AS EID”
after the EMPLOYEEID field.

6. Next, add another SELECT


statement after the 2 previous
SELECT statements as
shown. This statement uses
the previously defined table
variables.

7. The completed code should PROCEDURE


"HANA_DEV161_<group_number>"."dev161.exercises.g<group_num
be very similar to this. ber>.procedures::get_po_header_data" (
OUT EX_TOP_3_EMP_PO_COMBINED_CNT TABLE(
If you do not wish to type this LOGINNAME NVARCHAR(12),
code, you can reference the CREATE_CNT INTEGER,
CHANGE_CNT INTEGER,
solution web page at COMBINED_CNT INTEGER ) )
http://lt5069.wdf.sap.corp:801 LANGUAGE SQLSCRIPT
0/workshop/admin/ui/exercise SQL SECURITY INVOKER
Master/index.html?workshop= --DEFAULT SCHEMA <default_schema_name>
READS SQL DATA AS
dev161 BEGIN

po_create_cnt = SELECT COUNT(*) AS CREATE_CNT,


"HISTORY.CREATEDBY.EMPLOYEEID" AS EID
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO
.Header" WHERE PURCHASEORDERID IN (
SELECT PURCHASEORDERID
FROM
"sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
GROUP BY "HISTORY.CREATEDBY.EMPLOYEEID";

po_change_cnt = SELECT COUNT(*) AS CHANGE_CNT,


"HISTORY.CHANGEDBY.EMPLOYEEID" AS EID
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO

13
DEV161

.Header" WHERE PURCHASEORDERID IN (


SELECT PURCHASEORDERID
FROM
"sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
GROUP BY "HISTORY.CHANGEDBY.EMPLOYEEID";

EX_TOP_3_EMP_PO_COMBINED_CNT =
SELECT emp.LOGINNAME, crcnt.CREATE_CNT,
chcnt.CHANGE_CNT, crcnt.CREATE_CNT +
chcnt.CHANGE_CNT AS COMBINED_CNT
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::MD
.Employees" as emp
LEFT OUTER JOIN :PO_CREATE_CNT AS crcnt
ON emp.EMPLOYEEID = crcnt.EID
LEFT OUTER JOIN :PO_CHANGE_CNT AS chcnt
ON emp.EMPLOYEEID = chcnt.EID
ORDER BY COMBINED_CNT DESC LIMIT 3;

END

8. Save the procedure.

9. Once again, choose “Invoke


Procedure”.

10.Click “Run”.

11.The results are then shown.

EXERCISE 3 – CREATE & CONSUME A SCALAR FUNCTION


14
DEV161

In this exercise we are creating a scalar UDF for generating a full name from the last, first and middle
name of the employee.

We will …
- Create a new package specifically for functions (steps 1-2)
- Create a scalar function “get_full_name” that uses imperative SQLScript logic to concatenate
the full name out of scalar input parameters (steps 3-6)
- Modify the procedure “get_po_header_data” by replacing the column “LOGINNAME” with our
newly created scalar function using the alias “FULLNAME” (steps 7-10)
- Call the procedure (steps 11-13)

Explanation Screenshot

1. From your group package


folder, right click and choose
“New”, then “Package”.

2. Enter the name of the


package as “functions” and
click “Create”.

3. Right click on the “functions”


folder and choose “New”, then
“File”.

15
DEV161

4. Enter the name of the file as


“get_full_name.hdbscalarfuncti
on” and click “Create”.

5. Function editor is currently FUNCTION


"HANA_DEV161_<group_number>"."dev161.exercises.g<group_num
nothing more than a text editor ber>.functions::get_full_name" (
today. So there is no IN im_firstname NVARCHAR(40) ,
templates inserted for you and IN im_middlename NVARCHAR(40),
no syntax highlighting. Enter IN im_lastname NVARCHAR(40),
IN im_employeeid NVARCHAR(10) DEFAULT '' )
the code into the editor as RETURNS ex_fullname NVARCHAR(265) AS
shown here. Make sure to BEGIN
substitute your group number
in the FUNCTION statement if :im_middlename IS NULL THEN
ex_fullname = :im_lastname || ', ' || :im_firstname;
appropriately. Please note the ELSE
default for parameter ex_fullname = :im_lastname || ', ' ||
im_employeeid which makes :im_firstname || ' ' || :im_middlename;
END IF;
assigning a value to the
parameter optional. IF :im_employeeid <> '' then
ex_fullname = :ex_fullname || '(' ||
If you do not wish to type this :im_employeeid || ')';
END IF;
code, you can reference the
solution web page at END;
http://lt5069.wdf.sap.corp:801
0/workshop/admin/ui/exercise
Master/index.html?workshop=
dev161

6. Click “Save”.

7. Return to your procedure


called “get_po_header_data”
and modify it. Start by
renaming the “LOGINNAME”
column of the output table to
“FULLNAME”. Also change
the output length to 256. This
is needed to match later on
which the anticipated output
structure.

16
DEV161

8. Change the last SELECT


statement. Remove the
LOGINNAME column from the
field list and replace it with a
call to the scalar function that
you created earlier. Make
sure to pass the NAME.FIRST
NAME.MIDDLE and
NAME.LAST name columns to
the scalar function call.

9. The completed code should PROCEDURE


"HANA_DEV161_<group_number>"."dev161.exercises.g<group_num
look very similar to this. ber>.procedures::get_po_header_data" (
OUT EX_TOP_3_EMP_PO_COMBINED_CNT TABLE(
If you do not wish to type this FULLNAME NVARCHAR(256),
code, you can reference the CREATE_CNT INTEGER,
CHANGE_CNT INTEGER,
solution web page at COMBINED_CNT INTEGER ) )
http://lt5069.wdf.sap.corp:801 LANGUAGE SQLSCRIPT
0/workshop/admin/ui/exercise SQL SECURITY INVOKER
Master/index.html?workshop= --DEFAULT SCHEMA <default_schema_name>
READS SQL DATA AS
dev161 BEGIN

po_create_cnt = SELECT COUNT(*) AS CREATE_CNT,


"HISTORY.CREATEDBY.EMPLOYEEID" AS EID
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO
.Header" WHERE PURCHASEORDERID IN (
SELECT PURCHASEORDERID
FROM
"sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
GROUP BY "HISTORY.CREATEDBY.EMPLOYEEID";

po_change_cnt = SELECT COUNT(*) AS CHANGE_CNT,


"HISTORY.CHANGEDBY.EMPLOYEEID" AS EID
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO
.Header" WHERE PURCHASEORDERID IN (
SELECT PURCHASEORDERID
FROM
"sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
GROUP BY "HISTORY.CHANGEDBY.EMPLOYEEID";

EX_TOP_3_EMP_PO_COMBINED_CNT =
SELECT
"HANA_DEV161_<group_number>"."dev161.exercises.g<group_num
ber>.functions::get_full_name"( "NAME.FIRST",
"NAME.MIDDLE", "NAME.LAST") as FULLNAME, crcnt.CREATE_CNT,
chcnt.CHANGE_CNT, crcnt.CREATE_CNT + chcnt.CHANGE_CNT AS
COMBINED_CNT
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::MD
.Employees" as emp
LEFT OUTER JOIN :PO_CREATE_CNT AS crcnt
ON emp.EMPLOYEEID = crcnt.EID
LEFT OUTER JOIN :PO_CHANGE_CNT AS chcnt
ON emp.EMPLOYEEID = chcnt.EID
ORDER BY COMBINED_CNT DESC LIMIT 3;

END

10.Click “Save”.

17
DEV161

11. Run the procedure and check


the results. Click “Invoke
Procedure”.

12. A new SQL tab will be


opened, click “Run”.

13.Notice the FULLNAME


column, it shows the results of
the scalar UDF logic.

18
DEV161

EXERCISE 4 – CREATE & CONSUME A TABLE FUNCTION


There are application and scenarios where you need a table function instead of procedure to leverage
the advantage of direct selects on the output i.e. filtering, sorting and grouping. In the following
exercise we show you how you can easily transform a procedure to a table function.

We will …
- Create a table function “get_po_counts” with a scalar input parameter “im_fdate” and tabular
return type that matches the output parameter structure of procedure “get_po_header_data”
(steps 1-3)
- Copy the logic from the body of procedure “get_po_header_data” into the table function
“get_po_counts” (step 4)
- Use the scalar input parameter “im_fdate” for filtering the column “CHANGEDAT” in the query
assigned to table variables “po_change_cnt”. The month of “CHANGEAT” should match the
month of “im_fdate”. Do similar for the column “CREATEDAT” in the query assigned to table
variables “po_create_cnt”. (step 5)
- Remove the LIMIT from the final query and rename the table variable name to
“EMP_PO_COMBINED_CNT” (steps 6-8)
- Add a query on table variable “EMP_PO_COMBINED_CNT” as return statement (steps 9-11)
- Query the TOP 3 employees by using a SELECT statement with LIMIT clause on the table
function from the catalog view of the WEB IDE (steps 12-16)

Explanation Screenshot

1. Return to the “functions”


package, and right click and
choose “New”, then “File”.

2. Enter the name of the file as


“get_po_counts.hdbtablefuncti
on”. Then click “Create”.

3. Once again, a basic text editor FUNCTION


"HANA_DEV161_<group_number>"."dev161.exercises.g<group_num
will be opened. Enter the basic ber>.functions::get_po_counts" ( im_fdate DATE )
shell of the function as shown RETURNS TABLE (EMPLOYEEID NVARCHAR(10),
here. Make sure to substitute FULLNAME NVARCHAR(256),
your group number in the CREATE_CNT INTEGER,
CHANGE_CNT INTEGER,
FUNCTION statement COMBINED_CNT INTEGER)
appropriately. Please note the AS
scalar input parameter we will BEGIN
used later on for filtering.
END;
If you do not wish to type this
code, you can reference the

19
DEV161

solution web page at


http://lt5069.wdf.sap.corp:801
0/workshop/admin/ui/exercise
Master/index.html?workshop=
dev161

4. Copy the logic from the


procedure
“get_po_header_data” into the
body of the function. Make
sure to only copy the code
between the BEGIN and END
statements.

5. Add to the WHERE clauses in


the first two SELECT
statements for filtering by
month. Month is captured
from the input parameter
im_fdate.

6. In the 3rd SELECT statement,


change the name of the
intermediate table variable to
EMP_PO_COMBINED_CNT
to match the variable name to
the semantics of the query.

7. Also add the EMPLOYEEID


column to the field list.

20
DEV161

8. Finally, remove the LIMIT


clause at the end.

9. Finally, add a RETURN


SELECT statement at the end
to mark the to be returned
result set of the function

10.The completed code should FUNCTION


"HANA_DEV161_<group_number>"."dev161.exercises.g<group_num
be very similar to this. ber>.functions::get_po_counts" ( im_fdate DATE )
RETURNS TABLE (EMPLOYEEID NVARCHAR(10),
If you do not wish to type this FULLNAME NVARCHAR(256),
code, you can reference the CREATE_CNT INTEGER,
CHANGE_CNT INTEGER,
solution web page at COMBINED_CNT INTEGER)
http://lt5069.wdf.sap.corp:801 AS
0/workshop/admin/ui/exercise BEGIN
Master/index.html?workshop=
po_create_cnt = SELECT COUNT(*) AS CREATE_CNT,
dev161 "HISTORY.CREATEDBY.EMPLOYEEID" AS EID
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO
.Header" WHERE PURCHASEORDERID IN (
SELECT PURCHASEORDERID
FROM "sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
AND MONTH("HISTORY.CREATEDAT") = MONTH(:im_fdate)
GROUP BY "HISTORY.CREATEDBY.EMPLOYEEID";

po_change_cnt = SELECT COUNT(*) AS CHANGE_CNT,


"HISTORY.CHANGEDBY.EMPLOYEEID" AS EID
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO
.Header" WHERE PURCHASEORDERID IN (
SELECT PURCHASEORDERID
FROM "sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
AND MONTH("HISTORY.CHANGEDAT") = MONTH(:im_fdate)
GROUP BY "HISTORY.CHANGEDBY.EMPLOYEEID";

EMP_PO_COMBINED_CNT =
SELECT EMPLOYEEID,

"HANA_DEV161_<group_number>"."dev161.exercises.g<group_num
ber>.functions::get_full_name"(
"NAME.FIRST", "NAME.MIDDLE", "NAME.LAST") as
FULLNAME, crcnt.CREATE_CNT,
chcnt.CHANGE_CNT, crcnt.CREATE_CNT +
chcnt.CHANGE_CNT AS COMBINED_CNT
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::MD
.Employees"
as emp
LEFT OUTER JOIN :PO_CREATE_CNT AS crcnt
ON emp.EMPLOYEEID = crcnt.EID
LEFT OUTER JOIN :PO_CHANGE_CNT AS chcnt
ON emp.EMPLOYEEID = chcnt.EID
ORDER BY COMBINED_CNT DESC ;

RETURN select * from :emp_po_combined_cnt;

END;

21
DEV161

11.Click “Save”

12. Open the catalog.

13. Click the “Open SQL console”


button.

14. Enter a SELECT statement SELECT *


FROM
for your table function. Pass "HANA_DEV161_<group_number>"."dev161.exercises.g<group_num
the date ’18.12.2014’ as the ber>.functions::get_po_counts"('18.12.2014')
input parameter. Make sure to LIMIT 3;
substitute your group number
appropriately.

If you do not wish to type this


code, you can reference the
solution web page at
http://lt5069.wdf.sap.corp:801
0/workshop/admin/ui/exercise
Master/index.html?workshop=
dev161

15. Click the “Run” button.

16. The results of your table


function are then shown.

22
DEV161

EXERCISE 5 – DEBUG A PROCEDURE


In the following exercise we will show how to debug a procedure using the SQLScript debugger. This
includes setting breakpoints, evaluating expressions and intermediate results.

We will …
- Set a breakpoint in procedure “get_po_header_data” (steps 1-2)
- Call the procedure “get_po_header_data” and stop during execution in the debugger (step 3-
5)
- Step Over and investigate intermediate variables (steps 6-9)
- Evaluate expressions (steps 10-14)
- Stepping through the procedure and resume to check the result (15-18)

Explanation Screenshot

1. Return to the procedure you


created earlier in the Editor.

2. Set breakpoints at the lines


shown here by simply clicking
on the line number.

23
DEV161

3. Click “Invoke Procedure”.

4. A new SQL tab will be


opened. Click on the “Run”
button.

5. You will notice that control is


passed back to the editor
where execution has stopped
at the first breakpoint. There
is also a debugger pane which
is displayed on the right. You
can see all of the variables
and parameters for this
procedure. You might notice
that this pane is currently not
showing the intermediate table
variables at this point.

6. Click the “Stop Over” button.

7. You will notice that execution


has continued to the next
statement. In the debugger
pane, a new local variable has
been added. This is because
it is not defined explicitly will
be implicitly declared at
runtime during first usage.

24
DEV161

8. To see the data for this


intermediate table variable,
right click on it and choose
“Display Content”.

9. A new window is then opened


showing the data in the table.
Review the data and close the
window by clicking the “X” in
the upper right hand corner.

10. Click the “Toggle Expression


Editor” button.

11. In the yellow box that appears


below, enter a SELECT
statement as shown here and
hit “Enter”.

25
DEV161

12. You will notice the expression


is then added to the
“Expressions” section above.

13. Right click on the expression


and choose “Display Content”.

14. Review the results and close


the window by clicking the “X”.

15. Once again click the “Step


Over” button. Notice the next
intermediate table variables is
also added. You can review
the data in this table as well.

26
DEV161

16. Continue to step through the


code and when execution
stops at the END statement of
the procedure, display the
contents of the output
parameter the same way you
did for the intermediate table
variables. Finally, close the
window by clicking the “X”.

17. Click the “Resume” button.

18. Execution of the procedure is


now completed. Return to the
SQL tab and check the
results.

27
DEV161

EXERCISE 6 – ANONYMOUS BLOCKS


In this exercise we will show you how you can invoke SQLScript logic without the need to create a
persistent logic container such as a procedure or function. Instead we will use so called anonymous
blocks.

We will …
- Write an empty anonymous block skeleton in the SQL console of WEB IDE’s catalog view
(steps 1-3)
- Copy the logic from the body of procedure “get_po_header_data” into the body of the
anonymous block statement (step 4)
- Make “EX_TOP_3_EMP_PO_COMBINED_CNT” an explicitly declared table variable to
ensure data type conversion as we assume our calling application can only handle string type
columns (step 5)
- Add an implicit SELECT in table variable “EX_TOP_3_EMP_PO_COMBINED_CNT” to
retrieve the desired result by executing the anonymous block (steps 6-9)

Explanation Screenshot

1. Return to the catalog, by


clicking the “Navigation Links”
button and choosing
“Catalog”.

2. Click the “SQL Console”


button.

3. To have an anonymous block DO


BEGIN
you need a do begin …end

END;

28
DEV161

4. Copy the logic from the


procedure
“get_po_header_data” into the
body. Make sure to only copy
the code between the BEGIN
and END statements.

5. Let’s assume the application


executing this block only
allows string types. Since we
have no signature for defining
this we are simply declaring
the type of the table variable
EX_TOP_3_EMP_PO_COMBI
NED_CNT. The columns will
then be implicitly converted to
the corresponding types.
Between the BEGIN statement
and the first SELECT
statement, enter a DECLARE
statement to declare an
intermediate table variable
called
EX_TOP_3_EMP_PO_COMBI
NED_CNT as shown.

6. After the last SELECT


statement and before the END
statement, insert another
SELECT against the
intermediate table variable
which you declared above.

7. The completed code should DO


BEGIN
look very similar to this.
DECLARE EX_TOP_3_EMP_PO_COMBINED_CNT TABLE (
If you do not wish to type this "FULLNAME" NVARCHAR(256),
code, you can reference the "CREATE_CNT" NVARCHAR(10),
"CHANGE_CNT" NVARCHAR(10),
solution web page at "COMBINED_CNT" NVARCHAR(10));
http://lt5069.wdf.sap.corp:801
0/workshop/admin/ui/exercise po_create_cnt = SELECT COUNT(*) AS CREATE_CNT,
Master/index.html?workshop= "HISTORY.CREATEDBY.EMPLOYEEID" AS EID
FROM
dev161 "SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO
.Header" WHERE PURCHASEORDERID IN (

29
DEV161

SELECT PURCHASEORDERID
FROM
"sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
GROUP BY "HISTORY.CREATEDBY.EMPLOYEEID";

po_change_cnt = SELECT COUNT(*) AS CHANGE_CNT,


"HISTORY.CHANGEDBY.EMPLOYEEID" AS EID
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::PO
.Header" WHERE PURCHASEORDERID IN (
SELECT PURCHASEORDERID
FROM
"sap.hana.democontent.epmNext.data::PO.Item"
WHERE "PRODUCT.PRODUCTID" IS NOT NULL)
GROUP BY "HISTORY.CHANGEDBY.EMPLOYEEID";

EX_TOP_3_EMP_PO_COMBINED_CNT =
SELECT
"HANA_DEV161_<group_number>"."dev161.exercises.g<group_num
ber>.functions::get_full_name"( "NAME.FIRST",
"NAME.MIDDLE", "NAME.LAST") as FULLNAME, crcnt.CREATE_CNT,
chcnt.CHANGE_CNT, crcnt.CREATE_CNT + chcnt.CHANGE_CNT AS
COMBINED_CNT
FROM
"SAP_HANA_EPM_NEXT"."sap.hana.democontent.epmNext.data::MD
.Employees" as emp
LEFT OUTER JOIN :PO_CREATE_CNT AS crcnt
ON emp.EMPLOYEEID = crcnt.EID
LEFT OUTER JOIN :PO_CHANGE_CNT AS chcnt
ON emp.EMPLOYEEID = chcnt.EID
ORDER BY COMBINED_CNT DESC LIMIT 3;

Select * from :EX_TOP_3_EMP_PO_COMBINED_CNT;

END;

8. Click “Run”.

9. You will notice that the


SQLScript code is executed
and results are shown. Again,
there is no procedure or
function created here, just the
SQLScript being executed by
the engine.

30
DEV161

© 2015 SAP SE or an SAP affiliate company. All rights reserved.


No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP SE or an SAP
affiliate company. SAP and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered
trademarks of SAP SE (or an SAP affiliate company) in Germany and other countries.
Please see http://www.sap.com/corporate-en/legal/copyright/index.epx#trademark for additional trademark information and notices.

31

You might also like