381 108 10MB
English Pages 430 [439]
SAP PRESS is a joint initiative of SAP and Rheinwerk Publishing. The know-how offered by SAP specialists combined with the expertise of Rheinwerk Publishing offers the reader expert books in the field. SAP PRESS features first-hand information and expert advice, and provides useful skills for professional decision-making. SAP PRESS offers a variety of books on technical and business-related topics for the SAP user. For further information, please visit our website: http://www.sap-press.com. Alborghetti, Kohlbrenner, Pattanayak, Schrank, Sboarina SAP HANA XSA: Native Development for SAP HANA 2018, 607 pages, hardcover and e-book www.sap-press.com/4500 Stefan Haas, Bince Mathew ABAP Development for SAP S/4HANA: ABAP Programming Model for SAP Fiori 2019, 461 pages, hardcover and e-book www.sap-press.com/4766 Christensen, Darlak, Harrington, Kong, Poles, Savelli SAP BW/4HANA: An Introduction 2017, 427 pages, hardcover and e-book www.sap-press.com/4377 Acharya, Bajaj, Dhar, Ghosh, Lahiri SAP Cloud Platform: Cloud-Native Development 2019, 489 pages, hardcover and e-book www.sap-press.com/4713
Jörg Brandeis
SQLScript for SAP HANA®
Dear Reader, Sometimes you have to call in the specialists. There are only a handful of people in the world that fix antique grandfather clocks. Even fewer that maintain masterpiece Stradivarius violins. There’s only one go-to resource for SQLScript for SAP HANA. Until now, this book was only available in German. We simply needed this expert resource on SQLScript available for the English-speaking audience. The author and SQLexpert himself, Jörg Brandeis, confirmed that this hotly anticipated book had SQLScript programmers clamoring for an English version. With translations come unique challenges. For this book: hand-testing all code, updating anything new, and making sure the translation from German is smooth, readable, and easily referenceable. With SQLScript for SAP HANA, you’ve got it all—the complete guide to SQLScript for SAP HANA. Your comments and suggestions are the most useful tools to help us make our books the best they can be. Please feel free to contact me and share any praise or criticism you may have. Thank you for purchasing a book from SAP PRESS! Will Jobst
Editor, SAP PRESS [email protected] www.sap-press.com Rheinwerk Publishing • Boston, MA
Notes on Usage This e-book is protected by copyright. By purchasing this e-book, you have agreed to accept and adhere to the copyrights. You are entitled to use this e-book for personal purposes. You may print and copy it, too, but also only for personal use. Sharing an electronic or printed copy with others, however, is not permitted, neither as a whole nor in parts. Of course, making them available on the Internet or in a company network is illegal as well. For detailed and legally binding usage conditions, please refer to the section Legal Notes. This e-book copy contains a digital watermark, a signature that indicates which person may use this copy:
Imprint This e-book is a publication many contributed to, specifically: Editor Will Jobst Acquisitions Editor Hareem Shafi German Edition Editor Kerstin Billen Translation Lemoine International, Inc., Salt Lake City, UT Copyeditor Yvette Chin Cover Design Graham Geary Photo Credit iStockphoto.com/602302646/© monsitj Production E-Book Graham Geary Typesetting E-Book SatzPro, Krefeld (Germany) We hope that you liked this e-book. Please share your feedback with us and read the Service Pages to find out how to contact us. The Library of Congress has cataloged the printed edition as follows: Names: Brandeis, Jörg, author. Title: SQLScript for SAP HANA / Jörg Brandeis. Other titles: SQLScript für SAP HANA. English Description: 1st edition. | Bonn ; Boston : Rheinwerk Publishing, 2019. | Translation of: SQLScript für SAP HANA. | Includes index. Identifiers: LCCN 2019001344 (print) | LCCN 2019002441 (ebook) | ISBN 9781493218233 (ebook) | ISBN 9781493218226 (alk. paper) Subjects: LCSH: SQL (Computer program language) | SAP HANA (Electronic resource) Classification: LCC QA76.73.S67 (ebook) | LCC QA76.73.S67 B7413 2019 (print) | DDC 005.75/6--dc23 LC record available at https://lccn.loc.gov/2019001344
ISBN 978-1-4932-1822-6 (print) ISBN 978-1-4932-1823-3 (e-book) ISBN 978-1-4932-1824-0 (print and e-book) © 2019 by Rheinwerk Publishing, Inc., Boston (MA) 1st edition 2019 1st German edition published 2018 by Rheinwerk Verlag, Bonn, Germany
Contents Introduction ....................................................................................................................
15
1
SAP HANA
23
1.1
What Is SAP HANA? ......................................................................................
24
1.1.1 1.1.2 1.1.3
24 29 30
1.2
SAP HANA: A Fast SQL Database ............................................... SAP HANA: An Application Server ............................................. SAP HANA: A Collection of Tools ...............................................
System Architecture .....................................................................................
32
1.2.1 1.2.2
SAP HANA Server Components .................................................. Databases and Tenants ................................................................
32 34
Organizing Database Objects ...................................................................
36
1.3.1 1.3.2 1.3.3
Database Schemas ......................................................................... Database Catalogs ......................................................................... Content and Repositories ............................................................
36 38 39
Development Environments .....................................................................
40
1.4.1 1.4.2 1.4.3
SAP HANA Studio ............................................................................ SAP HANA Web-Based Development Workbench .............. SAP Web IDE .....................................................................................
41 45 48
1.5
The SQL Console .............................................................................................
50
2
Getting Started with SQLScript
55
2.1
SQL Versus SQLScript ....................................................................................
56
2.2
Basic Language Elements ...........................................................................
59
2.2.1 2.2.2 2.2.3 2.2.4
60 60 61 62
1.3
1.4
Statements ....................................................................................... Whitespace ....................................................................................... Comments ........................................................................................ Literals ................................................................................................
7
Contents
2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.2.10 2.2.11 2.2.12 2.2.13 2.2.14
2.3
2.4
Identifiers .......................................................................................... Access to Local Variables and Parameters ............................. System Variables ............................................................................ Reserved Words .............................................................................. Operators .......................................................................................... Expressions ....................................................................................... Predicates .......................................................................................... Data Types ........................................................................................ The NULL Value ............................................................................... The DUMMY Table .........................................................................
65 67 67 68 69 72 73 73 74 76
Modularization and Logical Containers ..............................................
78
2.3.1
Blocks ..................................................................................................
80
2.3.2 2.3.3
Procedures ........................................................................................ User-Defined Functions ...............................................................
83 90
Sample Program .............................................................................................
94
2.4.1 2.4.2 2.4.3 2.4.4
Requirements .................................................................................. Requirements Analysis ................................................................. Implementation .............................................................................. Testing the Implementation .......................................................
94 95 97 104
3
Declarative Programming in SQLScript
109
3.1
Table Variables ...............................................................................................
110
3.1.1 3.1.2
Declaring Table Variables ............................................................ Using Table Variables ....................................................................
111 112
SELECT Statements ........................................................................................
112
3.2.1 3.2.2 3.2.3
SELECT Clauses ................................................................................ Field List of SELECT Clauses ......................................................... FROM Clauses ..................................................................................
113 114 130
3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9
Joins .................................................................................................... WHERE Conditions ......................................................................... WITH Clauses ................................................................................... GROUP BY Clauses .......................................................................... HAVING Clauses .............................................................................. ORDER BY Clauses ..........................................................................
132 138 147 149 152 153
3.2
8
Contents
3.2.10 3.2.11 3.2.12
3.3
4 4.1
4.2
4.3
4.4
Set Theory ......................................................................................... Subqueries ........................................................................................ Alias Names ......................................................................................
154 156 158
Other Operators .............................................................................................
160
3.3.1 3.3.2
160 161
Data Types and Their Processing
165
Character Strings ...........................................................................................
166
4.1.1 4.1.2 4.1.3
Data Types for Character Strings .............................................. Conversions ...................................................................................... Character String Functions ..........................................................
166 169 169
Date and Time .................................................................................................
185
4.2.1 4.2.2 4.2.3 4.2.4 4.2.5
Date Information ............................................................................ Time Information ........................................................................... Combined Time and Date Information ................................... Processing Time and Date Values ............................................. Examples of Processing Time Values .......................................
185 191 192 193 198
Numerical Data ...............................................................................................
201
4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.3.8
Basic Arithmetic Operations ....................................................... Square Roots and Exponents ...................................................... Logarithms ........................................................................................ Rounding or Trimming .................................................................. Trigonometry ................................................................................... Random Numbers .......................................................................... Sign ...................................................................................................... Quantities and Amounts ..............................................................
202 203 203 203 206 206 207 207
Binary Data Types ..........................................................................................
213
4.4.1
Conversion Between Binary Data, Hexadecimal Data, and Character Strings ................................................................... Bits and Bytes ...................................................................................
215 216
Conversions Between Data Types ..........................................................
218
4.4.2
4.5
Calculation Engine Plan Operators ........................................... Map Merge ........................................................................................
9
Contents
5
Write Access to the Database
221
5.1
INSERT .................................................................................................................
222
5.1.1 5.1.2
Individual Data Records ............................................................... Inserting Multiple Records Simultaneously ..........................
222 224
UPDATE ..............................................................................................................
226
5.2.1 5.2.2
Simple UPDATE Statement ......................................................... UPDATE Statement with Reference to Other Tables ..........
226 226
UPSERT or REPLACE .......................................................................................
227
5.3.1 5.3.2
Inserting or Updating Individual Data Records .................... Inserting or Updating Multiple Data Records .......................
228 229
5.4
MERGE INTO .....................................................................................................
229
5.5
DELETE .................................................................................................................
232
5.6
TRUNCATE TABLE ...........................................................................................
232
6
Imperative Programming
233
6.1
Variables ............................................................................................................
233
6.1.1 6.1.2 6.1.3 6.1.4
Local Scalar Variables .................................................................... Local Table Variables ..................................................................... Session Variables ............................................................................ Temporary Tables ...........................................................................
233 238 247 248
6.2
Flow Control Using IF and ELSE ................................................................
249
6.3
Loops ...................................................................................................................
253
6.3.1 6.3.2 6.3.3 6.3.4
FOR Loop ............................................................................................ WHILE Loop ....................................................................................... Controlling Loop Passes ............................................................... Exercise: Greatest Common Divisor .........................................
253 254 255 255
Cursors ................................................................................................................
256
6.4.1 6.4.2
257 258
5.2
5.3
6.4
10
FOR Loop via a Cursor .................................................................... Open, Read, and Close Explicitly ................................................
Contents
6.5
6.6
6.7
6.8
7
Arrays ..................................................................................................................
260
6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6
261 261 262 263 264 265
Generating an Array ...................................................................... Accessing the Array ........................................................................ Arrays as Local Variables .............................................................. Splitting and Concatenating Arrays ......................................... Arrays and Table Columns ........................................................... Bubble Sort Exercise ......................................................................
Transaction Control ......................................................................................
268
6.6.1 6.6.2
Transactions ..................................................................................... Autonomous Transactions ..........................................................
268 269
Executing Dynamic SQL ..............................................................................
271
6.7.1 6.7.2
Parameters of Dynamic SQL ....................................................... Input Parameters ............................................................................
272 274
Error Handling .................................................................................................
276
6.8.1 6.8.2 6.8.3
276 277 278
What Are Exceptions? ................................................................... Triggering Exceptions ................................................................... Catching Exceptions ......................................................................
Creating, Deleting, and Editing Database Objects
283
Tables ..................................................................................................................
284
7.1.1 7.1.2 7.1.3
Creating Database Tables ............................................................ Changing Database Tables .......................................................... Deleting Database Tables ............................................................
284 289 290
7.2
Table Types .......................................................................................................
291
7.3
Views ...................................................................................................................
291
7.4
Sequences .........................................................................................................
294
7.4.1 7.4.2 7.4.3 7.4.4 7.4.5
294 294 295 296 296
7.1
Increment .......................................................................................... Limits .................................................................................................. Behavior When Reaching the Limit .......................................... Resetting the Sequence ................................................................ Changing and Deleting a Sequence .........................................
11
Contents
7.5
8
Triggers ..............................................................................................................
296
7.5.1 7.5.2
299 299
Parameters ........................................................................................ Per Row or Per Statement ............................................................
SQLScript in ABAP Programs
301
AMDP Procedures ..........................................................................................
304
8.1.1 8.1.2 8.1.3 8.1.4 8.1.5
Creating AMDP Procedures ......................................................... Generated Objects of an AMDP Method ................................ Lifecycle of the Generated Objects ........................................... Two-Track Development .............................................................. Using AMDP Procedures in AMDP Procedures .....................
305 308 312 313 316
CDS Table Functions .....................................................................................
319
8.2.1 8.2.2 8.2.3
Creating a CDS Table Function .................................................. Generated Objects of a CDS Table Function ......................... Implicit Client Handling of CDS Table Functions .................
319 325 326
8.3
AMDP Functions for AMDP Methods ....................................................
327
8.4
Alternatives to AMDPs for Calling SQLScript Code from ABAP Programs ...............................................................................................
329
8.5
Recommendations ........................................................................................
330
9
SQLScript in SAP Business Warehouse
333
9.1
Transformation Routines as AMDP .......................................................
338
9.2
Successive Transformations and Mixed Execution ........................
339
The Generated AMDP Classes ..................................................................
341
9.3.1 9.3.2 9.3.3
Signature of AMDP Methods ...................................................... Assigning the Output Tables ...................................................... Access to Data from Other Data Models ................................
342 344 345
The Individual Routines ..............................................................................
348
9.4.1 9.4.2
348 349
8.1
8.2
9.3
9.4
12
Start Routines .................................................................................. End Routines ....................................................................................
Contents
9.4.3 9.4.4
9.5
Expert Routines ............................................................................... Field Routines ...................................................................................
350 351
Error Processing and Error Stack .............................................................
352
9.5.1 9.5.2 9.5.3
353 354
Processing Flow in the Data Transfer Process ...................... Example: Recognizing Incorrect Data in Table OUTTAB ... Example: Finding Invalid Field Contents with Regular Expressions .......................................................................
355
10 Clean SQLScript Code
357
10.1 The Readability of the Code ......................................................................
358
10.1.1 10.1.2 10.1.3 10.1.4 10.1.5 10.1.6
Formatting the Code ..................................................................... Mnemonic Names .......................................................................... Granularity of Procedures and Functions ............................... Comments ........................................................................................ Decomposing Complex Queries ................................................ Readable SQLScript Statements ................................................
10.2 Performance Recommendations ............................................................ 10.2.1 10.2.2 10.2.3 10.2.4
Reducing Data Volumes ............................................................... Avoid Switching Between Row and Column Engines ........ Declarative Queries ........................................................................ Scalar Functions ..............................................................................
358 359 361 364 366 371 373 373 373 373 374
11 Tests, Errors, and Performance Analysis
375
11.1 Testing SQLScript Code ...............................................................................
376
11.1.1 11.1.2 11.1.3
SQL Console ...................................................................................... Testing ABAP Managed Database Procedure Methods ..... The TRACE Statement ...................................................................
376 378 380
11.2 The Debugger for SQLScript ......................................................................
381
11.2.1 11.2.2
The SAP HANA Web-Based Development Workbench Debugger ........................................................................................... SQLScript Debugger in SAP HANA Studio ...............................
381 387
13
Contents
11.2.3 11.2.4
AMDP Debugger in the ABAP Development Tools .............. Debugging in the SAP Web IDE ..................................................
391 394
11.3 Performance Analysis ..................................................................................
397
11.3.1 11.3.2 11.3.3 11.3.4 11.3.5 11.3.6
Runtime Measurement ................................................................ Execution Plan ................................................................................. Performance Analysis in the SAP HANA Web-Based Development Workbench ............................................................ PlanViz ................................................................................................ SQL Analyzer of the Database Explorer of the SAP Web IDE ..................................................................................... SQLScript Code Analyzer ..............................................................
397 399 400 402 410 412
Appendices
417
A
Data Model for Task Management ........................................................
419
B
List of Abbreviations ....................................................................................
423
C
The Author ........................................................................................................
425
Index ..................................................................................................................................
427
Service Pages ........................................................................................................... Legal Notes ...............................................................................................................
I II
14
0
Introduction
SAP presented the SAP HANA database to the public in 2010. The SQLScript programming language is the associated “SQL dialect” that you can use to send queries to SAP HANA. This dialect has been part of SAP HANA from the very beginning. However, at least in August 2018, when the German edition of this book was written, no textbook for this language was available in print. We would like to close this gap with this work. You may think enough information is available on the internet these days. So, why would you need a book? In fact, we have gathered almost all the knowledge you’ll find over the next 400 pages either on the internet or by working with different SAP HANA systems ourselves. To some extent, we’ve also received information through exchanges with colleagues or SAP employees. So why a book? Anyone can search for the relevant information on the internet and learn through their own experiences with the system. The most important source of information about SQLScript on the internet are the reference documentations provided by SAP (the "SAP HANA SQLScript Reference" found at http://bit.ly/1822_001, and the "SAP HANA SQL and System Views Reference" found at http://bit.ly/1822_002). The documentation contains a great deal of detail, but it lacks a suitable structure that a textbook would have. The reference documents are intended as reference works and serve an important function, but this documentation is of little use for systematic learning. The other important resources on the internet are blogs and forums, which reflect the experiences of many users of the SQLScript language. Accordingly, a great deal of useful and interesting information can be found at these sites, some of which might be missing from the reference documentation. However, the quality of these contributions varies greatly. Some authors provide really high-quality content, while others present, for example, their mediocre workarounds for solving a problem. Accordingly, you’ll have to question everything you read and try things out on your own system. Blogs and forums also lack a structure suitable for learning a language. So what distinguishes this book, apart from its physical existence as a pile of paper, from the freely accessible sources on the internet?
15
Why a book?
Introduction
쐍 A single source, not hundreds
If you’re looking for something, you’ll find the corresponding topic in the table of contents or index. 쐍 Structure
As a textbook, you can work through the book from cover to cover. 쐍 Quality
All examples have been tested, and all information has been checked on real systems. Target audience
This book is conceived as a textbook. Consequently, you don’t need any previous knowledge of the SAP HANA database or of SQLScript. Nevertheless, the book is not intended for laymen. We will assume that you already have experience with programming and that you are also familiar with SQL. You can’t develop an application only using the SQLScript language. However, every reader will have a use case in mind for using this language. Several platforms come into consideration for this, such as: 쐍 SAP Business Warehouse (SAP BW) in which transformation logic will be
stored in SQLScript routines 쐍 An SAP ERP or SAP NetWeaver system on which SQLScript will be used in
ABAP Managed Database Procedure (AMDP) methods from within ABAP 쐍 Native SAP HANA applications that run on the SAP HANA XS or XSA
application server 쐍 Applications based on non-SAP systems that access the SAP HANA data-
base via the SQL interface Correspondingly, we have compiled the relevant information for all these different applications in this book. We have also dedicated a separate chapter to each of the first two cases. If you do not work with SAP BW or do not program on the SAP NetWeaver application server, you can skip these chapters. Test system
To work through this book, you should have access to an SAP HANA database yourself. Being able to do the work yourself can be helpful for understanding the examples. Ideally, you already have access to an SAP HANA database for development in your company. If not, it’s not a problem. Several options are now available for obtaining simple and cost-effective access to an SAP HANA database. For example, they may consider the following options:
16
Introduction
쐍 A database of your own on a multitenant database system on the SAP
Cloud Platform 쐍 The local installation of SAP HANA, Express Edition, on your machine 쐍 Starting a virtual machine with preinstalled SAP HANA, Express Edition,
on the Google Cloud Platform All three options are free with certain restrictions. Nevertheless, they are completely sufficient for learning purposes. For all the examples found in the listings, we recommend that you try them out on your own system and check the result. Some examples have been selected in such a way that they highlight the limits of a specific function or show some unexpected behavior. Modifying these examples or developing your own examples can also be quite instructive. The listings will generally be structured in such a way that they can be executed directly in the SQL console and will also remove the database objects they generate. For example, database tables created with CREATE TABLE XY are deleted at the end of a listing via the DROP TABLE XY command. Thus, the examples can be executed as often as needed without impacting each other. Many examples are also based on a simple data model that we designed for this book, described in detail in Appendix A. This data model is a small task management tool for several projects with different teams. You can install this demo data model, together with some test data as a script, onto your own system. You can download the necessary files from the book’s website at https://www.sap-press.com/4862 under Product supplements. Alternatively, you can find these examples on GitHub at https://github.com/captainabap/SQLScript_for_SAP_HANA. We’ve tried to format the source code in the examples as consistently as possible. In this respect, the focus is on readability. The relevant passages and some comments are highlighted in bold type. For the naming of parameters and variables, we have created a variant of the Hungarian notation in the form of a two-digit prefix. The first digit indicates whether it is a local variable (L), an IN parameter (I), an OUT parameter (O), or a RETURN parameter (R). The second digit determines whether the value is a scalar value (V) or a table (T).
17
Source code
Introduction
This notation corresponds to a schema often used in ABAP. Some examples include the following: 쐍 lt_var is a local table variable. 쐍 iv_counter is a scalar IN parameter. 쐍 ot_result is an OUT table parameter.
The notation used in this book is not a standard, but we think it will be rather useful. In any case, for better readability of the source code in this book, the notation is definitely helpful. All keywords in SQLScript and all SQL functions are written in uppercase letters; the identifiers, in lowercase letters. This approach corresponds to the frequently used layout found in the Pretty Printer for ABAP.
Structure of the Book SAP HANA
Chapter 1 deals with SAP HANA, not only its use as a column-based, inmemory database, but also using SAP HANA as an application server. You’ll also learn about the different development environments, the organization of the development objects in the database catalog, and the SQL console.
Getting started with SQLScript
Chapter 2 introduces the basics of the SQLScript language. At first, this chapter may sound rather dull because the formal aspects of the language are discussed. However, we’ll turn to the topic of logical containers and jump into the deep end with (anonymous) blocks, procedures, and functions. We’ll then use these elements in our first comprehensive example, which depicts the modularization techniques and a structured procedure for the development of SQLScript functions and procedures.
Declarative programming in SQLScript
Chapter 3 describes how you can write declarative SQLScript queries. In other words, you, as the developer of the database, will use your source code to determine what data you need. The order in which the execution takes place and how this process be optimized are left to the database. Thus, a major focus in this chapter is on the well-known SELECT statement. Even if you already know this statement, taking another look in the chapter is worthwhile. Especially for ABAP developers, who may so far only be working with Open SQL, a great deal of useful information is offered in this chapter, including the concept of an expression, which doesn’t occur in this form in ABAP.
18
Structure of the Book
Chapter 4 deals with the different data types for character strings and for date, time, timestamp, and numeric data. Many helpful SQL functions are available for these data types that can be used in expressions of SQLScript statements in a wide variety of contexts.
Data types and their processing
Chapter 5 introduces SQL statements for write access to the database. In contrast to the declarative statements used up to this point, these statements are referred to as imperative code. In other words, you’ll tell the database step by step what to do and in what order.
Write access to the database
Chapter 6 deals mainly with sequence control via loops and conditions. But also topics like dynamic SQL, transaction control, and error handling are discussed in this chapter.
Imperative programming
The creation, modification, and deletion of database objects with SQLScript is the subject of Chapter 7. Even if you don’t need these statements in your applications, they can be a great help for testing purposes and practical exercises. Among other things, you’ll also learn the concepts of sequences and triggers, which can play a role in the development of database-related applications.
Creating, deleting, and editing database objects
Chapter 8 describes how you can use SAP HANA database objects, in particular SQLScript procedures and user-defined functions (UDFs) from within the ABAP programming language. You’ll learn about the AMDP framework, which takes care of many aspects, such as the transport and authorizations of the associated objects.
SQLScript in ABAP programs
The use of SQLScript in the SAP Business Warehouse (SAP BW) is the subject of Chapter 9. The use of AMDPs plays a decisive role in this scenario, since they can be used to implement transformation routines in SAP BW.
SQLScript in SAP Business Warehouse
Chapter 10 is dedicated to the topic of writing clean SQLScript code, i.e., code that meets specific quality requirements, for example, high performing, maintainable, and reusable.
Clean SQLScript code
Finally, Chapter 11 deals with testing and analyzing your development objects. In this context, you’ll get to know the various debuggers found in the different development environments, which can provide insight into a program’s flow. With regard to the optimization of runtime problems, we’ll discuss the tools available for analyzing and visualizing the execution plan of SQLScript statements.
Tests, errors, and performance analysis
19
Introduction
Appendix A describes the demo data model that we refer to repeatedly in this book. We recommend you install the data model on your system for testing purposes so that you can follow along with all our examples. To convey information in the best possible way, not only do we use many listing examples and illustrations in this book, but also boxes with further information, which are marked with different icons:
Tip Boxes marked with this icon provide recommendations for settings or offer tips from professional experiences.
Note This icon indicates that additional information is provided.
Warning With this icon, we have marked warnings and common pitfalls.
Acknowledgments For a variety of reasons, I would like to thank everyone who contributed directly or indirectly to the creation of this book: 쐍 Professor Guido Moerkotte, who taught me the basics of databases and
SQL in his lectures. He also suggested the three most important properties of databases to us students: Performance, performance, performance! 쐍 Thanks to all my customers who allowed me to work on exciting projects
where I learned a lot about SQLScript and SAP HANA databases. My customers also gave me the time and flexibility to write this book! 쐍 I’d also like to thank my colleagues and friends with whom I’ve discussed
many aspects of this book and from whom I received valuable feedback.
20
Acknowledgments
쐍 A big “thank you” goes to the authors of the many blogs and forums
dealing with the topics found in this book. You have given me a great deal of useful information! 쐍 Thanks as well to the employees at Rheinwerk Publishing, in particular
Kerstin Billen, Janina Karrasch, Hareem Shafi, and Will Jobst for their great support. And last but not least, I would like to thank Bettina, Julia, and Henrik for their patience and support. A big thank you to all of you! I couldn’t have done it without you.
Jörg Brandeis SAP Consulting & Development www.brandeis.de
21
Chapter 1 SAP HANA The SAP HANA platform is both a database and an application platform. Before we jump into the SQLScript language in the following chapters, let’s first look at SAP HANA as a whole.
With the SAP HANA database, SAP has made performance a top priority—a welcome development because long runtimes have always been a nuisance when using the software. Sometimes, more complex tasks or reports required several minutes! The SAP HANA database achieves excellent performance through leveraging concepts such as in-memory computing and column-based storage in database tables. The SAP NetWeaver ABAP platform has been enhanced to better leverage these technologies. Enhancements include, for example, the ABAP Managed Database Procedure (AMDP) framework, which allows you to call SQLScript procedures directly from within ABAP code, and core data services (CDS), which can now be used to model complex views on an SAP NetWeaver system. In addition, Open SQL, an elementary component of the ABAP language, has been enhanced with some important features. These changes have also been used to optimize classic SAP applications specifically for SAP HANA. SAP S/4HANA and SAP BW/4HANA are two variants of the SAP ERP system and the SAP Business Warehouse (SAP BW), which have been specially adapted for use with SAP HANA. In this chapter, we’ll provide an overview of SAP HANA. Section 1.1 deals with the question: What is SAP HANA? Is SAP HANA just a fast relational database, or is there even more behind it? Then, we’ll briefly discuss the system architecture and installation options in Section 1.2. When developing on SAP HANA, a distinction is made between design time objects and runtime objects. Section 1.3 describes how these two categories of objects are organized in SAP HANA.
23
Chapter overview
1
SAP HANA
Currently, three different development environments for developing applications on the SAP HANA database are available. For most of the examples in this book, only an SQL console is needed. The SQL console is a core component of all development environments. Section 1.4 provides an overview of the different development environments available, while Section 1.5 focuses on the SQL console. Through simple examples, we’ll demonstrate how you can use the SQL console.
1.1 What Is SAP HANA? SAP HANA, as both a database and platform for application development, contains many practical tools to map all possible application cases. We’ll describe these different aspects in the following sections.
1.1.1 SAP HANA: A Fast SQL Database The acronym “HANA” originally stood for High Performance Analytic Appliance. SAP HANA is a column-based relational database working with inmemory technology. In this section, we’ll briefly describe the most important technologies that contribute to SAP HANA’s performance.
Column-Based Storage Column store
In SAP HANA, most data is stored in the column store. In other words, all the data in a column is stored together in the same place. Figure 1.2 shows an example of how the data shown in Figure 1.1 can be stored column by column. ID 1 2 3 4 5 6 7
First name Peter Paul Sibylle Sigmar Siglinde Petra Klaus
Last name Müller Maier Müller Schmidt Fischer Becker Weber
Room A12 A12 A3 A3 A12 C1 A3
Department DEVELOPMENT DEVELOPMENT CONSULTING SUPPORT DEVELOPMENT SALES SUPPORT
Figure 1.1 Table with Sample Data
24
1.1
ID
First name
Last name
Room
Index Value 1 1 2 2 3 3 4 4 5 5 6 6 7 7
Index 1 2 3 4 5 6 7
Index 1 2 3 4 5 6 7
Index 1 2 3 4 5 6 7
Value Peter Paul Sibylle Sigmar Siglinde Petra Klaus
Value Müller Maier Müller Schmidt Fischer Becker Weber
What Is SAP HANA?
Department Value A12 A12 A3 A3 A12 C1 A3
Index 1 2 3 4 5 6 7
Value DEVELOPMENT DEVELOPMENT CONSULTING SUPPORT DEVELOPMENT SALES SUPPORT
Figure 1.2 Column-Based Storage of Data from Figure 1.1
Most operations can be performed much more quickly on individual columns than on an entire table. For example, aggregate functions only need the data of a single column. Another advantage of column-based storage is that each column can act as an index. When selecting column values, you do not have to search the entire table, only this one column. Memory consumption is also considerably lower with column-based storage, since efficient compression is carried out for each individual column. Because of these advantages, SAP recommends that tables be stored in the column store. You can find additional information on the column store and row store storage types in SAP Note 2222277.
In-Memory Technology Naturally, a database is faster if the data doesn’t first have to be read from a hard disk. Accessing the main memory is about 30 to 40 times faster than reading an SSD disk. Further, if the data is located in the CPU cache, this factor is about 10 times higher. However, using in-memory technology has two serious disadvantages: 쐍 The costs for main memory are considerably higher than for hard disk
storage. On the one hand, this problem is mitigated by perpetually lower hardware prices; on the other hand, the compression of data (see the next section) reduces the amount of main memory required. 쐍 In the event of a power or hardware failure, the data is immediately
erased from memory. Unlike the in-memory approaches of other databases, data in SAP HANA is not stored in parallel on the hard disk, and
25
Disadvantages of inmemory technology
1
SAP HANA
therefore, a different concept is necessary. SAP relies on a combination of savepoints, which regularly write the contents of the main memory to the hard disk, and the transaction log, which records all database access that modifies the data. If the database is restarted, the last savepoint is loaded, and all subsequent changes are loaded from the transaction log. This approach ensures the data is persistent and consistent at all times. In-memory technology not only allows for faster read operations, because the data doesn’t need be copied to the main memory first; the write operations are also considerably more efficient partly by alleviating the need to create additional indexes.
Compression Data is compressed column by column. No complex algorithms are used, such as the well-known Zip method. Instead, several simple compression types are used, each allowing very efficient packing and unpacking. The standard algorithm is the dictionary compression, where each occurring value in a column is assigned a numeric key as a 4-byte integer, as shown in Figure 1.3. Only these value keys need be stored in the column. This method already achieves good compression rates for most columns. Figure 1.3 shows an example of this procedure. High compression rates can be achieved, especially for columns with few different characteristics.
Department Index 1 2 3 4 5 6 7
Value DEVELOPMENT DEVELOPMENT CONSULTING SUPPORT DEVELOPMENT SALES SUPPORT
Dictionary for departments
Departments compressed
Key
Index
1 2 3 4
Value DEVELOPMENT CONSULTING SUPPORT SALES
Key 1 2 3 4 5 6 7
1 1 2 3 1 4 3
Figure 1.3 Example of Dictionary Compression CPU load during packing and unpacking
One disadvantage is the CPU load during packing and unpacking, which can be mitigated by two strategies:
26
1.1
What Is SAP HANA?
쐍 The data is only compressed during the delta merge operation (described
in the next subsection). This process could happen concurrently with other insertion and reading operations, thus reducing its impact on the applications running. 쐍 Unpacking only takes place for columns that are actually required. For
example, for a join, only the columns relevant to the join condition will initially be unpacked. As a result, the relevant data records for the result can be determined quickly, while the other columns can be read later. These columns must then also be unpacked. However, this task can be distributed quite well across multiple processors working in parallel. Figure 11.27 later in this book shows an example of the different plan operators of a database for a simple join. The plan operator JERequestedAttributes reads the corresponding attributes, which are then merged by JEAssembleResults to form a result row. For descriptions of the different compression methods and further background information on this topic, see SAP Note 2112604.
Insert-Only The SAP HANA database uses the insert-only approach for all modifying operations. This approach doesn’t mean that updating or deleting records is impossible. But existing records in the main storage are not changed during write operations. This memory area is optimized for read access and low memory consumption, and therefore, changes would be relatively expensive. Instead, changes are recording in the delta storage, shown in Figure 1.4, an additional memory area optimized for write access. The data found in the delta storage is uncompressed. New data is inserted directly into the delta storage. When data is to be deleted, this data is marked for deletion in the main or delta storage. When an existing record is changed, the original record is marked for deletion, and a new record is written to the delta storage.
Delta storage
The delta merge operation writes the changes recorded in the delta storage back to the data in main storage. This operation also removes data records flagged for deletion, and only one valid version of a data record remains in the main storage. The delta storage is empty after the delta merge operation.
Delta merge
27
1
SAP HANA
The delta merge operation is normally triggered automatically depending on how the database is configured. For data transfer processes (DTPs) in SAP BW, you can configure an explicit delta merge after execution.
Table Column 1
Column N
Main Storage
Main Storage
Read
Delta Merge
Delta Storage
Delta Merge
Delta Storage
Write
Figure 1.4 Operations on Main and Delta Storage Information about the table status
Use the M_CS_TABLES and M_CS_COLUMNS views to display the current status of a table or its columns. These views allow you to see, for example, how much data is currently in the delta and main storage. For more information on the delta merge procedure, see the document “How To – Delta Merge for SAP HANA and SAP BW powered by SAP HANA” at http://bit.ly/1822_101.
A Combination of Techniques The four techniques we’ve described so far complement each other perfectly and reconcile each other’s weaknesses: 쐍 The column-based storage method enables good compression of the
data. 쐍 This compression in turn reduces memory consumption, so that less
main memory is needed.
28
1.1
What Is SAP HANA?
쐍 The insert-only approach, with occasional delta merge operations,
means that the compression of the data doesn’t affect the applications running. 쐍 Last but not least, a high-performance database allows you to dispense
with additional indexes, aggregates, and materialized views, further reducing your main memory requirements. A combination of these techniques makes SAP HANA a powerful database. For more information about these techniques, refer to the SAP Notes mentioned earlier and the blog by Werner Daehn (http://s-prs.de/v620800).
1.1.2 SAP HANA: An Application Server Over time, the SAP HANA database has been enhanced by SAP HANA extended application services (SAP HANA XS) into a full-fledged application server for data-centered web applications. SAP HANA extended application services, advanced model (SAP HANA XSA), is the successor of SAP HANA XS, which has been renamed to SAP HANA XS, classic model.
SAP Note 2465027 With the introduction of SAP HANA 2.0 SPS 02, SAP HANA XS has been officially deprecated. Instead, only SAP HANA XSA will be used in the future. SAP Note 2465027 is outdated also states that the use of analytic views and deployment via the SAP HANA Repository have deprecated.
Note that SAP HANA XSA is not a newer version of SAP HANA XS. The application server was completely redeveloped and runs completely independently and concurrently to SAP HANA XS, classic model. The most important difference between SAP HANA XS and SAP HANA XSA is that the SAP HANA XSA architecture provides a runtime platform for different runtime environments. As a result, you can run JavaScript applications with Node.js while at the same time having Java applications running on Tomcat. In fact, SAP HANA XSA even implements the Bring Your Own Language (BYOL) concept, which allows for a large number of different languages. For example, a Python runtime environment has been available since the release of SAP HANA 2.0 SPS 03.
29
Differences between SAP HANA XS and SAP HANA XSA
1
SAP HANA
The individual runtime environments run independently of each other. An encapsulated copy of the runtime is created for each instance of an application, which prevents different applications from affecting each other. This segregation improves the scalability of the SAP HANA XSA architecture.
SAPUI5 and OpenUI5 Through SAPUI5, SAP provides a comprehensive JavaScript framework for creating web interfaces. This framework is also referred to as OpenUI5 and is available free of charge as an open source variant under the Apache license. Not only can you use the SAPUI5 framework on SAP HANA. SAPUI5 is also available on the current SAP NetWeaver and SAP ERP systems, where it is used to implement SAP Fiori apps.
OData The OData protocol is an HTTP-based protocol for accessing data using Create, Read, Update, and Delete (CRUD) operations. As a result, the OData log is particularly suitable for collaboration with a database. SAPUI5 components can consume OData services.
SAP HANA Deployment Infrastructure Containers Along with SAP HANA XSA, the concept of SAP HANA Deployment Infrastructure (HDI) containers was introduced. HDI containers bundle different development objects into a single package. A special feature of the HDI containers is that they aren’t bound to a specific schema and that all dependencies to other database objects are implemented using aliases. Thus, an HDI container can be installed several times in different schemes.
1.1.3 SAP HANA: A Collection of Tools SAP HANA contains a number of special functions that aren’t necessarily part of the core of a relational database. For business applications, however, these functions provide interesting opportunities, which we’ll discuss next.
30
1.1
What Is SAP HANA?
Geodata The SAP HANA database provides extensive functions for the real-time processing of geographical data. For this purpose, special data types are used that are suitable for the two-dimensional storage of points and geometric objects. This data can then be used to perform calculations in SQLScript based on a corresponding reference system, for example, a flat plane or the curved surface of the globe. For more information on this topic, see the SAP document “SAP HANA Spatial Reference” at http://bit.ly/1882_102.
Search and Text Analysis A full-fledged search engine is built into the SAP HANA database, enabling searches similar to what we’re used to from the internet. In addition to selecting data in a normal SELECT ... WHERE statement, the SAP HANA search function can also handle fuzzy search methods, with the following options: 쐍 A linguistic search finds words that have the same root. 쐍 An error-tolerant search finds words that are similar but not exact, which
might occur, for example, with typos. 쐍 A semantic search finds words with similar meanings.
Text analyses of unstructured data, such as continuous text and text mining, are also possible. For additional information on these activities, refer to “SAP HANA Text Analysis Developer Guide” found at http://bit.ly/1822_103.
Graph Processing The SAP HANA database contains a specific graph engine for the real-time processing of data available as graphs. This engine provides a set of algorithms for the analysis of graphs, including: 쐍 Width search 쐍 Shortest distance 쐍 Determination of strong interrelationship components
With GraphScript, a separate query language is available for the analysis of graphs. As an introduction to graph processing, we recommend the SAP document, “SAP HANA Graph Reference” found at http://bit.ly/1822_104.
31
SAP HANA as a search engine
1
SAP HANA
Predictive Analytics SAP HANA is also promoted by SAP as a predictive analytics platform (PAL). The predictive analysis library included with SAP HANA contains many algorithms for statistics and analysis. In addition, the automated predictive library (APL) enables the use of machine learning. For statistical calculations, the R programming language can be used as well.
1.2 System Architecture Originally, SAP HANA was sold as an appliance, that is, as a combination of hardware and software to ensure that only SAP-certified, high-quality hardware was used. However, SAP HANA can also be run on other hardware provided this hardware meets system requirements. Hardware requirements
At a minimum, the SAP HANA, express edition, can be installed on almost any system with sufficient main memory. Main memory is, of course, the most important parameter in an in-memory database. The smallest SAP HANA, express edition, installations require at least 8 GB, but almost no upper limits exist. The necessary memory requirement is initially measured according to the data volume to be stored. In addition, however, memory will be required to store temporary data for administration and queries. For more detail on memory usage, see the SAP document “SAP HANA Memory Usage Explained” found at http://bit.ly/1822_105.
1.2.1 SAP HANA Server Components An SAP HANA system consists of several server components, each of which manages different tasks, as shown in Figure 1.5. Let's take a look at the most important components: 쐍 Index server
The index server, the core of the database, contains the actual data and the components necessary for processing the data. Accordingly, the index server manages and processes all SQL queries. 쐍 Name server
The name server plays an important role in distributed SAP HANA systems by containing the information about which components are running where and where the relevant data is located.
32
1.2
HTTP
OData
JDBC
ODBC
BICS
System Architecture
MDX Interfaces
SQL Processor
OLAP Processor
MDX Processor
SQLScript
SQL Optimizer and Plan Generator SAP HANA XSA Platform
Spatial Engine
Graph Engine
Search Engine
Planning Engine
Row Engine
Calculation Engine
OLAP Engine
Join Engine
Functions Types Sequences Triggers
Runtime
Functions Procedures
SAP HANA XS Classic Engine
SDS SDI SDA
CDS Views Calculation Views Catalog Objects
Row Store
Data Provisioning
Column Store Stores SAP HANA Database
Figure 1.5 Overview of the Server Components of an SAP HANA System 쐍 SAP HANA XS and SAP HANA XSA server
SAP HANA XS and SAP HANA XSA are two complete application servers for web applications. The development environments, the SAP Web IDE and the SAP HANA Web-Based Development Workbench, are both applications that run on these application servers. 쐍 HDI server
The HDI server distributes design time and runtime objects in the database. 쐍 Extended store server
The extended store server includes additional disk space as a column store, if needed.
33
1
SAP HANA
쐍 Data provisioning server
The data provisioning server is needed for connecting external sources via smart data integration (SDI). 쐍 Streaming cluster
Rea-time data that is constantly updated can be processed via smart data streaming (SDS). For this purpose, the streaming cluster is required.
1.2.2 Databases and Tenants If more than one database is needed, different options are available. You can either install several single container database systems or one multicontainer database system.
Tenants and Clients SAP systems have supported the client capability concept for a long time. Under this concept, an ERP system can keep the data of several legally independent companies in the same system, for example, by using an additional key field (for example, MANDT) in all Customizing and application tables. This field is automatically evaluated or filled out by the system so that the developer doesn’t have to worry about client capability. As a result, users in each client can only see and change the data that belongs to their client, even though all programs and database tables exist for all clients. In contrast, the tenancy concept in SAP HANA isolates the data and data models by means of separate databases. Each of these databases runs its own index server, which holds the data. As a result, the data models on the individual tenants can also differ. In addition, user data and authorizations for each tenant are completely separated.
Single Container Database The SAP HANA system of a single container database contains exactly one database. Furthermore, the system contains all necessary server components and runs independently from other databases. Multiple single container database systems can be installed on one physical host.
34
1.2
System Architecture
Multicontainer Databases Contrary to the single container database, you can also run several separate databases simultaneously on one SAP HANA system. In that case, the individual databases are managed in what are called multitenant database containers (MDCs). In a multitenant installation, there is always one system database. This database contains a name server, a web dispatcher, and the other server components that don’t store data. These components can be used by the tenant databases.
System database
The individual tenant database containers contain only the index server. All other components that don’t store any persistent data themselves are used from the system database. Applications that communicate via SQL can connect directly to the relevant tenant database.
Tenant databases
These different installation options and the division between the system database and the tenant databases are reflected in the dialog box for connecting a system containing the SAP HANA Studio (as shown in Figure 1.6) development environment. We’ll introduce the SAP HANA Studio in Section 1.4.1.
Figure 1.6 Login Options for Multitenant Databases
35
1
SAP HANA
1.3 Organizing Database Objects Development objects in an SAP HANA database fall into two distinct categories: database objects and repository objects. Database objects are, for example, tables, views, column views, procedures, functions, or triggers. Most repository objects are text files, which are used to generate database objects. For some of these text files there are special editors. For example, the XML files of a calculation view can be edited within a graphical editor, where the connections between the tables and nodes can be edited. When the file is activated, a column view is generated as the corresponding database object.
1.3.1 Database Schemas All database objects in a database are assigned to a database schema, which serves different organizational functions. Database schema as namespace
On the one hand, a database scheme forms a namespace for all the objects it contains. The full name of these objects is formed according to the pattern .. When accessing objects of the same schema, the schema name can be omitted. Each external database connection, as well as the SQL console, always connects to exactly one schema, which allows the direct use of object names without specifying the schema.
Database schema for authorization control
Another function of a database schema is the authorization control. A user can be assigned different authorizations for each schema. Some schemas are always available in an SAP HANA database. Let’s look at the most important ones: 쐍 Public schema
The public schema contains database objects that are visible to all users. In fact, the objects in this schema are only synonyms. In other words, these objects are actually references to other objects created in another schema. The objects in this package can be used without specifying the schema name. For this reason, make sure you don’t use names for your own database objects that already exist as synonyms in the public package. 쐍 Personal schema
Each database user has his or her own personal database schema. The
36
1.3
Organizing Database Objects
name of this schema corresponds exactly to a user name. In SAP HANA Studio, the personal schema is also used as the default schema when the SQL console for the system is called. The personal schema is particularly suitable for tests and roughly corresponds to the local $TMP package on an SAP NetWeaver ABAP system. 쐍 SAP NetWeaver schema
If SAP HANA is used as a database for an SAP NetWeaver system (including an SAP BW or SAP ERP system), the SAP NetWeaver system is always linked to exactly one schema. All access via the default database connection are directed to this schema. The name of this schema is usually formed from the system ID: SAP. However, in the case of system copies, the schema name
may be different. 쐍 System schemas in SAP HANA
An SAP HANA database contains numerous schemas generated by the system, some of which also contain generated objects. All of these schemas start with the _SYS_ prefix. The metadata of the SAP HANA system and content modeling is stored in these schemas. A special feature is the _SYS_BIC schema. The database objects that are generated when content objects are activated are generated in this schema. For example, column views are generated from the graphically modeled calculation views. The complete name of these objects consists of the following elements: _SYS_BIC./
Typically, subobjects that start with the same name are also generated for these column views, as shown in Figure 1.7.
Figure 1.7 Example of Generated Objects in the _SYS_BIC Schema 쐍 SAP Landscape Transformation schema
When you configure the SAP Landscape Transformation, an associated database schema is created on SAP HANA for each source system.
37
1
SAP HANA
1.3.2 Database Catalogs All active database objects (and only these objects) are stored in the database catalog. These objects are the runtime objects and are structured on the first level by the database schema, then on all lower levels by the corresponding object types, as shown in Figure 1.8.
Figure 1.8 Catalog View of SAP HANA Web-Based Development Workbench
The first node in the catalog consists of the public synonyms, that is, all objects originating from the PUBLIC package. Figure 1.9 shows an example of defining a synonym.
Figure 1.9 Public Synonym for a Column View
38
1.3
Organizing Database Objects
1.3.3 Content and Repositories The content folder contains the design time objects for native SAP HANA applications that are stored in the SAP HANA repository. For example, it can contain the definition of a data model in a file with the extension .HDBDD. When you save, the database objects described in this file are activated, and the corresponding runtime objects are created in the corresponding schema. The content is organized using a hierarchical package structure, as shown in Figure 1.10.
Figure 1.10 Package Structure of the Content
We won’t go into further detail about content in this book. When database objects such as tables or procedures are created, these tasks are competed exclusively via statements in SQLScript. While this approach may not be the best, it corresponds to the subject matter of this book. If you want to develop native SAP HANA applications, we recommend that you also read the book SAP HANA XSA: Native Development for SAP HANA by Alborghetti et al. (www.sap-press.com/4500, SAP PRESS, Boston 2018).
39
Content
1
SAP HANA
1.4 Development Environments Three different development environments for SAP HANA are available. For the purposes of learning SQLScript, we’ll only need a fraction of the functions available in these development environments. For us, the display of the database catalog, the SQL console, and the SQLScript debugger are primarily relevant. These features are available in all three development environments. Overview
Before we go into more detail, let’s briefly overview the three development environments: 쐍 SAP HANA Studio is based on the Eclipse platform. Its strengths lie pre-
dominantly in its integration with the other plug-ins: The SAP BW modeling tools currently represent the toolset for using SAP BW on SAP HANA. The ABAP development tools represent the current development environment for ABAP applications. 쐍 The SAP HANA Web-Based Development Workbench provides a view sim-
ilar to that of SAP HANA Studio. As this environment runs in a web browser, individual users don’t need to install anything. 쐍 The SAP Web IDE also runs in a web browser and can be used for develop-
ing SAP HANA XSA applications in HDI containers. Which development environment is the best is hard to tell. All development environments have their advantages and disadvantages. The right choice therefore depends on the intended use. Table 1.1 contains typical use cases. Activity
Development Environment
Native SAP HANA application development
SAP Web IDE
Pure SAP HANA database modeling without using HDI
SAP HANA Web-Based Development Workbench
SAP BW development
Eclipse with SAP BW modeling tools and ABAP development tools, optional: SAP HANA Studio
Table 1.1 Development Environments by Intended Use
40
1.4
Development Environments
Activity
Development Environment
ABAP development with ABAP Managed Database Procedures (AMDPs)
Eclipse with ABAP development tools, optional: SAP HANA Studio
Table 1.1 Development Environments by Intended Use (Cont.)
Figure 1.11 shows an overview of these development environments, including the network connections and protocols used in each case.
Database server
Application server
SAP HANA
SQL
HTML
WBDW
SAP NetWeaver, SAP BW
SQL
RFC
SAP HANA Studio
SAP Web IDE
Browser
BWMT
ADT
Eclipse Client
Figure 1.11 Development Environments with Associated Network Connections
1.4.1 SAP HANA Studio SAP HANA Studio was the first development environment for developing SQLScript on the SAP HANA database. SAP HANA Studio is actually the Eclipse platform, which has been enhanced with the SAP HANA tools plugins. In this section, we’ll use the term SAP HANA Studio synonymously for the SAP HANA tools plug-ins.
41
1
SAP HANA
Additional plug-ins for Eclipse
The great advantage of using the Eclipse platform is its integration with tools from other SAP products, which can also be installed as plug-ins, as shown in Figure 1.12: 쐍 The ABAP development tools represent the current development envi-
ronment for ABAP development on SAP NetWeaver. Some newer development objects, such as core data services (CDS) views or ABAP Managed Database Procedures (AMDPs) can only be created and edited using the ABAP development tools. 쐍 The SAP BW modeling tools have largely replaced transaction RSA1 for
SAP BW modeling. The newer SAP BW objects, such as advanced DataStore objects or CompositeProviders, can only be opened with the SAP BW modeling tools. As of SAP NetWeaver 7.40, you must use the Eclipse development environment for ABAP and SAP BW development since the classic SAP GUI doesn’t support some new object types. Both ABAP development tools and SAP BW modeling tools have integrated SAP GUI into the Eclipse platform. When some object types are opened, the system switches to the corresponding GUI transactions.
Figure 1.12 SAP Plug-Ins for Eclipse Oxygen
42
1.4
Development Environments
Installing the Eclipse platform and associated plug-ins is relatively easy. You can find all the necessary resources and concise instructions on the SAP HANA tools website (http://s-prs.de/v620801).
Installation
The Old Version Can Do More The plug-in for connecting to systems on the SAP Cloud Platform is no longer available for the current Eclipse version. This plug-in, called SAP Cloud Platform tools for connecting to SAP HANA systems, is only available up to and including Eclipse version Neon (2016). If you don’t need to use the SAP Cloud Platform, you should always use the latest version of Eclipse. Since the end of 2019, the versions are now named with a combination of year and month. The current version (as of January 2019) is called 2018-09. For the SAP Cloud Platform, you should primarily use the web-based development environments, which are also better integrated with the platform’s other services.
To connect to a database via SAP HANA Studio, you’ll need the following information: 쐍 Host name or IP address 쐍 Instance number 쐍 Mode:
– Single database – System database of a multitenant database – Tenant database of a multitenant database 쐍 User name and password
Figure 1.13 shows the corresponding options for adding a new system. To add a new system, you must first navigate to one of the SAP HANA perspectives, such as SAP HANA Development. To do this, choose WINDOW • Perspective • Open Perspective.
43
Connecting to SAP HANA
1
SAP HANA
Right-click on the background of the Systems view to open the context menu and select the Add System... option, as shown in Figure 1.13.
Figure 1.13 Adding a New System in SAP HANA Studio User interface
To work with SAP HANA Studio, you must switch to one of the SAP HANA perspectives. All systems connected to SAP HANA Studio are displayed on the left. The following folders are located below this list: 쐍 Catalog
Database catalog and SQL console 쐍 Content
Hierarchical package structure with development objects for SAP HANA XS applications 쐍 Provisioning
Smart data access and remote sources 쐍 Security
User and role management The main focus of this book is on the Catalog area, where you can view all database objects and open the SQL console for individual database schemas, as shown in Figure 1.14, by opening the context menu on the relevant schema.
44
1.4
Development Environments
Figure 1.14 SAP HANA Studio: User Interface
1.4.2 SAP HANA Web-Based Development Workbench The SAP HANA Web-Based Development Workbench was the first webbased development environment that allowed for developing and testing database objects in SAP HANA. This environment runs in popular browsers such as Microsoft Internet Explorer, Mozilla Firefox, and Google Chrome. Note that there were some problems with the Microsoft Edge browser. The SAP HANA Web-Based Development Workbench allows you to develop SAP HANA XS, classic model, applications, but not SAP HANA XSA applications. You can launch the SAP HANA Web-Based Development Workbench via a URL. For customer installations, the URL is composed as follows: http://:80/sap/hana/ide The host can also be an IP address. For databases on the SAP Cloud Platform, the SAP HANA Web-Based Development Workbench can be opened via a link from the cockpit, as shown in Figure 1.15.
45
Launching the SAP HANA WebBased Development Workbench
1
SAP HANA
Figure 1.15 Link to the SAP HANA Web-Based Development Workbench in the SAP Cloud Platform Cockpit User interface of SAP HANA WebBased Development Workbench
The URL calls the homepage where you can choose between individual areas, as shown in Figure 1.16, such as the following: 쐍 Editor
Repository objects for SAP HANA XS applications and calculation views 쐍 Catalog
Database catalog and the SQL console 쐍 Security
User and role management 쐍 Traces
Trace and log files In the SAP HANA Web-Based Development Workbench, too, the examples and exercises in this book are mainly based on the database catalog, as shown in Figure 1.17. The catalog can be found on the left of the user interface. As in Eclipse, you can open the SQL console via the context menu by right-clicking on the desired schema or by clicking the SQL button.
46
1.4
Development Environments
Figure 1.16 Initial User Interface of the SAP HANA Web-Based Development Workbench
Figure 1.17 Catalog View of the SAP HANA Web-Based Development Workbench
47
1
SAP HANA
Several tabs may be displayed in the right-hand area of the screen that contain, for example, an SQL console, details about database objects, or a data preview.
1.4.3 SAP Web IDE Originally, the SAP Web IDE was a web development environment for creating SAPUI5 applications. With SAP HANA XSA and the introduction of HDI containers, this user interface was extended to include the SAP HANA database explorer (also referred to as SAP HANA runtime tools). Integration of HDI
The great benefit of using the SAP Web IDE is its integration with the SAP HANA deployment infrastructure (HDI). Its core idea is that database objects are no longer permanently assigned to a schema but instead are first defined, independently of the schema, in a container. The fixed reference to objects in other database schemas is also avoided. Synonyms are not replaced by the actual schema names until deployment.
Launching the SAP Web IDE You can launch the SAP Web IDE via the following URL: https://:53075/ If you operate your own SAP HANA system, you may experience a delay between system start and when the SAP Web IDE is available. The SAP Web IDE consists of different modules (features) that can be activated and deactivated individually. Activating the SAP HANA Database Explorer
The SAP HANA database explorer is one of these modules; you can launch the database explorer via the icon in the navigation menu on the left. If you don’t see this icon, the database explorer is not yet activated. In that case, you must first open the settings icon to activate the relevant feature, as shown in Figure 1.18.
User Interface The structure of the SAP Web IDE user interface is similar to that of the other two development environments. To add a database, you must click the icon, which opens the screen for entering the connection parameters, as shown in Figure 1.19.
48
1.4
Development Environments
Figure 1.18 Activating the Database Explorer
Figure 1.19 Adding a Database Connection
49
1
SAP HANA
The structure of the user interface largely corresponds to that of the other two development environments, as shown in Figure 1.20.
Figure 1.20 SAP HANA Database Explorer in the SAP Web IDE
1.5 The SQL Console The SQL console is part of all three development environments and allows the execution of any SQL and SQLScript commands. As a result, you can create database tables and procedures, for example, or perform administrative tasks such as assigning authorizations to users. Database connection for the SQL console
A window of the SQL console is always open for a system connection and has exactly one schema to which it is connected. For access within this schema, you don’t need to explicitly specify the schema prefix, which is handy when operating within one schema.
50
1.5
To launch the SQL console, open the database catalog in the development environment of your choice. Then, right-click on a database schema to open the context menu and then choose Open SQL Console, as shown in Figure 1.21. Alternatively, each development environment contains an SQL button, which opens an SQL console connected to your database user’s personal database schema.
The SQL Console
Launching the SQL console
Figure 1.21 Opening the SQL Console for a Schema
A tab with the SQL console opens in the editor area on the right. As an example, the user interface of the SQL console in the SAP HANA Web-Based Development Workbench is shown in Figure 1.22. The user interface is divided into several different areas: 1 The current database schema for which the SQL console was opened. 2 The host name of the SAP HANA system. 3 The execute icon executes the statements in the SQL Editor. If individual statements are selected, only these statements are executed; otherwise, all are.
51
UI elements of the SQL console
1
SAP HANA
4 The SQL icon opens an SQL console for the personal schema of the database user. 5 The tab for the SQL Editor. Several tabs can be opened. In addition to the SQL Editor, database objects or the data preview can also be displayed here. 6 The actual SQL Editor. In this area, you’ll enter your SQL statements. If several statements follow each other, each statement must be terminated by a semicolon. 7 The result view (Result1) displays the result of a statement. If the statements in the SQL Editor return several results, several tabs may be displayed in this area. 8 The messages of the system concerning execution are displayed in the message area. Errors will be displayed in a red font.
Figure 1.22 UI Elements of the SQL Console Getting started
To familiarize yourself with the SQL console, enter the following SQL statement into the editor:
52
1.5
SELECT * FROM m_cs_tables
Then, click the Execute button or press the (F8) key. Now, the system will execute the statement, and the message shown in Listing 1.1 will appear in the message area. Statement 'SELECT * FROM m_cs_tables' successfully executed in 9 ms 90 μs (server processing time: 6 ms 985 μs) Fetched 302 row(s) in 27 ms 160 μs (server processing time: 15 ms 984 μs) Listing 1.1 SQL Console Message When Executing a Statement
Additionally, the Result1 tab opens. In the lower area, you’ll the results as a table. The second example of the SQL console is shown in Listing 1.2. Type this code into the SQL console and run it by pressing (F8). CREATE TABLE names ( id INT, last_name VARCHAR(30), first_name VARCHAR(30) ); INSERT INTO names VALUES ( 1,'Brandeis','Jörg' ); INSERT INTO names VALUES ( 2, 'Müller', 'Peter' ); SELECT * FROM names; DROP TABLE names; Listing 1.2 Example of Multiple Statements in the SQL Console
In this example, a database table is created via CREATE TABLE. Two data records are inserted using the INSERT statement, the content is queried via the SELECT statement, and finally the database table is deleted using DROP TABLE.
Examples with CREATE and DROP Many examples in this book use CREATE to create a database object, which is deleted at the end of the listing using the DROP statement. These listings can therefore be executed as often as required, since no artifacts will be left in the database.
53
The SQL Console
1
SAP HANA
Partial execution of code
If only part of the code is selected in the SQL Editor, only this part will be executed. Let’s try this out using the earlier example from Listing 1.2 by following these steps: 1. Select the first four statements with your cursor and then click Execute or press (F8). The system will create the table, fill it with the two rows, and output the result. Because the DROP TABLE statement was not selected, this statement is not executed. 2. Now, select the two INSERT statements and the SELECT statement and execute it again. Now, you’ll four records in the table. 3. Finally, please select only the DROP TABLE statement and delete the table. In this chapter, we explored the basic concepts of SAP HANA and the most important tools. In the next chapter, we will start with the SQLScript language.
54
Chapter 2 Getting Started with SQLScript In this chapter, we’ll introduce you to the basics of SQLScript. First, we’ll deal with some important formal aspects of the programming language. Then, you’ll learn how to create and call procedures and customized functions.
In this chapter, we’ll focus on SQLScript first by clarifying what kind of language SQLScript actually is. Then, in Section 2.2, we’ll continue with the formal part of the SQLScript language. The basis of every programming language are its lexical elements, the name given to the smallest language units that make up a program. Lexical elements include, for example, comments, identifiers, statements, expressions, and literals. These lexical elements must meet certain formal criteria to be correctly recognized by the system. In addition, two different concepts of “nothing” will need to be examined. The value NULL represents the absence of a specific value in database fields. Thus, this value behaves differently than one might expect, a familiar trap for ABAP developers in particular, since they typically could ignore NULL, more or less. Another concept requiring explanation is the table DUMMY, which contains exactly one data record in only one column of the same name. However, this table is extremely useful in some cases. Section 2.3 describes logical containers, which form a framework for SQLScript statements. Logical containers include procedures, functions, and anonymous blocks. The chapter concludes with a complete example in Section 2.4, so you can review all the concepts from the preceding sections. The examples in this chapter may show SQLScript statements that will be explained in more detail in later chapters. But if you have experience with other programming languages, you’ll easily understand them. The relevant aspect for the example is always highlighted in bold.
55
2 Getting Started with SQLScript
2.1 SQL Versus SQLScript SQL is a database language for defining data structures in relational databases as well as for editing (inserting, updating, deleting) and querying databases based on it. Applications use the SQL language to communicate with the database by sending individual statements one after the other to the database. SQL lacks a way to bundle multiple statements or to define a flow logic. Enhancement of the SQL standard
Many database providers have therefore extended the SQL standard for their products with these functions. For example, Oracle developed the PL/ SQL language, and IBM developed the SQL PL language. (In both cases, the abbreviation PL stands for “procedural language.”) With these languages, blocks of statements could be stored as functions or procedures and executed over and over again. SQLScript is also an enhancement of the ANSI SQL standard, defined by SAP for the SAP HANA database.
ASE Speaks SQLScript Too SQLScript is almost exclusively perceived and marketed as a programming language for the SAP HANA database. However, with its subsidiary, Sybase, SAP has another database in its portfolio that understands SQLScript as well: Adaptive Server Enterprise (ASE). The SQLScript statements and SQL functions on ASE are compatible with SAP HANA 1.0 SPS 12. For more information, see the SAP document “SAP ASE SQLScript Reference” found at http://bit.ly/1822_201.
SQLScript enhancements to the SQL standard affect the following areas, among others: 쐍 Procedures, functions, and anonymous blocks as logical containers for the
SQLScript code 쐍 Extension of data types by table types without corresponding database
tables 쐍 Declarative logic to formulate complex, but still very high-performance
database queries 쐍 Imperative logic for flow control such as IF/ELSE or FOR loops
56
2.1
SQL Versus SQLScript
SQLScript is therefore an enhancement of the SQL standard. As a result, SQL statements are embedded directly in the SQLScript code. Together, they form a language. For this reason, this book is not limited to discussing only these enhancements, but considers SQLScript as a single entity. Traditionally, SQL statements are divided into the three categories: data manipulation language (DML), data definition language (DDL), and data control language (DCL). Let’s look at each in more detail:
Categories of SQL statements
쐍 Data manipulation language
DML includes all statements that read or update the dataset in the database tables. Most applications only use DML statements during operations. Typical statements are SELECT, INSERT, and UPDATE statements. Read access via DML is described in Chapter 3; update access, in Chapter 5. 쐍 Data definition language
This statement category is used to define the data model, which is usually done during the development, installation, or upgrade of an application. Typical statements are the CREATE, ALTER, and DROP statements. These statements are described in greater detail in Chapter 7. 쐍 Data control language
This part of the SQL language is responsible for assigning read and write authorizations. These statements are therefore relevant for database administration. Typical statements are GRANT and REVOKE. DCL is not discussed further in this book. For information on the administration of an SAP HANA database with SQL, see the SAP document “SAP HANA SQL and System Views Reference” found at http://bit.ly/1822_202. Figure 2.1 shows an overview of the SQLScript language with the SQL standard and SAP enhancements. By creating reexecutable procedures and functions, you can delegate even larger tasks to the database that go beyond the execution of a single SQL statement. SAP refers to this technique as the code-to-data paradigm. With this paradigm, complex and data-intensive calculations should be performed directly in the database, thus saving the cost of copying the data to the application server. In some cases, you may also benefit from the parallelization and further optimization of SAP HANA, which can only made be possible by the SQLScript language enhancements, since only individual
57
Code-to-data paradigm
2 Getting Started with SQLScript
statements can be issued with pure SQL. Figure 2.2 shows the differences between the classic three-layer architecture and the code-to-data paradigm. Procedures UDF Functions FOR SAP Extensions
WHILE
Imperative
IF Cursors
Declarative
Table Variables
SELECT
SQLScript DML
UPDATE Write access
INSERT DELETE
SQL Standard
DCL
GRANT REVOKE CREATE TABLE
DDL
ALTER TABLE DROP TABLE
Figure 2.1 Overview of Typical SQLScript Statements
Presentation tier
Classical 3-Tier architecture
Code-to-Data Paradigms
SAP GUI/Web-applications
SAP GUI/Web-applications
Application control Application tier
Application control Calculation logic
Database tier
Data
Calculation logic Data
Figure 2.2 Classic Three-Layer Architecture vs. Code-to-Data Paradigm
58
2.2
Basic Language Elements
Especially if problems can be solved with declarative code, considerable speed improvements are possible via code pushdown. However, this approach also has its disadvantages. The application developer, for example, must master several programming languages, and changing languages also increases the complexity of development and troubleshooting for the application. In addition, the logical separation between application server and database server is no longer as clean as in the classic three-layer architecture. This separation of the presentation layer, the application layer, and the database layer has long been regarded an important achievement in software architecture. The separation of the two lower layers was so strict that SAP systems could be run on different database systems, which was an important aspect for many customers and partners when deciding to adopt this software platform. This clean separation has been made obsolete by the code-to-data paradigm. Formally, the three layers still exist, since an application server and a database server exist. But the logical separation between the systems has been diluted because the database takes over some of the tasks of the application server. For third-party providers of products on the SAP NetWeaver platform, this paradigm shift brings significant disadvantages. If you need to keep your product open for all database platforms, you can only benefit to a limited extent from the advantages of the SAP HANA database. Alternatively, you could opt for a two-track development, which, however, would entail a corresponding additional effort.
2.2 Basic Language Elements You probably spoke your native language fluently and flawlessly before you heard about grammar for the first time in primary school. When learning foreign languages, however, examining the basic rules that apply to the language can be quite helpful. The same applies to programming languages. For the compiler to interpret our source code correctly, we must first understand how the individual language elements are structured. The source code of SQLScript is written in the Unicode character set, which represents the characters almost all writing cultures. You can, for example, use Cyrillic, Chinese, or Korean characters for the source text. For the sake of
59
Third-party providers
2 Getting Started with SQLScript
better readability and maintainability, for all identifiers, you should use only characters found in the ASCII character set without umlauts.
2.2.1 Statements The SQLScript language consists primarily of statements. With the exception of assignments, statements begin with a keyword and end with a semicolon. Several different types of statements are available in SQLScript, such as the following: 쐍 SQL statements such as INSERT, CREATE PROCEDURE, or COMMIT 쐍 Assignments using the equal sign or the INTO clause of a SELECT query (see
Chapter 3, Section 3.1.2, and Chapter 6, Section 6.1.1) 쐍 Loops with FOR or WHILE, or as cursor (see Chapter 6, Section 6.3 and Sec-
tion 6.4) 쐍 Conditional branches with IF (see Chapter 6, Section 6.2) 쐍 Procedure calls (Section 2.3.2) 쐍 Declarations of variables Nested statements
Some statements may contain statements themselves. For example, an IF statement forms a parentheses around one or more statement blocks. We’ll describe the block concept in further detail in Section 2.3.1. As shown in Listing 2.1, the IF statement starts in line 1 and ends with the semicolon in line 4. The INSERT statement starts and ends in line 3. 1 IF lv_counter > 0 2 THEN 3 INSERT INTO colors VALUES ('Purple'); 4 END IF; Listing 2.1 IF Statement Containing an INSERT Statement
2.2.2 Whitespace The term whitespace describes all characters in the source code that are represented as blank spaces in white. These characters include, among others, blank characters, tabs, and line breaks. These characters have different tasks
60
2.2
Basic Language Elements
in programming languages. In SQLScript, whitespace is only required where a unique separation of consecutive keywords, fields, variables, etc. would otherwise not be possible. However, whitespace may also be inserted anywhere else between the individual language elements. The compiler doesn’t distinguish between the different whitespace characters. Likewise, the number of consecutive whitespace characters is also irrelevant. You can also use whitespace for formatting, for example, to improve the readability of the source code by indenting lines of code. Unlike some other programming languages, such as Python, indenting has no effect on semantics. Further, each statement does not need to be on a new line, even if this makes the code much clearer.
Interpretation
The example shown in Listing 2.2 includes two identical SELECT statements. Semantically, the different formatting doesn’t play any role. SELECT col1,col2 FROM T1; SELECT col1, col2 FROM T1 ; Listing 2.2 Example of Different Formatting
2.2.3 Comments Comments are components of the source code that are completely ignored by the system. The content of a comment thus only helps human readers understand the code. SQLScript distinguishes between two variants of comments: end-of-line comments and block comments. An end-of-line comment starts with a double hyphen (--). Anything written after this up to the end of the line is not interpreted as part of a statement. The end-of-line comment can be preceded by parts of statements. A statement that extends over several lines can also be interrupted by an end-ofline comment.
End-of-line comments
Block comments start with two characters, a slash and an asterisk (/*), and ends with an asterisk and a slash (*/), for example:
Block comments
/* This is a block comment */
61
2 Getting Started with SQLScript
A block comment can also extend over several lines and be included in the middle of a statement. Figure 2.3 shows a few examples of using comments in SQLScript.
Figure 2.3 Examples of (Superfluous) Comments in the Source Code
Comments should not describe the obvious in the source code but should help readers understand the source code, for example, by providing the following information: 쐍 Background information 쐍 A reference to the specification 쐍 The structure of the source text
Against this background, all comments in the example shown in Figure 2.3 are superfluous but illustrate where comments are possible in the source code.
2.2.4 Literals Literals represent constant values in the source code that are entered directly. Literals can be used in different places, for example, in assignments, as field values, or as comparison values in a condition. Literals can have different data types that are derived from their value. Table 2.1 shows examples of different data types. Name
Format
Example
Simple strings
In single quotation marks
'Peter'
Unicode strings
In single quotation marks with a capital N as prefix
N'Jörg'
Table 2.1 Literals of the Different Data Types
62
2.2
Basic Language Elements
Name
Format
Example
Binary strings
In single quotation marks with a capital X as prefix
X'FF'
Integers
Digit sequence
123
Decimal numbers
Digit sequence with decimal point
123.456
Floating-point numbers
Mantissa and exponent, separated by a capital E
123E2
Hexadecimal numbers
Prefix 0x
0xFF
Date
Prefix DATE
DATE'2017-11-10'
Time
Prefix TIME
TIME'15:42:04.123'
Timestamp
Prefix TIMESTAMP
TIMESTAMP'2011-12-31 23:59:59'
Table 2.1 Literals of the Different Data Types (Cont.)
For the numerical literals, a negative algebraic sign (a minus sign, −) is also possible as a prefix. Listing 2.3 shows different literals in a simple SELECT statement. If you execute this statement in the SQL console of the SAP HANA Web-Based Development Workbench or in the SAP Web IDE, you’ll see a symbol for the data type next to each column header of the result table. SELECT 'Jörg' N'Jörg' x'fff' -10 - 1.2345 - 17.126E30 0xff '2010-01-01' DATE'2017-11-10' '15:42:04.123' TIME'15:42:04.123'
AS AS AS AS AS AS AS AS AS AS AS
string, unicode, binary, integer, decimal, float, hex, date_as_string, date, time_as_string, time,
63
2 Getting Started with SQLScript
FROM
'2011-12-31 23:59:59' AS timestamp_string, TIMESTAMP'2011-12-31 23:59:59' AS timestamp dummy;
Listing 2.3 Examples of Literals in the Source Code Character string literals
The result of the character string literals is shown in Figure 2.4. If you use non-Unicode strings, the umlauts may be displayed differently in the data preview in the different development environments.
Figure 2.4 Result of the Character String Literals Numerical literals
Figure 2.5 shows numerical literals. To the left of the column header, you’ll see a small symbol for the data types displayed. In our example, you’ll see 12 throughout, which represents numerical data types. Notice that the floating-point literal has been converted into scientific notation with only one predecimal place. The hexadecimal literal was converted from “0xFF” to the number “255.”
Figure 2.5 Result of Numerical Literals Time and date literals
For both time and date literals, a character string representation was also created in the listing (Figure 2.6). In the output, these converted literals can’t be distinguished from the correct display of date and time values. Only the symbols for the data types in the column headers tell you which data types are actually used. By using the prefixes TIME, DATE, and TIMESTAMP, the data was generated with all the correct data types.
Figure 2.6 Result of Time and Date Literals
64
2.2
Basic Language Elements
2.2.5 Identifiers Identifiers are names for objects in SAP HANA, for example, for tables, views, and columns. These identifiers are always case sensitive, which means that a distinction is made between uppercase and lowercase letters. In this context, understanding how the source code is interpreted by the system is important. Two different notations styles can be used. In simple notation, an identifier in the source text is not specified within quotation marks. As a result, internally, the identifier is automatically converted into uppercase letters. In addition, the following restrictions also apply to the identifier:
Simple notation of identifiers
쐍 It must start with a letter or an underscore 쐍 It may only consist of the following characters:
– Letters of the Latin alphabet, no umlauts – Digits – Underscore ( _ ) – Dollar sign ($) – Hash (#) Only simple notation is permitted for the names of parameters and variables. Listing 2.4 shows a simple example of how to use simple notation. The identifiers are internally interpreted as ID, STATUS, TITLE, and TASKS. SELECT id, status, title FROM tasks; Listing 2.4 Example of Simple Notation
In special notation, identifiers are put between quotation marks. This type of notation allows all Unicode characters in every position. As a result, blank characters; special characters, such as periods and commas; and all other characters are allowed.
65
Special notation of identifiers
2 Getting Started with SQLScript
The following example shows how, with special notation, the contents between the quotation marks are used exactly as identifiers: CREATE TABLE id_with_space("ID" int, " ID" int , "ID " int);
Bad identifiers make legibility considerably more difficult. For example, a table may be created with columns that differ only in the position of blank characters, which is syntactically allowed and won’t cause errors. However, the output shown in Figure 2.7 consists of a table with column names that can no longer be distinguished by the human eye.
Figure 2.7 Resulting Table Definition
If Possible, Always Use Simple Notation This example shows how dangerous using poorly chosen identifiers can be. Therefore, we recommend you always use capital letters without umlauts for your own database objects and to avoid using spaces or special characters. We recommend always using simple notation to avoid problems. With simple notation, ambiguous names are almost impossible.
When we access existing tables, we don’t have the choice of which table and column names to use. The demo data of SAP’s SAP HANA interactive education (SHINE) data model contains, among others, column names with periods such as NAME.FIRSTNAME, which forces us to use special notation for those columns. Note that you can combine simple notation and special notation in any possible way in the source code.
66
2.2
Basic Language Elements
Identifiers of Generated Database Objects of SAP Business Warehouse SAP Business Warehouse (SAP BW) generates the database tables for the data models in the generation namespaces /BIC/ or /BI0/. As a result, each database object begins with this prefix, and some field names will also have these prefixes. To access these objects in SQLScript, you’ll need to use special notation with quotation marks. However, note, again, that everything must then be specified in capital letters. Here’s an example of the attribute table of the InfoObject 0MAT_PLANT: "SAPNPL"."/BI0/PMAT_PLANT"
2.2.6 Access to Local Variables and Parameters In SQLScript, you can also access local table variables and table parameters via a SELECT statement just as you would access database tables. Thus, a distinction is necessary for read access, so that the source code remains unique. For this purpose, a colon is placed in front of the variable, as shown in Listing 2.5. CREATE PROCEDURE get_name(IN id INT) AS BEGIN tmp = SELECT id, lastname, firstname FROM users; SELECT * FROM :tmp WHERE id = :id; END; CALL get_name(1); Listing 2.5 Access to Local Fields and Parameters
The colon is not required for write access, since variables won’t be confused with database objects. These objects can’t be changed by a simple assignment, only by the changing statements that you’ll learn about in Chapter 5.
2.2.7 System Variables Some system variables exist in SQLScript, each of which can provide useful information in their respective context and are particularly useful for analyzing and logging error situations. System variables start with two leading colons. Some common system variables include the following:
67
2 Getting Started with SQLScript
쐍 ::CURRENT_OBJECT_NAME
Name of the procedure or function in which the system variable is queried. In anonymous blocks, this variable has the value NULL. Outside of logical containers (Section 2.3), accessing the variable returns an error. 쐍 ::CURRENT_OBJECT_SCHEMA
Database schema of the procedure or function in which the system variable is queried. The visibility of this variable is the same as for the ::CURRENT_OBJECT_NAME variable. 쐍 ::SQL_ERROR_CODE
Contains the current error code. This variable is only visible within error handlers (see Chapter 6, Section 6.8). 쐍 ::SQL_ERROR_MESSAGE
Contains the message for the current error code. The visibility of this variable is similar to that of the ::SQL_ERROR_CODE variable. 쐍 ::ROWCOUNT
The variable contains the number of data records that were updated by the most recent database statement. Reading database statements are not relevant. If you query the variable before an updating database statement has taken place, an error is generated. 쐍 ::CURRENT_LINE_NUMBER
Contains the line number in the source code. This variable is only available with SAP HANA 2.0 SPS 02. You’ll find practical examples for using system variables in Chapter 6, Section 6.8, on error handling.
2.2.8 Reserved Words Many words should not be used as identifiers in SQLScript because they are reserved for the language itself. As a result, you can use these words as identifiers only in special notation because otherwise the semantics are no longer unique. You can print out the set of keywords for SQLScript from the RESERVED_KEYWORDS system view using the SELECT * FROM RESERVED_KEYWORDS; statement.
68
2.2
Basic Language Elements
In addition, we recommend avoiding using the keywords of other programming languages involved in the project, as well as of the latest ANSI-SQL standard, to avoid any complications.
2.2.9 Operators Operators calculate a result from the operands. For example, you can use the plus operator (+) to create a sum out of two numbers: Result = Number1 + Number2;
Based on the number of operands, you can subdivide operators into unary and binary operators. Unary operators have exactly one operand; binary, exactly two. Table 2.2 shows some examples. Operator Type
Pattern
Example
Unary
−9
Binary
3+4
Table 2.2 Differentiation of Operators According to the Number of Operands
Grouped by the data type of the result, the following operators are available: 쐍 Arithmetic operators return a numeric result:
– Addition (+) – Subtraction (−) – Multiplication (*) – Division (/) – Negation (−, as a mathematical sign) 쐍 String operators to concatenate strings into a new string (||) 쐍 Relational operators return as a result a statement in Boolean logic,
which can be either TRUE, FALSE, or UNKNOWN. UNKNOWN corresponds to a NULL value of the database. The result of these operators is always exactly UNKNOWN if an operand is NULL. – Equal to (=) – Not equal (!= or )
69
Operators by data type
2 Getting Started with SQLScript
– Less than () – Less than or equal to (=) 쐍 Logical operators link logical statements into new logical statements:
– AND: If both operands are TRUE, the result is also TRUE. – OR: If at least one of the two operands is TRUE, the result is TRUE. – NOT: This unary operator negates the value of its operand. TRUE becomes FALSE, and vice versa. For all operators, the result is NULL if one operand is NULL. Priority rules
If an expression contains multiple operators, priority rules can determine the sequence in which operators are evaluated to ensure that the result of an expression is clearly defined. Table 2.3 shows the evaluation sequence of operators from top to bottom. Group
Operators
–
Parentheses
Arithmetic operators
Sign Multiplication and division Addition and subtraction
String operators
Concatenation
Relational operators
All relation operators
Logical operators
NOT AND OR in real life
Table 2.3 Evaluation Sequence of the Operators from Top to Bottom
Even if you know the evaluation sequence of the operators, you should always use parentheses if you have more than two operators. Using parentheses increases readability considerably and allows even less-experienced
70
2.2
Basic Language Elements
colleagues to interpret your source code correctly. The simple example shown in Listing 2.6 illustrate how significantly the use of parentheses can increase readability. In this example code, multiplication and division operators takes precedence over addition and subtraction operators. SELECT "PURCHASEORDERID", "PURCHASEORDERITEM", "PRODUCT.PRODUCTID", "CURRENCY", case when netamount 0 --- With parentheses: --then ((grossamount / netamount) * 100) - 100 --- Without parentheses: then grossamount / netamount * 100 - 100 else 0 end as tax, "GROSSAMOUNT", "NETAMOUNT", "TAXAMOUNT", "QUANTITY", "QUANTITYUNIT", "DELIVERYDATE" FROM "SAP_HANA_DEMO"."sap.hana.democontent.epm.data::PO.Item"; Listing 2.6 Example of Using Parentheses for Operators
Splitting more complex expressions containing several operators into several smaller steps often makes sense, providing intermediate results that can make troubleshooting and debugger much easier. Execution speed will not change as a result of this method, since the SAP HANA database optimizes expressions accordingly before execution. The set operators UNION (ALL), INTERSECT, and EXCEPT are not described in this section, but we’ll discuss them in detail in Chapter 3, Section 3.2, in the context of the SELECT statement.
71
2 Getting Started with SQLScript
2.2.10 Expressions An expression is a language construct that is evaluated in its context and returns a value. Expressions can occur in various places within an SQL statement, such as in SELECT, WHERE, or GROUP BY clauses. The following elements can be used as expressions: 쐍 Literals 쐍 Constant and variable names 쐍 Column names 쐍 Function calls 쐍 Links of expressions with operators 쐍 CASE statements 쐍 Subqueries 쐍 Aggregate functions
Some expressions may themselves be composed of other expressions. For example, an expression can be used for the parameter in a function call. Thus, expressions can always be deeply nested constructs. Context of expressions
Not all expressions are possible in every context. For example, aggregate functions can only be used meaningfully in SELECT statements. An aggregate function can’t be used to assign a scalar variable. The example shown in Listing 2.7 illustrates some of these types of expressions, especially the nested use of expressions within expressions. SELECT -Columnname as an expression id, -Concatenation as an expression firstname || ' ' || lastname AS name, -CASE expression ... CASE -... with a UDF expression WHEN sex = 'F' THEN NCHAR('9792') WHEN sex = 'M' THEN NCHAR('9794') ELSE '' END AS MW,
72
2.2
--
Basic Language Elements
SQL function as expression COALESCE(team, 0) AS team FROM users;
Listing 2.7 Expressions in Field Lists
2.2.11 Predicates Predicates are logical expressions that can be used in the selection conditions of SELECT statements. If the predicate for a line can be evaluated as TRUE, this line is included in the result set. Chapter 3, Section 3.2.5, contains a detailed description of the predicates in the context of the WHERE clause.
2.2.12 Data Types We need data types to store data in a database column, to process data in local variables, or to pass data as parameters. Data type always defines what the data looks like and which operations are possible with this data.
Scalar Data Types A scalar data type can store exactly one value, which can be a number or a string, for example. The opposite of a scalar data type is a composite data type, such as a table. You’ll frequently see the term primitive data type in books about object-oriented programming languages. This phrase largely corresponds to the scalar data type. The phrase “primitive data type” is used to emphasize its distinctness from reference types, i.e., the objects, whereas the qualifier scalar stresses its difference from composite or table-like data. When a function returns exactly one value, it is referred to as a scalar function. Some functions return table-like data. A SELECT query always returns a table. Even if the result table has exactly one column and one row, it is still a table. However, we refer to such a query as a scalar query. Many scalar data types have been built into SQLScript, which you’ll learn about in Chapter 4.
73
Scalar functions
2 Getting Started with SQLScript
Data Types for Table Variables and Parameters The table-like data types are needed for defining table variables and table parameters. Table-like data types are always composed of scalar data types. You can explicitly create table types as database objects via CREATE TYPE. These table types then occur as a separate database object in the catalog of the respective schema. Alternatively, you can refer to existing database tables for typing or define the table type directly in the source code using a field list. Typing
Listing 2.8 shows all three alternatives for typing a local table variable. DO BEGIN -- Type of a database table DECLARE lt_tab1 tasks; -- Type of a tabletype DECLARE lt_tab2 id_text; -- Table type defined in code with TABLE DECLARE lt_tab3 TABLE( id INT, col1 NVARCHAR(12) ); lt_tab1 = SELECT * FROM tasks; lt_tab2 = SELECT id, title AS text FROM :lt_tab1; lt_tab3 = SELECT id, title AS col1 FROM :lt_tab1; SELECT * FROM :lt_tab1; SELECT * FROM :lt_tab1; SELECT * FROM :lt_tab1; END; Listing 2.8 Different Typing of Tables
2.2.13 The NULL Value NULL doesn’t describe a concrete value, but the absence of a value. In particular, a NULL value is not a valid initial value such as 0 or SPACE. As a result, you can’t use columns or fields containing the NULL value to carry out meaningful comparisons. Accordingly, the comparison operators initially react unexpectedly.
74
2.2
Basic Language Elements
NULL in Open SQL in ABAP The NULL value hardly ever occurs on the SAP NetWeaver platform with the ABAP programming language, largely due to the complete integration of Open SQL used in the ABAP language. Write access occurs almost exclusively via a work area or an internal table whose rows match exactly those of the database table. Within the work area or internal table, no field can be NULL. As a result, NULL can’t be written into the database table either. Another mechanism that avoids including NULL into the database is a specific setting made when database tables are created in the data dictionary (DDic). This setting allows you to set the indicator for initial values in database tables for each column, which corresponds to the addition of NOT NULL when defining tables in SQL. This setting ensures that the column always has an initial value appropriate to its type such as 0 or SPACE. Nevertheless, NULL can occur in a database if, for example, a database table was subsequently extended by a column and the NULL values were not excluded when the column was defined. Correspondingly, Open SQL also provides the option of selecting by NULL within a column.
A simple example shown in Listing 2.9 illustrates this scenario. In this example, a database table, TEST_NULL, has been created with the two columns: ID and NAME. Then, five data records have been written into the columns, but the last data record doesn’t contain a NAME value. Accordingly, as shown in Figure 2.8, the column contains the NULL value.
Figure 2.8 Representing NULL as a Question Mark in SAP HANA Studio
This example gets particularly interesting when the two SELECT statements are executed. You would expect the first statement to find the first three
75
Example
2 Getting Started with SQLScript
records, since the names all begin with P, and the second statement should return all other records, since they do not begin with P. Actually, however, the data record with ID=5 isn’t read by either of the SELECT statements. CREATE TABLE test_null( id INT, name VARCHAR(10) ); INSERT INTO test_null VALUES(1, 'Peter'); INSERT INTO test_null VALUES(2, 'Paul'); INSERT INTO test_null VALUES(3, 'Petra'); INSERT INTO test_null VALUES(4, 'Andrea'); INSERT INTO test_null(id) VALUES(5); SELECT * FROM test_null WHERE name LIKE 'P%'; SELECT * FROM test_null WHERE name NOT LIKE 'P%'; DROP TABLE test_null; --to delete the table Listing 2.9 Selecting by a Column that Contains NULL Values
Therefore, if you select by a column that may contain NULL values, these values must always be taken into account. In our example, an additional query for IS NULL would make sense, for example, in the following statement: SELECT * FROM test_null WHERE name NOT LIKE 'P%' OR name IS NULL;
In development environments, you can specify in the settings how the NULL value should be displayed. A common selection is to use either the question mark (?) or the NULL string. Coalesce
To avoid the value NULL in queries, you can use the SQL function COALESCE. This function can be called with several parameters. The leftmost parameter that is not NULL is returned.
2.2.14 The DUMMY Table Table DUMMY is a database table that contains exactly one column called DUMMY, which in turn contains exactly one row with the content “X.” Since
76
2.2
Basic Language Elements
the contents of the table must not be changed, you can always rely on these properties. One use case for the DUMMY table is for testing expressions. Because you can’t directly execute SQLScript code in the SQL console without building an anonymous block around it, DUMMY represents a useful alternative. For example, Listing 2.10 shows how you can test the TO_DATS( ) function for converting dates. -- Test with DUMMY SELECT TO_DATS('2016-01-01') FROM dummy; -- The same test with an anonymous block DO (OUT rv_result NVARCHAR(10) =>?) BEGIN rv_result = TO_DATS('2016-12-31'); END; Listing 2.10 The DUMMY Table for Testing Expressions
Another convenient way of deploying the DUMMY table is that to create an empty table with a fixed structure. This scenario happens, for example, when you implement a transformation routine as an ABAP Managed Database Procedure (AMDP) in SAP BW. The generated interface of this procedure contains a defined table called ERRORTAB. If no value is assigned to this table, the procedure can’t be activated, and a syntax error will be displayed. The code shown in Listing 2.11 enables you to generate an empty table with the appropriate structure. errorTab =
SELECT '' AS ERROR_TEXT, '' AS SQL__PROCEDURE__SOURCE__RECORD FROM dummy WHERE dummy = 'Y';
Listing 2.11 Generating an Empty Table via DUMMY
Other database systems also provide such DUMMY tables even though, in some cases, their names are different.
77
Examples
2 Getting Started with SQLScript
2.3 Modularization and Logical Containers Normally, SQL statements are sent one by one from an application to the database. If several statements are to be executed one after the other as a script, a logical framework is required. In SQLScript, this framework is formed by the logical containers in the form of procedures, functions, and anonymous blocks. Procedures and functions
Procedures and functions are subroutines that can contain a number of SQLScript statements. These subroutines are saved as database objects under a name and can be called again at any time under this name. The transfer of data is carried out via parameters. If you want to execute a sequence of SQLScript statements in the SQL console without first creating a procedure or function, you must execute them in an anonymous block. Procedures and functions are used to modularize the source code, which serves different purposes; the two most important goals, clearness and reuse, are described in the following sections.
Clearness
Long stretches of source code are difficult to read. In his book, Clean Code, Robert C. Martin writes: The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that. The reason for this requirement is for better readability and maintainability of the source code. Of course, you’ll lose the big picture in a function that consists of several hundred lines. However, a meaningful structuring in procedures can help. In particular, the many dependencies on variables within a long code base create a high degree of complexity. By breaking your code down into smaller procedures and functions, you can reduce dependencies considerably, since the call parameters will clearly document which variables are read or written.
Reuse
Another important reason for modularizing source code is for reusability. According to the well-known Don’t Repeat Yourself (DRY) principle, you should avoid redundancy in the source code. The best way to avoid redundancy is to outsource code to suitable procedures or functions, which significantly increases the maintainability and testability of a system.
Procedure or function?
In SQLScript, you’ll have two options for creating subroutines: procedures and user-defined functions (UDFs). With regard to UDFs, a further distinc-
78
2.3
Modularization and Logical Containers
tion is made between table UDFs and scalar UDFs based on their return types. UDFs themselves represent an expression, as described in Section 2.2.10. As a result, you can use UDFs in many places, in particular, in SELECT statements. Scalar UDFs can be used, for example, to process data in the field list of a SELECT clause or in comparative expressions. Table UDFs can be used wherever a database table would be used. Listing 2.12 shows how elegantly you can embed the UDFs into a SELECT query. SELECT a.id, udf_username(a.assignee), a.title, s.status_text FROM udf_tasks_in_status(4) AS a LEFT OUTER JOIN udf_status_texts('EN') AS s ON a.STATUS = s.id; Listing 2.12 SELECT Query with UDFs
UDFs are only allowed to read data. The task of changing data and database objects is reserved for procedures, which have no initial restrictions with regard to the statements to be used. Table 2.4 lists the most important distinctive criteria between procedures, table UDFs, and scalar UDFs. Procedures
Table UDFs
Scalar UDFs
Any number of return parameters of any type
Exactly one return parameter with one table type
One or more return parameters with a scalar type
Tables and scalar types as input parameters
Tables and scalar types as input parameters
Only scalar types for input parameters
Can’t be used as an expression in other statements
Can be used as a table expression
Can be used as a scalar expression
Table 2.4 Comparison between Procedures, Table UDFs, and Scalar UDFs
79
Distinctive criteria
2 Getting Started with SQLScript
Procedures
Table UDFs
Scalar UDFs
Can contain any reading and writing SQL statements
May only contain reading SQL statements
Must not contain any table statements
Can call any functions and procedures
May call functions and reading procedures
May only call scalar UDFs
Table 2.4 Comparison between Procedures, Table UDFs, and Scalar UDFs (Cont.)
These criteria largely determine which of the three modularization techniques is best suited to solve your particular problem. If you need a reading subroutine that only returns a value or a table, you should prefer functions because they are easier to use. The following section deals with the concept of blocks, which you’ll encounter later when defining procedures and functions.
2.3.1 Blocks BEGIN and END
Blocks form parentheses around several statements. Blocks are either explicitly defined using BEGIN and END, or they can be an implicit part of a control structure, function, or procedure. Listing 2.13 provides some different examples of blocks. --Standalone block BEGIN
END; --Procedure definition CREATE PROCEDURE AS BEGIN
END; --Blocks in an IF/ELSE condition IF THEN
80
2.3
Modularization and Logical Containers
ELSE
END IF; --Block in a FOR loop FOR IN DO
END FOR; --Block in a WHILE loop WHILE DO
END WHILE; Listing 2.13 Examples of Different Blocks
A block consists of the following three optional sections:
Sections of a block
1. Explicit declaration of local variables via DECLARE. The implicit declaration of local table variables (see Chapter 3) can also be made later. 2. Declaration of exception handlers. 3. Statement list with the actual flow logic. The syntax of a standalone block is shown in Listing 2.14. BEGIN [] [] [] END; Listing 2.14 Syntax of Blocks
The declaration of local variables is described in Chapter 3 for table variables, and Chapter 6 focuses on scalar variables, where you’ll also find further information on exception handling. A list of statements consists of individual SQLScript statements, each of which ends with a semicolon. Because a block itself represents a statement, blocks can also be nested as deeply as you need. Note that the visibility of variables is always limited to the current block and its sub-blocks. Variables can also be redefined in sub-blocks and thus hide the variables of the surrounding blocks. The visibility of local variables is demonstrated in
81
2 Getting Started with SQLScript
Chapter 6 through an example. In principle, you should avoid using identical variable names.
Anonymous Blocks DO BEGIN and END
Anonymous blocks allow you to execute SQLScript statements directly in the SQL console. Without an anonymous block, statements can only be executed one by one. The block forms parentheses around a set of statements. Within these parentheses, variables can be used, and any SQLScript code can be executed. In this respect, an anonymous block is itself a statement and thus has similar properties to procedures and functions. However, unlike these elements, an anonymous block has no name. As a result, anonymous blocks can neither be stored as database objects nor called from outside the database. An anonymous block can be conceived as a procedure that is created, called, and deleted in a single step. The syntax of anonymous blocks is shown in Listing 2.15. DO [()] BEGIN [] [] [] END; Listing 2.15 Syntax of Anonymous Blocks
Because the anonymous blocks can’t be saved, using parameters seems pointless at first. However, parameters can be used to highlight input values of a block and display the output in the SQL console. Definition and parameterization
The parameters of an anonymous block are specified in parentheses between DO and BEGIN. Each parameter requires the following four specifications: 쐍 The parameter’s direction is determined via IN or OUT. 쐍 The parameter’s name is specified in simple notation. 쐍 The expected data type is either a scalar type or a table type. You can
either define the data type from scratch, or you can refer to an existing table or table type.
82
2.3
Modularization and Logical Containers
쐍 The arrow (=>) is used to bind input parameters to concrete values or to
link the output parameters, including a trailing question mark (?) to the console output. Tables are also allowed for IN parameters. However, only database tables can be transferred in an anonymous block. Listing 2.16 shows a simple example of an anonymous block with parameters. DO(IN iv_status INT => 1, OUT ot_tasks TABLE ( id INT, titleNVARCHAR(40) ) => ?) BEGIN ot_tasks = SELECT id, title FROM tasks WHERE status = :iv_status; END; Listing 2.16 Anonymous Block with Parameters
2.3.2 Procedures A procedure is a reusable block of statements stored in the database. These statements have been given a name and are linked to the context of the call via input and output parameters. The procedure can be implemented either in SQLScript or in the R programming language. The latter is especially suitable for statistical data processing but is beyond the scope of this book. For procedures, terms such as “stored procedures” are also common in other database systems. Procedures do not belong to the scope of the SQL standard but are extensions of SQLScript.
Creating Procedures You can create procedures using the CREATE PROCEDURE statement. Some development environments provide support by allowing you to generate the framework of this statement. A source code file is then created and stored in the package hierarchy. You can then generate the procedure from
83
CREATE PROCEDURE
2 Getting Started with SQLScript
within this file by saving it. Listing 2.17 shows the syntax of the CREATE PROCEDURE statement. CREATE [OR REPLACE] PROCEDURE [()] [LANGUAGE {SQLSCRIPT|RLANG} ] [SQL SECURITY {DEFINER|INVOKER} ] [DEFAULT SCHEMA defaultschema] [READS SQL DATA ] [WITH ENCRYPTION] AS BEGIN [SEQUENTIAL EXECUTION]
END Listing 2.17 Components of the CREATE PROCEDURE Statement
Most components of the CREATE PROCEDURE statement are optional or have default values and thus can be omitted. The remaining mandatory components consist of the basic structure shown in Listing 2.18. CREATE PROCEDURE AS BEGIN
END; Listing 2.18 Mandatory Part of the CREATE PROCEDURE Statement
These mandatory components tell the SAP HANA database that the procedure is to be created and stored with the specified name. The source code consists of a list of statements separated by semicolons.
Parameter Lists A procedure can have any number of parameters. For each parameter, a direction must be specified: IN, OUT, or INOUT. The values of IN parameters must not be changed in the procedure. Data and table types
The data type of the IN and OUT parameters can either be a scalar SQL data type (see Chapter 4) or a table-like data type. For INOUT parameters, only scalar data types are allowed.
84
2.3
Modularization and Logical Containers
The table type can either be a database table or a data type that has been generated via CREATE TYPE (see Chapter 7), or you can define a table type directly in the interface. Listing 2.19 shows an example of the different options for typing a parameter. CREATE PROCEDURE parameter_test ( --Scalar data type as input parameter IN iv_project INT, --Database table as type for an output parameter OUT ot_tasks tasks, -- A table type for an output parameter OUT ot_status_text id_text, -- Definition of the table type in the code: OUT ot_remaining_effort TABLE ( task INT, remaining_effort INT ) ) AS BEGIN ot_tasks = SELECT * FROM tasks WHERE project = :iv_project; ot_status_text = SELECT id, status_text AS TEXT FROM status_text; ot_remaining_effort = SELECT id AS task, planned_effort - effort AS remaining_effort FROM :ot_tasks; END; CALL parameter_test(2, ?, ?, ?); --DROP PROCEDURE parameter_test; Listing 2.19 Example of Creating, Executing, and Deleting a Simple Procedure
85
2 Getting Started with SQLScript
DEFAULT
For IN parameters, you can use the DEFAULT keyword to specify default values. In this case, these parameters don’t have to be bound when called. For scalar parameters, constant values can be used as default values. For table parameters, you can specify the name of a database table or a view instead. If no parameter is bound, the data is then read from it. Listing 2.20 shows an example of a procedure with default values for the IN parameters. The call can be made completely without parameters. If no other table is specified, the TASKS table is used for the query. --Definition of a procedure with default values CREATE PROCEDURE default_values ( IN iv_max_id INT DEFAULT 10, it_table tasks DEFAULT tasks ) AS BEGIN SELECT id, title FROM :it_table WHERE id 'EN', et_result=> lt_status_texts) ; END; Listing 2.21 Internal Procedure Call with Schema Specification
The CALL keyword is not necessary for internal calls, as shown in Listing 2.22. DO BEGIN statustexts(iv_langu=>'DE', et_result=> lt_status_texts) ; END; Listing 2.22 Internal Procedure Call without CALL Named parameters
Parameters can be named when called, as in the examples shown in Listing 2.21 and Listing 2.22. In this case, the order of the parameters in the call is irrelevant. The value is assigned with the character string =>. On the left side is the IN or OUT parameter, on the right side the corresponding value,
88
2.3
Modularization and Logical Containers
expression, or variable. If you specify a new table variable here, this variable is declared implicitly and initialized with the value. Listing 2.23 shows an example. DO BEGIN statustexts(iv_langu=>'EN', et_result=>lt_status_texts) ; SELECT * FROM :lt_status_texts; END; Listing 2.23 Declaration and Initialization of a New Table Variable When Calling a Procedure
As an alternative to using named parameters, you can specify the parameters in exactly the right sequence. In that case, you won’t need to specify any parameter names or use the character string =>, as shown in Listing 2.24.
Parameters per sequence
DO BEGIN statustexts('EN',lt_status_texts) ; SELECT * FROM :lt_status_texts; END; Listing 2.24 Procedure Call via the Position
In the examples shown in Listing 2.23 and Listing 2.24, the procedure was always called in a logical container. As a result, local table variables could be used, while the CALL keyword could be omitted. In calls from the SQL console, you can specify the OUT parameters using a question mark (?). If you specify parameters, the output is displayed in the data preview of the console. The question mark can be used with both named and unnamed parameters, as shown in Listing 2.25. --Call without parameter name CALL parameter_test(2, ?, ?, ?); --The same call with named parameters CALL parameter_test(iv_project=>2, ot_tasks=>?,
89
Internal calls
2 Getting Started with SQLScript
ot_status_text=>?, ot_remaining_effort=>?); Listing 2.25 Parameterization from the SQL Console
2.3.3 User-Defined Functions User-defined functions (UDFs) can be used in the same way as the SQL functions provided by the SAP HANA system. Thus, UDFs can be used wherever scalar expressions or table expressions are allowed. This feature enables their elegant inclusion in SELECT queries, as shown in Listing 2.12.
Creating UDFs Development environments don’t provide support for UDFs. You must create them from the SQL console using the CREATE FUNCTION statement. Listing 2.26 shows the syntax. CREATE FUNCTION [()] RETURNS [LANGUAGE SQLSCRIPT] [SQL SECURITY {DEFINER|INVOKER} ] [DEFAULT SCHEMA defaultschema] [DETERMINISTIC] AS BEGIN
END Listing 2.26 Syntax of the CREATE FUNCTION Statement
As shown in Listing 2.26, defining UDFs is similar to creating procedures. Accordingly, we’ll focus only on where UDFs differ from procedures.
Properties of UDFs In contrast to procedures, the optional parameter list, found in parentheses after the function name, defines only the IN parameters. Correspondingly, the IN keyword is optional and not needed. Otherwise, the parameter list
90
2.3
Modularization and Logical Containers
looks the same as for procedures. Default values for parameters are also permitted. The keyword RETURNS is followed by a definition of the return parameters. If table UDFs are used, the return parameter is exactly one unnamed table. Scalar UDFs can involve one or more named return parameters.
RETURNS
The specification of the programming language via LANGUAGE SQLSCRIPT is optional. Since UDFs can only be implemented in SQLScript so far, specifying a language is superfluous. SAP nevertheless recommends that you always specify the language.
LANGUAGE SQLSCRIPT
As with procedures, you can specify the security modes using SECURITY MODE.
SECURITY MODE
As of SAP HANA 2.0, you can use the DETERMINISTIC addition to tell the system that a scalar UDF for the same input always returns the same result. This addition allows the SAP HANA database to buffer the results. If you mark a function with the DETERMINISTIC addition, at the time of creation, the system checks that non-DETERMINISTIC functions, such as CURRENT_TIME, are not called
DETERMINISTIC
The statements of a function are specified in a block, as the procedures. However, some small differences between these functions and the blocks described in Section 2.3.1 exist. Both types of UDFs (scalar and table) have in common that only read access to the database is allowed.
AS BEGIN END
Listing 2.27 shows a simple example of a scalar UDF. CREATE FUNCTION udf_name ( iv_firstname NVARCHAR(20), iv_lastname NVARCHAR(20) ) RETURNS rv_name NVARCHAR(42) AS BEGIN rv_name = :iv_lastname || ', ' || :iv_firstname; END; Listing 2.27 Example of a Scalar UDF
A name for the display is composed of first name and last name. Listing 2.29 shows the use of this UDF. The example shown in Listing 2.28 is an example of a table UDF. The last statement in the function is always the RETURN statement.
91
2 Getting Started with SQLScript
CREATE FUNCTION udf_status_texts (iv_langu VARCHAR(2)) RETURNS TABLE ( id INT, status_text VARCHAR(20) ) AS BEGIN RETURN SELECT id, status_text FROM status_text WHERE langu = :iv_langu; END; Listing 2.28 Example of a Table UDF
Table 2.5 provides an overview of the most important differences between scalar and table UDFs. Scalar UDFs
Table UDFs
Only scalar parameters may be used.
Table parameters or scalar parameters can be used.
Multiple return parameters may be created. These parameters are given a name that is used to address them in the function itself.
There is exactly one unnamed table as return parameter. This table must be completely typed.
The default value for the security mode is DEFINER.
The default value for the security mode is INVOKER.
The block may only contain assignments to scalar variables. Declaring exception handling is not permitted here.
As the last statement in the block, you must use RETURN to return a table either via a SELECT statement or a table variable.
The RETURN statement is used to return the return value in the function.
Table 2.5 Differences Between Scalar and Table UDFs
Calling and Using UDFs User-defined functions can be used as expressions in other statements. A direct assignment of the result to local variables is only possible with scalar UDFs. If you use table UDFs, you must hide the function in a SELECT query. As shown in Listing 2.29, the result of previously defined UDFs is assigned
92
2.3
Modularization and Logical Containers
to local variables. However, the smarter approach is to use UDFs directly in SELECT queries, as shown earlier in Listing 2.12. DO BEGIN DECLARE lv_name NVARCHAR(42); --Assignment of scalar UDFs to scalar variables lv_name = udf_name( 'Jörg', 'Brandeis' ); SELECT lv_name FROM dummy; --Assigning a Table UDF to a Table variable lt_status_texts = SELECT * FROM udf_status_texts('EN'); SELECT * FROM :lt_status_texts; END; Listing 2.29 Assigning UDF Results to Local Variables
Scalar UDFs can also return more than one value. As shown in Listing 2.30, the function NOW defines two return values, DATE and TIME. These return values can be queried individually by specifying the name of the relevant return value separated by a period after the function call. CREATE FUNCTION RETURNS rv_time rv_date AS BEGIN rv_date rv_time = END;
udf_now TIME, DATE = CURRENT_DATE; CURRENT_TIME;
SELECT udf_now().rv_date, udf_now().rv_time FROM dummy; Listing 2.30 UDF with Multiple Return Values
Alternatively, all return values can be assigned at the same time, as shown in Listing 2.31. The target variables are in parentheses and in the correct sequence to the left of the equal sign.
93
2 Getting Started with SQLScript
DO BEGIN DECLARE lv_time TIME; DECLARE lv_date DATE; (lv_time, lv_date) = udf_now(); SELECT lv_date, lv_time FROM dummy; END; Listing 2.31 Simultaneous Assignment of all Return Values of a UDF
2.4 Sample Program To conclude this chapter, we would like to demonstrate a slightly more comprehensive sample program. We’ll describe the program step by step, from requirements to analysis and implementation to testing the functions. In this example, we’ll use statements and expressions that we haven’t discussed yet or only discussed superficially. Nevertheless, we consider the source code readable if you already have experience with programming languages. We recommend that you execute and modify all the examples found in the listings yourself. Only through practical experience will you get a feel for the behavior of SQLScript. If you can’t follow the example in this section yet, come back when you’ve worked through Chapter 3.
2.4.1 Requirements In our example, a scalar UDF will be created that determines the appropriate prices based on the properties of a package. If certain conditions are met, the package can be designated a small parcel, which requires special handling. Figure 2.9 shows DHL’s price table, which will be mapped via a UDF. The following framework conditions will be used in our example: 쐍 The maximum belt dimension (= L + 2W + 2H) for packages up to 10 kg is
300 cm. Packages that exceed this belt size will be charged as larger packages.
94
2.4 Sample Program
쐍 If the shipment is not possible, the price “0” and a corresponding mes-
sage should be returned, for example: – Weight too high – Dimensions too large – Not a small parcel 쐍 Once the price has been determined successfully, the message “Price
determined” should be returned. 쐍 Lower limits for the formats do not need to be checked.
Parcel prices Dimensions
Weight
Post office
Online franking
Small parcel up to 30 x 30 x 15 cm
up to 1 Kg
4.00
3.89
Small parcel up to 60 x 30 x 15 cm
up to 2 Kg
4.50
4.39
Parcel up to 60 x 30 x 15 cm
up to 2 Kg
-
4.99
up to 5 Kg
6.99
5.99
up to 10 Kg
9.49
8.49
up to 31.5 Kg
16.49
16.49
Parcel up to 120 x 60 x 60 cm
Figure 2.9 DHL Price Table (as of June 2018)
2.4.2 Requirements Analysis As a first step, we’ll try to structure and understand our requirements. In the following sections, we’ll consider individual aspects of the requirement.
Parameterization Our function needs the following information: 쐍 Weight (g) 쐍 Length (cm) 쐍 Width (cm)
95
2 Getting Started with SQLScript
쐍 Height (cm) 쐍 Should the package be sent as a small parcel? 쐍 Is the shipping cost based on the store price or the online price?
Dimensions should be given in centimeters; weights, in grams.
Linear Dimensions With regard to linear dimensions, the assignment of values to parameters plays a crucial role. The largest value should be the length; the second largest, the width; and the smallest value, the height. Otherwise, the formula for the belt dimension could provide incorrect results. The caller of the function is responsible for the correct assignment of the length parameters. Categories
Even if six price levels exists, we only have three different sizes according to which a distinction is made. Dividing sizes into categories (1 through 4) is a good idea. In our case, Category 4 means that the package has exceeded a maximum limit. A belt measurement higher than 300 cm automatically means that this package falls into the highest price tier.
Differentiation Between Store and Online In the price table, no price has been specified for parcels up to 2 kg for branch shipping, as no special price is needed for these packages. Therefore, the price for the next higher price level is applied. Price class
In order not to interweave the case distinctions too much, the introduction of a price class is appropriate. This class specifies the row to which a package belongs: 쐍 PN1—small parcel
쐍 PT3—package 10 kg
쐍 PN2—large package
쐍 PT4—package 31.5 kg
쐍 PT1—package 2 kg
쐍 NA—not determinable
쐍 PT2—package 5 kg
Program Flow According to our previous considerations, the following calculations must be carried out for price determination:
96
2.4 Sample Program
쐍 Determination of the size category from the linear dimensions 쐍 Determination of the belt dimension 쐍 Determination of the price class 쐍 Derivation of the price from the price class
These calculations should each be done in a separate function or procedure so that they are cleanly encapsulated. When determining the price class, it is best to identify situations in which shipping is not possible and a message is to be issued.
2.4.3 Implementation After the requirements have been analyzed, we’ll start with the implementation. There are different approaches to this, although we personally prefer the top-down approach: First, the main program is created with the basic structure of the steps from the requirements analysis. This basic framework can initially also consist of pseudo code, i.e., descriptive comments. These lines are then supplemented or replaced step by step with real code. The result is shown in Listing 2.32. CREATE FUNCTION udf_shipping_price ( iv_length INT, iv_width INT, iv_height INT, iv_weight INT, iv_as_small_Parcel VARCHAR(1), iv_is_online VARCHAR(1) ) RETURNS rv_price DEC(17,2), rv_message NVARCHAR(30) AS BEGIN --Determining the size category --Determination of the belt dimension --Price class determination --Deriving the price using the price class END; Listing 2.32 Framework of the UDF_SHIPPING_PRICE Function with Pseudo Code
97
2 Getting Started with SQLScript
The Structure of UDF_SHIPPING_PRICE UDF_VERSANDPREIS In the next step, we’ll add real code to the pseudo code (see Listing 2.33). We’ll act as if the used functions or procedures for the execution of the steps already exist. This procedure helps us consider which parameters are relevant for the individual functions or procedures and which variables we need to transfer the data between the calls. This listing can only be executed without errors at the very end if the functions and procedures used in each case exist. CREATE FUNCTION udf_shipping_price ( iv_length INT, iv_width INT, iv_height INT, iv_weight INT, iv_is_small_Parcel VARCHAR(1), iv_is_online VARCHAR(1) ) RETURNS rv_price DEC(17,2), rv_message NVARCHAR(30) AS BEGIN DECLARE lv_size_category INT; DECLARE lv_price_class VARCHAR(3); DECLARE lv_belt_dimension INT; --Determining the size category lv_size_category = udf_size_category(:iv_length, :iv_width, :iv_height); --Determining the belt dimension lv_belt_dimension = udf_belt_dimension(:iv_length, :iv_width, :iv_height); --Determining the price class call pr_price_class(:lv_size_category, :iv_weight,
98
2.4 Sample Program
:lv_belt_dimension, :iv_is_small_parcel, lv_price_class, rv_message); --Deriving the price using the price class rv_price = udf_price(:lv_price_class, :iv_is_online); END; Listing 2.33 Calculation of the Shipping Price per UDF
The values for size category, belt size, and price are determined in a scalar UDF. A procedure is created for the price class. The next step is to create and test the necessary functions and procedures one after the other. Only when these elements are available can the UDF_SHIPPING_PRICE function be created successfully.
The Size Category The size category is determined in the UDF_SIZE_CATEGORY function via a simple CASE expression within a SELECT statement (see Listing 2.34). You’ll learn more about the CASE expression in Chapter 3. But for now, note that, in SQLScript, CASE is an expression that returns exactly one value. Other programming languages use the CASE statement to control program flow so that various different statement sequences are processed, but the CASE expression in SQLScript is completely different. CREATE FUNCTION udf_size_category ( iv_length INT, iv_width INT, iv_height INT ) RETURNS rv_result INT AS BEGIN SELECT CASE WHEN :iv_length 219 --These could be interesting THEN CALL write_error_log(::sql_error_code, ::sql_error_message); ELSE RESIGNAL;--Better abort with these errors END IF;
281
RESIGNAL
6
Imperative Programming
END;--End of the error handling ... END; Listing 6.47 Forwarding Errors Using RESIGNAL
The RESIGNAL statement forwards the exception on a 1:1 basis if no further parameters are available. Other error codes and error texts can also be transferred. The syntax for this transfer corresponds exactly to the syntax of the SIGNAL statement. Therefore, you can, for example, enrich the original error text with further useful information, such as the database schema and the name of the current procedure. The error handler shown in Listing 6.48, for example, can add this information to the error text. DECLARE EXIT HANDLER FOR SQLEXCEPTION RESIGNAL SET MESSAGE_TEXT = 'Procedure' || ::CURRENT_OBJECT_SCHEMA || '.' || ::CURRENT_OBJECT_NAME ||::SQL_ERROR_MESSAGE; Listing 6.48 Error Handler with Database Schema and Procedure Added in Error Text
With the statements and concepts you have learned in this chapter, you can solve all problems on existing database models. However, to create your own database tables, views, and other database objects, you need additional statements, which you will learn in the next chapter. In addition, further concepts such as sequences and triggers will be explained.
282
Chapter 7 Creating, Deleting, and Editing Database Objects Not only can you write data to existing database tables and read this data from them again with SQL, you can also create tables and other database objects directly. In this chapter, we’ll show you how to manage database objects like tables, table types, views, and more.
In most cases, you’ll use the modeling tools found in your development environment to create database objects, such as tables or views. In this chapter, you’ll learn how to create database objects directly using SQL. The SQL statements needed for this topic are referred to as data definition language (DDL). In addition, we’ll introduce you to a few other useful database objects, such as sequences and triggers. Back in Chapter 2, you learned how to create procedures and functions. In general, you can create, delete, and change other database objects according to the same schema: 쐍 CREATE
You always use CREATE to generate new database objects: CREATE
; 쐍 ALTER
Changes to the object definition are implemented using the ALTER statement: ALTER
;
283
CREATE, ALTER, and DROP
7
Creating, Deleting, and Editing Database Objects
쐍 DROP
The DROP statement allows you to delete an object: DROP ;
The listings shown in previous chapters contained examples that included the CREATE and DROP statements when a table was created for only one listing and then was deleted afterward. Object definitions can involve many fine details, which we won’t describe too deeply in this book. Instead, refer to the reference documentation “SAP HANA SQL and System Views Reference” at http://bit.ly/1822_701, which lists all available options for the various system statuses.
7.1 Tables Let’s start with the most important object type in a database—the database tables. The current reference documentation (http://bit.ly/1822_702) for the CREATE and ALTER TABLE statements alone consists of almost 50 pages with brief, keyword-like descriptions for all the options available for defining and altering database tables. In the following sections, we’ll focus on basic table definition and describe some interesting features from a developer perspective. Thus, we won’t cover the parameterization for administration, partitioning, storage behavior, etc., in this book.
7.1.1 Creating Database Tables CREATE TABLE
In the simplest variant, to create a database table, you only need to define the columns in the table definition of the CREATE TABLE statement, for example, as follows: CREATE TABLE status (id INT , text NVARCHAR(30) );
All other table properties correspond to the default values of the CREATE TABLE statement.
284
7.1
Tables
Column Definition Columns are defined after the table name in parentheses. All column definitions are listed one after the other, separated by commas. These definitions usually look like the ones shown in Listing 7.1.
[DEFAULT ] [] Listing 7.1 Column Definition
A default value is used when a new record is inserted, but no value is specified for this column. In addition, you can also define constraints for each column, as shown in Listing 7.2, such as the following: 쐍 NOT NULL
The column value must be defined; otherwise, a data record can’t be inserted. 쐍 UNIQUE
In this column, every value (except NULL) may occur only once. 쐍 PRIMARY KEY
The column is the sole primary key. As a result, this column automatically has the properties NOT NULL and UNIQUE. CREATE TABLE status (id INT PRIMARY KEY, sort_nr INT NOT NULL UNIQUE, text NVARCHAR(30) ); Listing 7.2 Example of Constraints on Individual Columns
If the two constraints UNIQUE or PRIMARY KEY refer to more than one column, you can also specify the respective constraints after the relevant column definitions, as shown in Listing 7.3.
285
Constraints for multiple columns
7
Creating, Deleting, and Editing Database Objects
CREATE TABLE test_unique (a INT, b INT, c INT, UNIQUE(a, b), UNIQUE(b, c)); Listing 7.3 Example of Multiple UNIQUE Constraints on Multiple Columns
In the example shown in Listing 7.3, the combined values from columns A/ B and B/C must be unique for each row. Note that multiple NULL values are permitted in this context. A composite primary key is similar to a UNIQUE constraint, and additionally, the NOT NULL constraint is valid for each column, as shown in Listing 7.4. CREATE TABLE test_composite_key (a INT, b INT, c INT, PRIMARY KEY(a, b)); Listing 7.4 Example of a Composite Primary Key
Type of Table In the context of an SAP HANA database, we basically differentiate between two types, ROW and COLUMN, for tables. The type of a database table is determined optionally during the process of its creation using the following statement: CREATE [] TABLE ROW
The ROW value for a type means that the table contents will be stored row by row in the row store. This type is therefore particularly suitable if only a few data records need to be read but their full width is relevant.
COLUMN
In contrast, the table type, COLUMN stores the data column by column in the column store. This type may seem absurd at first, but the advantage is that, for example, with more complex SQL queries, only the columns relevant for determining the result set will be processed first. Additional columns can be added later. SAP recommends using COLUMN tables whenever you need to process a large number of data records, of which you only need a relatively small number of columns.
286
7.1
Tables
When selecting the appropriate storage type, you should also take into account that read access to ROW and COLUMN tables are controlled by different engines. A join using tables of both types forces the engines to change, which means that the data must be copied once. The following four types can be used to create temporary tables. Their properties have already been described in detail in Chapter 6, Section 6.1.4.
Types
쐍 GLOBAL TEMPORARY [ROW] 쐍 GLOBAL TEMPORARY COLUMN 쐍 LOCAL TEMPORARY [ROW] 쐍 LOCAL TEMPORARY COLUMN
Default Value for the Table Type Up to and including SAP HANA 2.0 SPS 02, the default value for the type is ROW. With the release of SPS 03, the default value has been set to COLUMN. If you need to reverse this change, you can define the default value yourself in the configuration file indexserver.ini via the default_table_type parameter. This parameter was available before SPS 03 and won’t be overwritten during upgrades. You can find more information on this topic in the SAP Note 2551355.
Automatic Number Assignment You can specify that a column be automatically filled with sequential numbers, which is similar to using a sequence, which we’ll describe in detail in Section 7.4. The addition GENERATED BY DEFAULT AS IDENTITY at the end of a column definition causes the assignment of a sequential number if no value for the column has been specified during the insertion process. Alternatively, you can use GENERATED ALWAYS AS IDENTITY to constantly force the generation of a sequential number, as shown in Listing 7.5. CREATE COLUMN TABLE test_identity ( a INT GENERATED BY DEFAULT AS IDENTITY, b VARCHAR(10));
287
Automatic number assignment
7
Creating, Deleting, and Editing Database Objects
INSERT INSERT INSERT INSERT
INTO INTO INTO INTO
test_identity test_identity test_identity test_identity
(b) VALUES ('One'); (b) VALUES ('Two'); (a,b) VALUES (3, 'Three'); (b) VALUES ('Four');
SELECT * FROM test_identity; Listing 7.5 Automatic Number Assignment
For the number assignment, you can also use other options such as a start value or an increment by which an increase should be carried out. These options are described in more detail in Section 7.4.1, which deals with sequences.
Copying a Table CREATE TABLE LIKE
If you want to create a table that should be defined exactly like an existing table, you can use the following statement: CREATE TABLE LIKE [WITH DATA];
The addition WITH DATA ensures that all data from the original table is copied into the new table. Especially for testing and error analysis, such table copies can be quite useful.
Creating a Table Based on an SQL Query CREATE TABLE AS
You can also create database tables with a SELECT query, as shown in Listing 7.6. In this context, the columns of the field list are used for the column definition. CREATE TABLE tmp_tasks AS ( SELECT a.id, b.firstname, b.lastname, t.team_text FROM tasks AS a LEFT OUTER JOIN users AS b ON a.assignee = b.id
288
7.1
LEFT OUTER JOIN team_text AS t ON b.team = t.id ) WITH DATA; Listing 7.6 Creating a New Table Based on an SQL Query
As with CREATE TABLE ... LIKE ..., you can use the WITH DATA addition as well. This addition inserts the query data directly into the new database table, which can be quite helpful for testing and error analysis. For example, if you want to save the contents of a table for later comparison, this variant of the CREATE TABLE statement enables you to store the result as a new table.
7.1.2 Changing Database Tables When database tables are changed, the individual properties of the existing definition are changed. For this reason, the ALTER statement doesn’t contain the entire table definition, only the properties that are actually to be changed. Listing 7.7 contains some examples of changing the most important table properties. CREATE ROW TABLE demo_table( col1 INT, col2 INT ); --Adding a column ALTER TABLE demo_table ADD (col3 VARCHAR(20)); --Change column properties, e.g. set default value: ALTER TABLE demo_table ALTER (col1 INT DEFAULT 42); --Add the primary key definition: ALTER TABLE demo_table ADD CONSTRAINT pk PRIMARY KEY (col1, col2); --Changing the type: ALTER TABLE demo_table COLUMN; Listing 7.7 Example of Changing the Table Properties
289
ALTER TABLE
Tables
7
Creating, Deleting, and Editing Database Objects
In the database catalog, right-click on the relevant table and select Open Definition from the context menu to view the current table definition. Now, you can reproduce the changes from the listing step by step. Figure 7.1 shows the state of the table definition once all changes have been made.
Figure 7.1 Definition of the Table from Listing 7.7
7.1.3 Deleting Database Tables DROP TABLE
When deleting database tables, the details of the definition aren’t necessary. The statement DROP TABLE causes the permanent deletion of a table including its entire contents.
Proceed with Caution when Deleting The DROP TABLE statement enables you to delete entire tables including their contents. No security question will ask, “Are you sure you want to delete the table and its contents?” to confirm the action. Thus, this statement is extremely dangerous, especially in combination with dynamic SQL. You should only execute this statement for production tables if you are 100% sure deletion won’t cause a major problem. Before deleting a table, cautious people will use CREATE TABLE ... LIKE ... WITH DATA to create a backup copy of the table, including its data. RESTRICT/CASCADE
The RESTRICT addition ensures that a table is deleted only if no dependencies with other objects exist. Alternatively, the CASCADE addition allows you to determine that dependent objects should be deleted as well.
290
7.3
7.2 Table Types User-defined table types are used exclusively for defining and calling procedures and functions. Correspondingly, in the database catalog, these table types are represented as subitems for the procedures in most development environments, as shown in Figure 7.2.
Figure 7.2 Table Types in the SAP HANA Web-Based Development Workbench Database Catalog
The definition of a table type consists only of the columns that are defined exactly as in the definition of database tables, as shown in Listing 7.8. CREATE TYPE my_type AS TABLE( col1 INT, col2 VARCHAR(10) ); CREATE PROCEDURE my_procedure( IN it_data my_type ) AS BEGIN ... Listing 7.8 Example of Defining and Using a Table Type in a Procedure Definition
7.3 Views A view is a named SELECT query that can be accessed by its name. Views are also sometimes called virtual tables because they do not contain any data themselves. However, you can use views like a table in a SELECT query.
291
Views
7
Creating, Deleting, and Editing Database Objects
Example
Listing 7.9 shows an example: The table invoice_positions contains the individual items of an invoice. The invoices view shows the amount per row and totals the amounts per invoice and currency. CREATE TABLE invoice_position( invoice_nr INT, position INT, product NVARCHAR(30), quantity INT, amount DEC(17,2), currency VARCHAR(5), primary key (invoice_nr, position) ); CREATE VIEW invoices AS SELECT invoice_nr, SUM(amount*currency) as amount, currency FROM invoice_position GROUP BY invoice_nr, currency; INSERT INTO invoice_position VALUES (1, 10, 'TVs', 1, 765.23, 'EUR'); INSERT INTO invoice_position VALUES (1, 20, 'Cable' , 1, 12.99 , 'EUR'); INSERT INTO invoice_position VALUES (1, 30, 'Batteries', 4, 1.99 , 'EUR'); INSERT INTO invoice_position VALUES (2, 10, 'Computer mouse', 1, 23.99 , 'EUR'); INSERT INTO invoice_position VALUES (3, 10, 'Cable' , 2, 12.99 , 'EUR'); INSERT INTO invoice_position VALUES (3, 20, 'Network switch' , 1, 27.99 , 'USD'); --SELECT query to the table SELECT invoice_nr, SUM(amount*quantity) as amount, currency FROM invoice_position
292
7.3
GROUP BY invoice_nr, currency; --SELECT query on the VIEW SELECT * FROM invoices; Listing 7.9 Example of a View as a Stored SELECT Query
When you run this example, you’ll see that the two queries return exactly the same result. The advantage of using the view, however, is that the logic in the view can be reused. In this example, the simplest syntax for creating a view is as follows: CREATE VIEW AS ;
As of SAP HANA 2.0 SPS 02, views can have input parameters. These input parameters are defined in a similar manner as functions and procedures and can then be used in different places within a query, as shown in Listing 7.10. CREATE VIEW invoices (IN iv_currency VARCHAR(5)) AS SELECT invoice_nr, SUM(amount*quantity) as amount, currency FROM invoice_position WHERE currency = :iv_currency GROUP BY invoice_nr, currency; Listing 7.10 Defining Parameterized Views
For expressions in the SELECT query to refer to the parameters, the parameters are preceded by a colon, much like in procedures or functions. The parameterization for the querying of views is carried out in the same way as the parameterization of procedures and functions: SELECT * FROM invoices( 'USD' ); SELECT * FROM invoices( iv_currency=>'USD' );
293
Parameters
Views
7
Creating, Deleting, and Editing Database Objects
Parameters are assigned either by their position or sequence, or by the names of the parameters. Even if all parameters of a view have been assigned a default value, the call must still be made with parentheses.
7.4 Sequences A sequence enables you to generate unique, sequential integer numbers across an entire system. The database ensures that these properties are maintained, even if several users query numbers over a sequence in several sessions in parallel. As a result, sequences are suitable for assigning technical keys or document numbers, for example. Database columns with automatic number assignment (Section 7.1.1) also contain sequences. ABAP developers are familiar with a similar concept: number ranges. Their properties largely correspond to those of the sequences. CREATE SEQUENCE
The statement CREATE SEQUENCE ; generates a simple sequence that starts at 1 and counts up continuously until its maximum value of 263-1 is reached. The statement .nextval always provides the next value of the sequence until the maximum value is reached, after which a database error is generated. The expression .currval allows you to query the last delivered value without counting upward. If the properties of a simple sequence do not fit, you can change them with additional parameters, as in the following statement: CREATE SEQUENCE
7.4.1 Increment Normally, a sequence counts continuously up by 1. The parameter INCREMENT BY allows you to define a different value. This value can also be negative if the sequence needs to count down instead of up.
7.4.2 Limits You can use the following parameters to define the limits within which a sequence operates:
294
7.4 Sequences
쐍 MINVALUE
쐍 NO MINVALUE
쐍 MAXVALUE
쐍 NO MAXVALUE
Depending on the counting direction of the sequence, the value at the first call of NEXTVAL corresponds to the values MINVALUE or MAXVALUE.
7.4.3 Behavior When Reaching the Limit If the upper or lower limit of a sequence is reached, a database error occurs. By using the CYCLE parameter in this situation, you can avoid this error, and the sequence will start again at its original start value. Listing 7.11 shows an example of defining a sequence that counts down from 10 to 0 and then starts over again. In the following anonymous block, the sequence is queried a hundred times in a loop, the result is stored in an array, and the array is converted into a local table. This table is then read out at the end. CREATE SEQUENCE countdown INCREMENT BY-1 MAXVALUE 10 MINVALUE 0 CYCLE; DO BEGIN DECLARE lv_counter INT; DECLARE lv_tmp INT; DECLARE la_array INT ARRAY; FOR lv_counter IN 1..100 DO SELECT countdown.nextval INTO lv_tmp FROM DUMMY; la_array[:lv_counter] = lv_tmp; END FOR; lt_output = UNNEST(:la_array); SELECT * FROM :LT_OUTPUT; END; Listing 7.11 Example of Using a Sequence
295
7
Creating, Deleting, and Editing Database Objects
The result shows that the sequence worked as desired. What is remarkable about this listing is that the sequence was used in a SELECT query of the DUMMY table. The reason for this is that it is not permitted to use the direct assignment lv_tmp = countdown.nextval. Sequences may only be used in SELECT, INSERT, or UPDATE statements.
7.4.4 Resetting the Sequence RESTART WITH
A sequence should normally count continuously. Manual intervention is not desired at all. However, intervention is possible via the statement ALTER SEQUENCE RESTART WITH ;.
7.4.5 Changing and Deleting a Sequence As with other database objects, the ALTER SEQUENCE statement allows you to change individual properties of a sequence. You can use DROP SEQUENCE to delete a sequence. If you create a new sequence with the same name, it starts again with its start value.
7.5 Triggers A trigger is an SQLScript procedure that is automatically executed whenever a database table is accessed and modified. In this context, you can specify the time (BEFORE or AFTER) and the type of the event (INSERT, UPDATE, or DELETE). Listing 7.12 contains an example of triggers that log insert and update operations to table invoice_position (including time, date, and user) into the table RP_LOG. Creating triggers
Two different triggers are created so that, in the log in the Action field, a distinction can be made between insert (I) and update (U). CREATE SEQUENCE lognr; --technical key of the log CREATE TABLE invoice_position( invoice_nr INT, position INT, product NVARCHAR(30),
296
7.5
quantity amount currency primary key
INT, DEC(17,2), VARCHAR(5), (invoice_nr, position)
); CREATE TABLE rp_log( log_nr INT, invoice_nr INT, position INT, users VARCHAR(80), datum DATE, zeit TIME, action VARCHAR(1) ); --Trigger for inserting CREATE TRIGGER rp_insert AFTER INSERT ON invoice_position REFERENCING NEW ROW ls_new FOR EACH ROW BEGIN INSERT INTO rp_log VALUES( lognr.nextval, :ls_new.invoice_nr, :ls_new.position, current_user, current_date, current_time, 'I'); END; --Trigger for updating CREATE TRIGGER rp_update AFTER UPDATE ON invoice_position REFERENCING NEW ROW ls_new FOR EACH ROW BEGIN INSERT INTO rp_log VALUES( lognr.nextval, :ls_new.invoice_nr, :ls_new.position,
297
Triggers
7
Creating, Deleting, and Editing Database Objects
current_user, current_date, current_time, 'U'); END; INSERT INTO invoice_position VALUES (1, 10, 'Chocolate', 1, 1.99, 'EUR'); INSERT INTO invoice_position VALUES (1,20, 'Espresso coffee beans', 1, 13.99, 'EUR'); UPDATE invoice_position SET amount = '12.99' WHERE invoice_nr = 1 AND position = 20; SELECT * FROM rp_log; Listing 7.12 Example of a Trigger for Automatic Change Logging
Triggers are always executed at the defined times. Triggers cannot be bypassed during write access. Triggers are therefore suitable for requirements such as change logging, access control, or consistency assurance. For example, a trigger can remove all dependent records when deleting a record.
Triggers Limit Reproducibility Triggers can be used to execute a portion of the application logic in an event-driven manner when accessing a database table. However, other programmers could find understanding the program sequence difficult and the code hard to read. Triggers can also trigger other triggers themselves, which further reduces the clarity. Therefore, triggers should only be used sparingly, if at all. For a development team, full visibility about all existing triggers can be difficult to achieve for all team members.
298
7.5
Triggers
7.5.1 Parameters Within a trigger, the data of the SQL statement can be accessed using two values, OLD and NEW, which can be assigned to a variable in the trigger definition. The value OLD corresponds to the old data in the database that is affected by the statement. This value is only available with DELETE and UPDATE. The value NEW contains the new data and can therefore only be used with INSERT and UPDATE. CREATE TRIGGER rp_update AFTER UPDATE ON invoice_position REFERENCING NEW ROW ls_new OLD ROW ls_old FOR EACH ROW ... Listing 7.13 Assigning OLD and NEW to Local Variables
7.5.2 Per Row or Per Statement In the example shown in Listing 7.12, triggers are executed for each inserted or updated row. You can also execute one trigger per statement to be updated. However, as a result, more than one row could be modified at a time. Accordingly, the assignments of the OLD and NEW parameters of the trigger must be defined as a table as well. Listing 7.14 contains an example of creating a trigger with row-based processing. Listing 7.15 shows an example of processing per statement. CREATE TRIGGER rp_insert AFTER INSERT ON invoice_position REFERENCING NEW ROW ls_new FOR EACH ROW ... Listing 7.14 Parameterization for Row-Based Processing
299
OLD and NEW
7
Creating, Deleting, and Editing Database Objects
CREATE TRIGGER rp_insert AFTER INSERT ON invoice_position REFERENCING NEW TABLE AS lt_new FOR EACH STATEMENT ... Listing 7.15 Parameterization for Processing per Statement with Table Parameters
By wrapping up with SQL statements for creating, changing, and deleting database objects, we are finished with our exploration of individual language components. In the next section, we'll deal with the SAP NetWeaver application server and the ABAP programming language, located above the database. This is how we'll access SQLScript.
300
Chapter 8 SQLScript in ABAP Programs To enable the use of SQLScript from within ABAP programs, various options are available, for example, the ABAP Managed Database Procedures (AMDP) framework or table functions. In this chapter, we’ll provide you an overview of these techniques.
In previous chapters, you learned how to write effective SQLScript source code. You can use various options to call this source code from within the SAP NetWeaver ABAP platform. From the ABAP perspective, SQLScript basically is Native SQL, which is how all database-specific SQL dialects are described. The opposite of Native SQL is Open SQL, which is part of the ABAP programming language. Open SQL is database-independent and is translated into the corresponding Native SQL at runtime.
Consider Other Database Systems If you use Native SQL in ABAP, the corresponding programs and classes are restricted for use in a particular database system. To be compatible for multiple database systems, you must develop along several tracks. Accordingly, you should create different implementations for the various SQL variants. In this chapter, we’ll focus on following a two-track approach in the examples, using both: 쐍 SQLScript for the SAP HANA database 쐍 Open SQL for all other databases
The term ABAP Managed Database Procedure (AMDP) stands for the framework recommended by SAP for using SQLScript code in ABAP programs. This concept serves as the basis for creating, managing, and calling database procedures and functions. The basic idea behind AMDP is that the
301
AMDP
8
SQLScript in ABAP Programs
source code of SAP HANA database objects can be wrapped in the implementation of methods of an ABAP class. The corresponding SAP HANA database object is then generated from this, when required. Three different objects can be created with the AMDP framework: 쐍 AMDP procedures can be called like methods of an ABAP class. These pro-
cedures are implemented in SQLScript. The caller of the method doesn’t know that the procedure is actually a database procedure. 쐍 CDS table functions are AMDP functions that are encapsulated by a core
data services (CDS) object and can therefore be called from ABAP or Open SQL like a normal database view via a SELECT query. 쐍 AMDP functions for AMDP methods can’t be called directly from ABAP or
Open SQL. However, these functions can be used when implementing other AMDP objects in SQLScript source code. Table 8.1 compares the most important properties of the three objects. AMDP Procedure
CDS Table Function
AMDP Function
Call from ABAP
Like an ABAP method
In a SELECT statement
Not possible
Implementation
In a static or instance method
In public, static method of a static class
In a static or instance method
Two-track development
Inheritable
Possible by case distinction
Not relevant, since only callable from other AMDP methods
Type of data access
Read and write
Read-only
Read-only
Where are the parameters defined?
When you define the method
In the definition of the CDS object
When you define the method
Type of parameters
Any IMPORTING , EXPORT, and CHANGE
Any scalar IMPORTING and exactly one tablelike RETURNING parameter
Any scalar IMPORTING and exactly one tablelike RETURNING parameter
Table 8.1 Comparison of the Three AMDP Objects
302
SQLScript in ABAP Programs
AMDP Framework With the release of SAP NetWeaver 7.4 SPS 05, ABAP Managed Database Procedures (AMDPs) were introduced as a framework for managing and calling database procedures in the SAP HANA database. With the release of SAP NetWeaver 7.5, AMDP functions have been added to this concept. Although these functions are technically not procedures, but functions, the name AMDP is also used for them. AMDP classes are classes that implement the interface IF_AMDP_MARKER_ HDB and that contain at least one AMDP method. AMDP methods can be either AMDP procedures or AMDP functions. AMDP functions either implement a CDS table function, or AMDP functions are available internally for other AMDP methods.
The AMDP framework provides ABAP developers with extensive options for implementation according to the code-to-data paradigm. Direct access to the SAP HANA database is not absolutely necessary since all development objects can be implemented via the ABAP development tools in the Eclipse development environment. You can also use a debugger for the SQLScript code in the AMDP methods. This AMDB debugger is described in more detail in Chapter 11, Section 11.2.3.
Tools
If SAP HANA data models such as calculation views are modeled or if procedures and functions are developed outside the AMDP framework, direct database access with corresponding authorizations will be necessary. The Eclipse plug-ins from SAP HANA Studio must also be installed. When does using SQLScript in an ABAP program make sense? No general answer exists for this question. Basically, the use of AMDPs makes sense above all when significant performance improvements can be achieved, which is particularly the case in the following scenarios: 쐍 If using SQLScript prevents the transport of large amounts of data
between the database and the application server. 쐍 If the SQLScript procedure is programmed declaratively and can there-
fore be easily parallelized and optimized by the SAP HANA database. 쐍 If the transformations with routines are to be executed directly in the
SAP HANA database in SAP Business Warehouse (SAP BW). Data transfer
303
Benefits of AMDP
8
SQLScript in ABAP Programs
processes (DTPs) will be accelerated considerably, regardless of whether the previous ABAP code worked with database accesses or not. Disadvantages
But the use of AMDPs also has a few disadvantages. You must always consider whether you want to accept these disadvantages for the expected performance improvements. The following reasons, among others, speak against the use of AMDPs: 쐍 The application developer must be proficient in several programming
languages. Sometimes, a well-implemented ABAP method is better than a poorly implemented AMDP. 쐍 SAP GUI is not suitable for developing AMDPs. 쐍 The application logic is distributed between the database server and the
application server. 쐍 Performance is not improved in all cases. 쐍 The developments can’t be used in other database systems. For a suitable
procedure for parallel development, still leveraging the advantages of SAP HANA with AMDPs, Section 8.1.4. Alternatives
You should always evaluate the alternatives before using AMDPs, including, for example, CDS views and the extended features of Open SQL of the latest SAP NetWeaver releases. According to the SAP documentation (http:// bit.ly/1822_801), AMDPs should only be used if database-specific functions, such as the SQL function for currency conversion, is required but not available in Open SQL, or if the transport of large amounts of data between database server and application server must be avoided.
8.1 AMDP Procedures From the point of view of an ABAP developer, an AMDP procedure is a method of an ABAP class, which is implemented in the SQLScript programming language. Being amethod solves several problems, such as the following: 쐍 The SQL procedure is called as a method call of an ABAP class. As a result,
the procedure call is perfectly integrated in ABAP.
304
8.1
AMDP Procedures
쐍 The transport of the database procedure is performed using the ABAP
class rather than requiring several transport mechanisms that have to be kept in sync. 쐍 At the time of development, the developer does not need direct access to
the SAP HANA database with the appropriate authorizations. Working with the usual ABAP developer authorizations with the ABAP development tools is sufficient. In the following sections, the terms AMDP and AMDP procedure are used interchangeably. If not explicitly mentioned, the information doesn’t refer to AMDP functions.
8.1.1 Creating AMDP Procedures You can create an AMDP method only in a global class, which implements the marker interface IF_AMDP_MARKER_HDB. The interface itself has no methods; it serves exclusively to mark the AMDP classes. An AMDP class can include both normal ABAP methods and AMDP methods. Whether a method is implemented as AMDP is not specified in the method declaration. Listing 8.1 shows an example. CLASS zcl_amdp_demo DEFINITION PUBLIC CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_amdp_marker_hdb. TYPES gty_tt_countries TYPE TABLE OF t005t . METHODS get_countries IMPORTING VALUE(iv_langu) TYPE langu EXPORTING VALUE(et_country) TYPE gty_tt_countries CHANGING VALUE(cv_subrc) TYPE sy-subrc. ENDCLASS. CLASS zcl_amdp_demo IMPLEMENTATION. METHOD get_countries
305
IF_AMDP_MARKER_ HDB
8
SQLScript in ABAP Programs
BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT USING t005t. et_country = select * from t005t where spras = :iv_langu; SELECT CASE WHEN COUNT(*) > 0 THEN 0 ELSE 4 END AS subrc INTO cv_subrc FROM :et_country; ENDMETHOD. ENDCLASS. Listing 8.1 Example of a Simple AMDP Method
Restrictions on the Method Signature An SQLScript procedure is generated at a later time from the source code of an AMDP method. However, these database procedures are more restrictive with regard to parameters than ABAP methods. Accordingly, the following restrictions must of course also apply to AMDP methods: 쐍 First, all parameters must be completely typed. Generic data types such
as TYPE TABLE or REF TO DATA are not permitted. 쐍 Since SQLScript doesn’t know any structures, only scalar data types and
table types may be used as parameters. The table types can only use scalar data types in their row structure. 쐍 All parameters must be transferred as value parameters (call by value);
you can’t use any reference parameters (call by reference). The reason for this restriction is obvious when you consider that the application server is running on a different system than the database. Accordingly, no shared memory area exists that both systems reference. 쐍 You can only use IMPORTING, EXPORTING, and CHANGING parameters with
AMDP procedures. The use of RETURNING parameters is not possible.
306
8.1
AMDP Procedures
쐍 Only AMDP exception classes can be declared in the signature of the
method. These exception classes are the subclasses of CX_AMDP_ERROR. If these exception classes are declared, the caller of the AMDP method can handle these exceptions. However, if not declared, these errors result in a dump.
Implementing an AMDP Procedure AMDP procedures are developed in the SQLScript language, which is indicated to the system by the addition BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT. If an AMDP implementation only reads data, you can optionally specify the addition OPTIONS READ-ONLY.
OPTIONS READ-ONLY
The optional addition USING enables you to tell an AMDP implementation that you want to use the corresponding tables, views, AMDP functions, or AMDP procedures from the default database schema of the SAP NetWeaver system. Thus, you can use this name without having to explicitly specify the relevant database schema in the SQLScript source code. The objects are only separated by whitespaces and listed after the keyword USING. Note that this code is still ABAP code. If, for example, you specify a table generated by SAP BW from the generation namespace, /BIC/ or /BI0/, you do not need to use any quotation marks, for example:
USING
...USING /BI0/PPLANT.
If you access this table in SQLScript code, however, you must use special notation, since the slash is not permitted in simple notation, as in the following: SELECT ... FROM "/BI0/PPLANT".
The use of AMDP procedures and functions is declared in the USING clause via the name of the associated ABAP method using the notation CLASS=>METHOD. Listing 8.2 contains an example of the keywords in the METHOD clause of the method implementation. Everything after the period in line 5 up to the keyword ENDMETHOD is interpreted as SQLScript.
307
USING for AMDP objects
8
SQLScript in ABAP Programs
1 METHOD get_countries 2 BY DATABASE PROCEDURE FOR HDB 3 LANGUAGE SQLSCRIPT 4 OPTIONS READ-ONLY 5 USING t005t. 6 7
8 ENDMETHOD. Listing 8.2 Keywords for Implementing an AMDP Method
A General Concept for a Specific Database Basically, all instructions and declarations in connection with AMDP are designed in such a way that AMDPs can be implemented in different database systems and in different languages. Accordingly, the implementation of AMDP methods also includes the mandatory entries FOR and LANGUAGE . However, to date (SAP NetWeaver 7.51), only implementations for the SAP HANA database with the SQLScript language are possible. The language L may only be used within SAP. The other database systems under SAP NetWeaver each have their own programming languages, such as Oracle’s PL/SQL language. However, these languages can’t be used to implement AMDPs.
8.1.2 Generated Objects of an AMDP Method An ABAP class serves as an envelope for the code of the AMDP procedure. Some SAP HANA database objects are automatically generated from this class. Figure 8.1 shows the objects generated by the procedure found in Listing 8.1. Note that a table type, two procedures, a database table, and a view have been generated for an AMDP method. Each object has its own special tasks, which we’ll explain next.
308
8.1
Figure 8.1 Generated Objects of an AMDP Procedure
The Generated AMDP Procedure The procedure ZCL_AMDP_DEMO=>GET_COUNTRIES contains the actual SQLScript source code. However, the code has been slightly modified, as shown in Listing 8.3. CREATE PROCEDURE "ZCL_AMDP_DEMO=>GET_COUNTRIES" ( IN "IV_LANGU" NVARCHAR (000001), OUT "EV_SUBRC" INTEGER, IN "CT_COUNTRY__IN__" "ZCL_AMDP_DEMO=>GET_COUNTRIES=>P00000# ttyp", OUT "CT_COUNTRY" "ZCL_AMDP_DEMO=>GET_COUNTRIES=>P00000#ttyp" ) LANGUAGE sqlscript SQL SECURITY INVOKER AS BEGIN "CT_COUNTRY" = select * from :CT_COUNTRY__IN__ ; BEGIN lt_countries = SELECT land1 FROM :CT_COUNTRY; et_country = SELECT t5.* FROM "ZCL_AMDP_DEMO=>T005T#covw" AS t5 INNER JOIN :LT_COUNTRIES AS countries ON t5.land1 = countries.land1 WHERE t5.spras = :IV_LANGU;
309
AMDP Procedures
8
SQLScript in ABAP Programs
SELECT CASE WHEN COUNT(*) > 0 THEN 0 ELSE 4 END AS subrc INTO ev_subrc FROM :CT_COUNTRY; END; END; Listing 8.3 Source Code of Procedure ZCL_AMDP_DEMO=>GET_COUNTRIES Parameter list
The relevant passages in the source code are highlighted in bold type. First, you’ll see the parameter list. Notice that the CHANGING parameter CT_COUNTRY occurs twice. This repetition is because, in SQLScript, an INOUT parameter must have a scalar type. Thus, in addition to the OUT parameter CT_COUNTRY, the IN parameter CT_COUNTRY__IN__ is created. In the first line after AS BEGIN, the parameter CT_COUNTRY is filled with the contents of CT_COUNTRY__IN__. This simulates the behavior of a CHANGING parameter.
Table Types for the Table Parameters In the parameter interface of an SQLScript procedure, all parameters must be typed. In the case of table parameters, corresponding table types are created for AMDP procedures. In our example, CT_COUNTRY is typed using the generated table type ZCL_AMDP_DEMO=>GET_COUNTRIES =>P00000#ttyp.
USING Views Each access to a table declared via USING is encapsulated by a view. In our example, this view is the database view, ZCL_AMDP_DEMO =>T005T#covw, which replaces direct access to table T005T. The task of the view is to compensate for any field sequences that differ between the ABAP Dictionary and the database object.
Stub Procedure In addition to the actual AMDP procedure, a second procedure is generated, which is named according to the name pattern #stb2#
310
8.1
AMDP Procedures
. Accordingly, in our example, the procedure name is ZCL_AMDP_ DEMO=>GET_COUNTRIES#stb2#20180301173139.
This procedure serves as a stub for the call from SAP NetWeaver. The timestamp (Section 8.1.3) is used for versioning purposes in case the object changes. The source code shown in Listing 8.4 involves only two parameters, IV_ LANGU and EV_SUBRC. The CHANGING table parameter CT_COUNTRIES is not part of the parameter definition of the procedure. The return of the table CT_COUNTRIES is not carried out via an explicitly defined table parameter but via the result set of the procedure. After the call of the AMDP procedure, a SELECT query is executed to the table CT_COUNTRIES. CREATE PROCEDURE "ZCL_AMDP_DEMO=>GET_COUNTRIES#stb2#20180301173139" ( IN "IV_LANGU" NVARCHAR (000001), OUT "EV_SUBRC" INTEGER ) LANGUAGE sqlscript SQL SECURITY INVOKER AS BEGIN "CT_COUNTRY__IN__" = SELECT * FROM "ZCL_AMDP_DEMO=>GET_COUNTRIES= >P00000#tft#20180301173139" ; CALL "ZCL_AMDP_DEMO=>GET_COUNTRIES" ( "CT_COUNTRY__IN__" => :CT_COUNTRY__IN__ , "IV_LANGU" => :IV_LANGU , "EV_SUBRC" => :EV_SUBRC , "CT_COUNTRY" => :CT_COUNTRY ); SELECT * FROM :CT_COUNTRY; END; Listing 8.4 Source Code of the Stub Procedure
Input Tables as GTT The values of table parameters are transferred into the stub procedure via generated, global temporary tables (GTTs). Before the actual AMDP
311
Return of the table
8
SQLScript in ABAP Programs
procedure is called, the table variables are initialized from the GTT. In our example, CT_COUNTRIES is filled from the GTT in the following way: "CT_COUNTRY__IN__" = SELECT * FROM "ZCL_AMDP_DEMO=>GET_COUNTRIES=> P00000#tft#20180301173139"
Here again, a timestamp is part of the name.
8.1.3 Lifecycle of the Generated Objects The lifecycle of the AMDP classes and methods is not identical to the lifecycle of the corresponding SAP HANA objects. In the following sections, we’ll describe the effects of various actions carried out on the SAP NetWeaver application server on the corresponding SAP HANA objects. 쐍 Creating and activating an AMDP class
Creating and activating an AMDP class with an AMDP method doesn’t generate any database objects. Thus, you can transport AMDP classes to SAP NetWeaver systems without an SAP HANA database. If an SAP HANA database is available as the central database system, the database objects are temporarily created and immediately deleted again for the syntax check. 쐍 Executing an AMDP method
The generated database objects, introduced in the previous section, are generated during the first execution of the AMDP method. The timestamp in the object’s name refers to the activation time of the class. Even if a class contains several AMDP methods, only the objects for the executed methods are generated. 쐍 Repeated editing and activation of an AMDP class
The stub procedures for all AMDP procedures are deleted when the class is reactivated. The same applies to all generated AMDP procedures that have changed. The generated GTT will remain for the time being. The next time the program is executed, the objects are created again with the new timestamp. Since GTTs are not deleted immediately, some objects with different timestamps can still exist at the same time.
312
8.1
AMDP Procedures
쐍 Deleting an AMDP class
The generated objects on SAP HANA are deleted upon the deletion of the AMDP class. The late generation of SAP HANA objects means that transporting AMDP classes in a mixed system landscape can run smoothly. Versioning of changes is carried out using timestamps to ensure that the correct version of a procedure is always called.
8.1.4 Two-Track Development There are different reasons why you would want both an ABAP and an AMDP implementation of a method. From a technical point of view, developing both is not a problem, since whether a method is written in SQLScript or ABAP is only determined when the method is implemented and doesn’t affect the definition of the method. In the following sections, we’ll look at a few typical use cases where more than one implementation exists.
Clean Code: Separation of Concerns The principle of the separation of concerns was formulated in 1974 by Edsger W. Dijkstra. Under this principle, different tasks should also be performed by different components in a system. In our case, separation of concerns means that database access should not be mixed with other application code. Instead, different classes should be created for each aspect. If you adhere to this principle, two-track development of AMDP and ABAP implementations is also relatively simple. Classes for database access can be easily exchanged.
Support of Different Database Systems If the application needs to run on different database systems, you can have one implementation in Open SQL and one in AMDP. Of course, you can also create special implementations for each of the other databases. Switching between the various implementations should take place automatically at runtime. For this purpose, you can use the factory design pattern. In Figure 8.2, we’ll use a static factory method, GET_INSTANCE, to generate the
313
Switching between implementations
8
SQLScript in ABAP Programs
instances. Based on the SY-DBSYS field, this method decides which class implementation should be used.
ZCL_READ_XYZ + EXECUTE( ): Table of data + GET_INSTANCE( ): ZCL_READ_XYZ
Extends
Extends
ZCL_READ_XYZ_AMDP + EXECUTE( ): Table of data
ZCL_READ_XYZ_OSQL + EXECUTE( ): Table of data
Figure 8.2 UML Diagram for Two Implementations of Database Access with a Static Factor Method
Listing 8.5 shows a simple implementation of the method GET_INSTANCE. Of course, other database systems could also be considered. METHOD get_instance. DATA lv_classname TYPE classname. CASE sy-dbsys. WHEN 'HDB'. lv_classname = 'ZCL_READ_XYZ_AMDP'. WHEN OTHERS. lv_classname = 'ZCL_READ_XYZ_OSQL'. ENDCASE. CREATE OBJECT ro_instance TYPE (lv_classname). ENDMETHOD. Listing 8.5 Static Factory Method GET_INSTANCE in ABAP
Comparison Between ABAP and AMDP If you want to test the differences between the implementations in ABAP and AMDP in runtime and result, inheritance is rather useful concept as in, for example, the previous section where we leveraged inheritance from a
314
8.1
AMDP Procedures
shared superclass. However, you’ll need a suitable switch that allows you the flexibility to select the relevant implementation. You can create these switches, for example, by using entries in a Customizing table or by defining user parameters. These switches can then be queried in a corresponding factory method.
Retroactive Implementation as AMDP Let’s say you implemented a method in ABAP and later discover performance problems; you can implement the method as an AMDP. To preserve the original implementation for performance and result comparisons, creating a subclass is a good idea. The corresponding method is then implemented as an AMDP in this subclass. Due to restrictions on AMDPs regarding access to instance attributes and parameters, this procedure must be taken into account when creating your methods. Alternatively, you can carry out a refactoring, as shown in Figure 8.3, by following this approach: 1. Outsource the logic into a new method that meets the requirements of an AMDP: no access to class and instance data, no RETURNING parameters, no parameters with structures. 2. Create a subclass. 3. Redefine the corresponding method as an AMDP.
MY_CLASS + METHOD_X( ) # AMDP_SUITABLE_METHOD_X( ) MY_CLASS Refactoring + METHOD_X( )
Extends
MY_CLASS_AMDP # AMDP_SUITABLE_METHOD_X( )
Figure 8.3 Outsourcing the Logic to an AMDP-Compatible Method and Redefinition
315
Refactoring
8
SQLScript in ABAP Programs
To switch between the two versions of the class, you can use a factory method again.
ABAP Unit Tests A mock object is often used to insert data into a class to be tested in a unit test. This object has the same external interface as a real object but provides predefined data that is independent of the database state. Classes that contain an AMDP can, for example, be replaced for unit tests by a local subclass in which the AMDP method has been replaced by a corresponding ABAP implementation. For such tests, you can use the dependency injection design pattern. Only in global classes
Note that AMDP implementation is only possible in global classes. In local classes, only an implementation in ABAP is allowed.
8.1.5 Using AMDP Procedures in AMDP Procedures An AMDP method generates a corresponding database procedure the first time it is executed (see also Section 8.1.3). This database procedure can of course also be called directly in any SQLScript code, especially in other AMDP procedures. Thus, a certain modularization of the programs is possible without direct development access to the database. Example
Listing 8.6 contains a simple example of calling an AMDP procedure in another AMDP method. Note that a CHANGING parameter in the AMDP method has two associated parameters in the corresponding database table, as described in Section 8.1.2, as follows: 쐍 CT_PRICE 쐍 CT_PRICE__IN__
In this case, you must assign these parameters yourself in order to call the procedure correctly.
Avoid CHANGING Table Parameters In the database procedure, the CHANGING table parameters are implemented in two parameters. As shown in Listing 8.6, the code needed for a direct call of this procedure can look confusing to untrained readers
316
8.1
because the CT_PRICES__IN__ parameter was not defined anywhere in the ABAP class. If you use these two parameters instead, the code will be more readable: 쐍 IT_PRICES for entering the table 쐍 ET_PRICES for the output of the table
If the generated procedures are only called using ABAP methods, whether or not you use CHANGING table parameters doesn’t matter. CLASS zcl_amdp_call DEFINITION PUBLIC. PUBLIC SECTION. TYPES: BEGIN OF ty_s_price, item TYPE numc4, net_price TYPE wertv9, gross_price TYPE wertv9, vat TYPE wertv9, waehrs TYPE waers, END OF ty_s_price. TYPES ty_t_price TYPE STANDARD TABLE OF ty_s_price. INTERFACES if_amdp_marker_hdb. METHODS calculate_vat IMPORTING VALUE(iv_vat) TYPE int1 CHANGING VALUE(ct_price) TYPE ty_t_price. METHODS calculate_gross_price IMPORTING VALUE(iv_vat) TYPE int1 CHANGING VALUE(ct_price) TYPE ty_t_price. ENDCLASS.
317
AMDP Procedures
8
SQLScript in ABAP Programs
CLASS zcl_amdp_call IMPLEMENTATION. METHOD calculate_gross_price BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT USING zcl_amdp_call=>calculate_vat. CALL "ZCL_AMDP_CALL=>CALCULATE_VAT"( iv_vat => :iv_vat, ct_price => :ct_price, ct_price__in__ => :ct_price ); ct_price = SELECT item, net_price, net_price + vat as gross_price, vat, waehrs FROM :ct_price; ENDMETHOD. METHOD calculate_vat BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT. ct_price = SELECT item, net_price, gross_price, net_price * :iv_vat / 100 as vat, waehrs FROM :ct_price; ENDMETHOD. ENDCLASS. Listing 8.6 Calling an AMDP Procedure from Another AMDP Method USING
All AMDP procedures used must be declared in an AMDP method via USING, which ensures that the necessary database objects are generated as required. Note that the class constructor of the AMDP classes used is called before the method is executed.
318
8.2
CDS Table Functions
8.2 CDS Table Functions A core data services table function (CDS table function) is an AMDP function that provides table data and can be consumed from ABAP in Open SQL, like a database view. The implementation of a CDS table function is similar to an AMDP procedure as a method of an ABAP class. A corresponding user-defined function (UDF) is then generated from this method in the SAP HANA database. Since UDF functions can’t be consumed directly in Open SQL, the AMDP functions are encapsulated by a CDS object. An AMDP function can therefore also be considered a programmed CDS view. The CDS object can then be used normally, such as a database view, in Open SQL.
Core Data Services The classic ABAP Dictionary manages database objects such as data types (data elements, structures, table types); database tables; and views. The definition of these objects are stored and managed in a database-neutral form in the associated database tables (DD*) at the ABAP application server level. Depending on the database system used, the appropriate database objects are then generated from the stored definition. The classic ABAP Dictionary, which can be called via Transaction SE11, only allows the limited use of the SQL options, especially for views. CDS are a common concept that exists both directly in the SAP HANA database and on the SAP NetWeaver ABAP application server. With CDS, database objects such as views or table functions can be defined with the help of their own language, which is based on the data definition language (DDL) of SQL. These data models can be enriched with semantic information using annotations.
8.2.1 Creating a CDS Table Function To create a CDS table function, two related objects must be created: 쐍 The CDS table function is defined in a DDL source with the parameters
and the table type of the return table. This step implicitly defines the signature of the associated AMDP method.
319
Implementation
8
SQLScript in ABAP Programs
쐍 The AMDP function is implemented in a method of a static ABAP class.
This step contains the SQLScript source code for the table function. Interaction
Figure 8.4 shows the interaction between a CDS table function and an AMDP function. IMPLEMENTED BY …
CDS Table Function
AMDP Function
FOR TABLE FUNCTION … SAP NetWeaver Application Server for ABAP Generate
SAP HANA
UDF Function
USING-Views
Figure 8.4 Objects Involved in a CDS Table Function
The CDS Table Function You can use a wizard to create CDS table functions from the ABAP development tools of the Eclipse development environment. To do this, click New • Other ABAP Repository Object in the context menu of the development package and choose Core Data Services • Data Definition in the following dialog. Figure 8.5 shows the corresponding wizard. To create a CDS table function, you must select the template Define Table Function with Parameters.
320
8.2
Figure 8.5 Wizard for Creating CDS Objects
The wizard then generates a basic structure of the corresponding source code of the CDS table function, as shown in Listing 8.7. @EndUserText.label: 'Example for a table function' define table function Z_CDS_TF with parameters parameter_name : parameter_type returns { client_element_name : abap.clnt; element_name : element_type; } implemented by method class_name=>method_name;; Listing 8.7 Basic Structure of the Definition of a CDS Table Function
In this section, we’ll describe only a rudimentary syntax for defining CDS objects, which are not the focus of the book. For more information on CDS objects, we recommend the SAP document “SAP HANA Core Data Services (CDS) Reference," at http://bit.ly/1822_802.
321
CDS Table Functions
8
SQLScript in ABAP Programs
Components
The definition of the CDS table function consists of the following components: 쐍 @EndUserText.label
This annotation contains the descriptive text for the CDS table function previously specified in the wizard. 쐍 define table function
This component indicates the start of the definition of the CDS table function. The name of the CDS entity is in the same namespace as the data types of the ABAP Dictionary. Therefore, a CDS entity must not have the same name as, for example, a database table. 쐍 with parameters
If the CDS table function will have parameters, these parameters can be defined in this component. The use of parameters is optional. The client is often specified as a parameter, which will allow you to select data by client in the function, as shown in Listing 8.9. 쐍 returns { }
The field list defines the structure of the return table. If the CDS table function is client-dependent, the first field must have the ABAP Dictionary type CLNT. For example, you can use the data element MANDT. 쐍 implemented by method =>
This component tells the CDS table function by which AMDP method the implementation is performed. The CDS entity can be activated if the associated method doesn’t exist yet.
The AMDP Function The actual implementation of the CDS table function occurs an AMDP method in a static, global ABAP class, which requires the implementation of the marker interface IF_AMDP_MARKER_HDB. Unlike AMDP procedures, AMDP functions for CDS table functions are static methods. The parameters are not defined individually in the method definition. Instead, you’ll use the addition FOR TABLE FUNCTION to establish the reference to the associated CDS table function. The parameters defined in the CDS entity are then available in the function implementation. The method implementation must be structured as shown in Listing 8.8.
322
8.2
CDS Table Functions
METHOD BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY [USING ].
ENDMETHOD. Listing 8.8 Structure of the Implementation of an AMDP Function for a CDS Table Function
The additions in the METHOD statement are all mandatory except for the USING specification. The use of USING in this context is similar to as with AMDP procedures.
Example of a CDS Table Function For a functioning CDS table function, the definition of the CDS entity and the implementation of the AMDP function belong together. Listing 8.9 and Listing 8.10 contain some simple examples to show the basics of CDS table functions using texts for countries read from table T005T. In practice, your CDS table functions will be used for much more complex scenarios that utilize multiple features of the SAP HANA database and SQLScript. @EndUserText.label: 'Country texts' define table function z_country_text with parameters @Environment.systemField: #CLIENT mandt:mandt, @Environment.systemField: #SYSTEM_LANGUAGE sy_langu:langu returns { mandt:mandt; country:land1; text:landx50; } implemented by method zjb_cl_country=>get_country_text; Listing 8.9 Example of Defining a CDS Table Function
The client and language are taken from the system fields via the annotation @Environment.systemField.
323
Definition
8
SQLScript in ABAP Programs
RETURN statement
The implementation shown in Listing 8.10 consists of only a RETURN statement, which returns the result of a SELECT query. CLASS zjb_cl_country DEFINITION PUBLIC. PUBLIC SECTION. INTERFACES if_amdp_marker_hdb. CLASS-METHODS get_country_text FOR TABLE FUNCTION z_country_text. ENDCLASS. CLASS zjb_cl_country IMPLEMENTATION. METHOD get_country_text BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING t005t. RETURN SELECT mandt, land1 AS country, landx50 AS text FROM t005t WHERE spras = :sy_langu AND mandt = :mandt; ENDMETHOD. ENDCLASS. Listing 8.10 Example of Implementing a CDS Table Function
Testing
You can test the CDS table function using a simple ABAP program, as shown in Listing 8.11. REPORT zjb_test . SELECT * FROM z_country_text INTO TABLE @DATA(lt_country) ##db_feature_mode[amdp_table_function]. cl_demo_output=>display( lt_country ). Listing 8.11 ABAP Program for Testing the CDS Table Function from the Example
324
8.2
Notice that the CDS table function can be read with a SELECT query, much like a database table or a view.
Two-Track Implementation You cannot create alternative implementations in ABAP or Open SQL for CDS table functions. However, if your program needs to run on SAP HANA as well as on other database systems, the caller of the CDS table function must take care of an alternative implementation. To query at runtime whether CDS table functions are available, you can use the CL_ABAP_ DBFEATURES class. As shown in Listing 8.12, this class can be queried for the existence of the used feature AMDP_TABLE_FUNCTION. IF cl_abap_dbfeatures=>use_features( VALUE #( ( cl_abap_dbfeatures=>amdp_table_function ) ) ). * Implementation with CDS table function ELSE. * Alternative implementation without SAP HANA features ENDIF. Listing 8.12 Checking the Availability of CDS Table Functions
The syntax check also indicates with a warning that database-dependent functions are used when querying CDS table functions. You can use the following pragma to disable the warning, as shown in Listing 8.11. ##db_feature_mode[amdp_table_function]
This pragma signals to the syntax check that the developer is aware that this query will lead to errors in other database systems.
8.2.2 Generated Objects of a CDS Table Function As with the AMDP procedures, database objects can also be generated on SAP HANA for the CDS table functions. First, a UDF function has been assigned the same name as the associated static method of the AMDP function, as shown in Listing 8.13. create function "ZJB_CL_COUNTRY=>GET_COUNTRY_TEXT" (
325
CDS Table Functions
8
SQLScript in ABAP Programs
"MANDT" NVARCHAR (000003), "SY_LANGU" NVARCHAR (000001) ) returns table ( "MANDT" NVARCHAR (000003) , "COUNTRY" NVARCHAR (000003) , "TEXT" NVARCHAR (000050) ) language sqlscript sql security invoker as begin RETURN SELECT mandt, land1 AS country, landx50 AS text FROM "ZJB_CL_COUNTRY=>T005T#covw" WHERE spras = :SY_LANGU AND mandt = :MANDT; end; Listing 8.13 Generated UDF Function for the AMDP Function
As with the AMDP procedures, a view was also generated for the table specified via USING.
8.2.3 Implicit Client Handling of CDS Table Functions By default, the implicit client handling of CDS table functions is enabled. Thus, the first field in the field list must be of dictionary type CLNT. Accordingly, the developer must also ensure that this field is filled out correctly with the source client of the data. In a SELECT query to the CDS table function, all data with other clients are then implicitly filtered out. To improve performance, you should filter out the data of other clients in the AMDP function. To create a filter, you’ll define an input parameter for the client, which is then automatically assigned the correct client via the annotation @Environment.systemField: #CLIENT. The examples shown in Listing 8.9 and Listing 8.10 illustrate what the correct client handling looks like.
326
8.3
AMDP Functions for AMDP Methods
Note the Client in the Join Condition As an ABAP developer, you may not be accustomed to taking the client into account, since this is usually undertaken by Open SQL. In SQLScript, however, the client is only an ordinary database field. Be sure you make the correct selection yourself, in particular for join conditions. If you forget the client in this situation, data records from all the different clients are multiplied out.
If implicit client handling is not desired, you can disable it using the annotation @ClientDependent: false. Nevertheless, you can still have the client as a field in the return structure of the CDS table function and select it as for any other field.
Client-independent
Use Implicit Client Handling If Possible Application and Customizing data are typically client-specific. Thus, you should always use the implicit the client handling feature of the CDS table function.
8.3 AMDP Functions for AMDP Methods If AMDP functions are only to be used in SQLScript source code by other AMDP methods, defining an associated CDS table function is not necessary. The definition and implementation of an AMDP function for AMDP methods differs in the following aspects: 쐍 The AMDP method can be a static method or an instance method. There-
fore, the associated AMDP classed don’t have to be static. 쐍 The method can also be declared in the private or protected visibility
area. 쐍 The parameters of the method are defined when the method is defined. 쐍 The addition, FOR TABLE FUNCTION in the method definition is omitted.
Listing 8.14 contains an example using an AMDP function in a different AMDP method. The direct call of the method GET_COUNTRY_TEXT in an ABAP method of the class ZCL_AMDP_FUNC would not be possible.
327
AMDP function in different AMDP method
8
SQLScript in ABAP Programs
CLASS zcl_amdp_func DEFINITION PUBLIC. PUBLIC SECTION. TYPES: BEGIN OF ty_s_country, mandt TYPE mandt, country TYPE land1, text TYPE landx50, END OF ty_s_country. TYPES ty_t_country TYPE STANDARD TABLE OF ty_s_country WITH DEFAULT KEY. INTERFACES if_amdp_marker_hdb. METHODS test_amdp_table_function IMPORTING VALUE(iv_langu) TYPE langu VALUE(iv_mandt) TYPE mandt EXPORTING VALUE(et_country) TYPE ty_t_country. PRIVATE SECTION. METHODS get_country_text IMPORTING VALUE(iv_langu) TYPE langu VALUE(iv_mandt) TYPE mandt RETURNING VALUE(rt_country) TYPE ty_t_country. ENDCLASS. CLASS zcl_amdp_func IMPLEMENTATION. METHOD test_amdp_table_function BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING zcl_amdp_func=>get_country_text. et_country = select * from "ZCL_AMDP_FUNC=>GET_COUNTRY_TEXT" ( iv_langu => :iv_langu, iv_mandt => :iv_mandt); ENDMETHOD. METHOD get_country_text BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING t005t.
328
8.4 Alternatives to AMDPs for Calling SQLScript Code from ABAP Programs
RETURN SELECT mandt, land1 AS country, landx50 AS text FROM t005t WHERE spras = :iv_langu AND mandt = :iv_mandt; ENDMETHOD. ENDCLASS. Listing 8.14 Example of Using an AMDP Function in a Different AMDP Method
8.4 Alternatives to AMDPs for Calling SQLScript Code from ABAP Programs With the AMDP framework, calling SQLScript can be elegantly integrated into the ABAP language and the Open SQL used. A person reading an ABAP program may not initially recognize that AMDP objects are actually hidden behind a method call or a presumed table. However, with alternative techniques, you can use to execute SQLScript statements from ABAP programs. These techniques may be necessary if secondary database connections will be used and can be helpful when executing dynamic SQL code. However, there are also other alternative techniques with which you can call SQLScript code from ABAP without using AMDPs: 쐍 ABAP Database Connectivity (ADBC)
ADBC is a class-based framework for running Native SQL. Individual SQL statements, database connections, and result sets are represented as ABAP objects. ADBC can be regarded as a successor to the static embedding of Native SQL using the EXEC SQL statement in ABAP code. In more than name only, the ADBC framework is reminiscent of the similarly structured JDBC from the Java world. 쐍 EXEC SQL ENDEXEC
This statement enables you to embed Native SQL statically into the ABAP source code. However, SAP no longer recommends this procedure. Instead, ADBC is referenced for the use of Native SQL.
329
Alternative techniques
8
SQLScript in ABAP Programs
쐍 CALL DATABASE PROCEDURE
This ABAP statement allows you to call any database procedure on SAP HANA via an associated proxy object. However, SAP recommends using AMDPs instead, as long as the procedure will be called via the primary database connection.
8.5 Recommendations In this chapter, you learned some ways to directly access the objects of an SAP HANA database in your programs. Even if trying out these new techniques is tempting, let’s pause a moment to review some final considerations: 쐍 If possible, you should continue to use Open SQL, as long as no signifi-
cant performance improvements are foreseeable. The ABAP language has been extended in recent releases to include powerful functions, such as the use of expressions and the option of combining multiple queries via UNION. More complex queries can also be mapped using CDS views. 쐍 However, if, for performance reasons or other considerations, executing
SQLScript code directly from ABAP programs still seems necessary, the techniques of the AMDP framework on the SAP HANA database are the weapon of choice for executing static SQLScript code. 쐍 If you need dynamic SQLScript code, ADBC is the right technique. How-
ever, dynamic SQL code is always problematic. On one hand, error analysis is often more difficult, and on the other hand, you must guard against security gaps and vulnerability to SQL injection attacks. 쐍 If you are working with secondary database connections, you should
consider using a CALL DATABASE PROCEDURE statement. Further, the autonomous transactions we discussed in Chapter 6, Section 6.6.2, can also solve some classic use cases for secondary database connections more elegantly. Regardless of the technology used, the clean encapsulation of the database access is always recommended in both AMDP and Open SQL. Only if you
330
8.5
bundle and encapsulate the database access in separate classes will you have the necessary flexibility to carry out optimizations later without fear of negative side effects. In this chapter, we've overviewed the AMDP framework. In the next chapter you will learn how this framework is used by SAP BW to implement transformation routines in SQLScript.
331
Recommendations
Chapter 9 SQLScript in SAP Business Warehouse In SAP Business Warehouse (SAP BW), data transfer processes (DTPs) can now be completely executed on the database. ABAP Managed Database Procedures (AMDPs) are integrated so they can still execute their own code in the transformation rules. In this chapter, we’ll describe this technique through some practical examples.
SAP BW has been consistently adapted and optimized for use on the SAP HANA database in several steps over the last few years: 쐍 Since SAP BW 7.0, a side-by-side scenario, in which the SAP HANA data-
base operated as a secondary database alongside the primary database, has been possible. 쐍 Since release SAP BW 7.3 powered by SAP HANA, SAP HANA could be
used as primary database for SAP NetWeaver. These customers were thus able to benefit from a fast database without any special adjustments to data modeling features. 쐍 With the release of SAP BW 7.40, the system has been optimized for SAP
HANA databases. New modeling objects, such as advanced DataStore objects and CompositeProviders, now also enable a field-based data modeling process. In addition, the execution of the data transfer processes (DTPs) has been optimized so that these processes can now run entirely on the database. To make this capability possible, expert routines (discussed in more detail in Section 9.4.3) can also be implemented in SQLScript. 쐍 SAP BW 7.50 introduced further optimizations and enhancements, such
as semantic groups for advanced DataStore objects. As of SAP HANA SP04, start, end, and field routines are also possible in SQLScript. The SAP BW/4HANA starter add-on provides a set of tools to prepare for migrating to SAP BW/4HANA.
333
9
SQLScript in SAP Business Warehouse
쐍 SAP BW/4HANA currently represents the end of this development. In
contrast to its predecessors, SAP BW/4HANA only runs on, and has been completely optimized for, SAP HANA databases. SAP regards SAP BW/4HANA as a new product, not a successor to previous SAP BW releases in terms of licensing. But, this book’s focus is technology. From this perspective, SAP BW/4HANA is an evolution that has removed many outdated and obsolete objects. From the point of view of an ABAP developer, the adaptations of SAP BW to SAP HANA primarily change the fact that the routines in the transformations between InfoProviders can now also be implemented as AMDPs. But first we would like to briefly illustrate why this capability is important. SAP BW transformations
An SAP BW transformation describes a fieldwise mapping from a source into a target, as shown in Figure 9.1.
Figure 9.1 Modeling an SAP BW Transformation in the SAP GUI
For each target field, you can define a rule that specifies how the field value is determined. Typical rules include the following: 쐍 1:1 mapping from a source field 쐍 Constant values
334
SQLScript in SAP Business Warehouse
쐍 Formulas with source fields 쐍 Quantity conversions 쐍 Reading master or transaction data 쐍 Routines (ABAP or AMDP)
As of SAP BW 7.40 SP05, SAP BW transformations can also be executed directly on a SAP HANA database as long as no ABAP routines are used. A data transfer process (DTP) describes how the data is written from a source to a target. Among other things, a DTP defines the following properties:
Data transfer process
쐍 Path
Which path should the data take between source and target? This path also determines which transformations are involved. 쐍 Filtering
Which data should be transferred from the source to the target? 쐍 Package size
How much data should be transferred at the same time? 쐍 Extraction mode
Will updating involve a delta process or consist of a full update? 쐍 Error handling
How should a request behave in case of incorrect data? When you start a data transfer process, a request is generated. First, the data is selected from the source according to the filtering, split into packages, and then processed in parallel in several background processes. The classic execution of a data transfer process takes place on the ABAP server. To execute a DTP, perform the following steps, as shown in Figure 9.2: 1. Extract data into small packages (50,000 records by default). 2. Copy the data to the application server. 3. Process lines and fields on the ABAP application server via a generated ABAP program. If necessary, start, end, or field routines programmed in ABAP are also included. 4. Copy the result to the database. 5. Insert the data into the input table of the target object.
335
ABAP execution of a DTP
9
SQLScript in SAP Business Warehouse
Data Transfer Process Transformation as a generated ABAP report
SAP BW SAP HANA
Extraction in small packages
Source
Target
Figure 9.2 Data Transfer Process with ABAP Execution SAP HANA execution of a DTP
If a transformation meets certain conditions, it can be executed directly on the SAP HANA database as of SAP BW 7.40 SPS 05. The most important prerequisite in this scenario is that no ABAP routines exist. You can check whether executing in SAP HANA is possible via the Runtime Status field in the transformation, as shown in Figure 9.3. Next to this field is a button, which you can click to check the current status of the transformation.
Figure 9.3 Display of Runtime Status
The data transfer process when executed by SAP HANA differs considerably from how the ABAP application server would execute the process. As shown in Figure 9.4, with SAP HANA, a calculation scenario is generated from the transformations. Data is then read from this calculation scenario on the SAP HANA database and written directly to the input table of the data target via INSERT. The ABAP application server is no longer involved in processing the data. If possible, data packages are created (see SAP Note 2230080). The default package size is 1 million records.
336
SQLScript in SAP Business Warehouse
Data Transfer Process (DTP)
SAP BW SAP HANA
Trigger
Source
INSERT from on SAP HANA calculation scenario
Target
Figure 9.4 Data Transfer Process with SAP HANA Execution
Several features result in higher performance in the SAP HANA execution scenario, when compared to execution by the ABAP application server: 쐍 The data doesn’t have to be copied to the application server during an
SAP HANA transformation. This data is instead written directly from the source into the target via an INSERT statement. 쐍 Data extraction for ABAP transformations is performed with a default
value of 50,000 data records per package. For SAP HANA transformations, a package size of 1,000,000 data records is selected by default. In fact, packaging only takes place if suitable technical features for packaging are found in the source data. Larger data packages reduce the overhead for status management and monitoring. 쐍 By processing directly on the SAP HANA database, data processing can
be easily parallelized. 쐍 Existing routines are implemented in SQLScript for SAP HANA transfor-
mations. These routines can then be easily optimized. So far, transformations have been modeled in Transaction RSA1, regardless of where they are executed later. If no routines are implemented, often you can execute them both in SAP HANA and in the ABAP runtime. You can then define this when you create the data transfer process. All routines of an SAP BW transformation must be implemented in the same programming language, either in ABAP or as AMDP in SQLScript. When you create the first routine of a transformation, you have to make a decision. Accordingly, a transformation with routines can only be executed in the respective runtime environment.
337
Performance
9
SQLScript in SAP Business Warehouse
Tools
The implementation of AMDP routines requires the use of the ABAP development tools in Eclipse. The SAP BW transformation should be modeled using the SAP BW modeling tools in Eclipse, since the change to routine implementation works better here. The debugging of the AMDP routines is described in Chapter 11, Section 11.2.3.
9.1 Transformation Routines as AMDP When you create the first routine for a transformation, you’ll be prompted, in the popup menu shown in Figure 9.5, whether you want to implement the routine in ABAP or as an AMDP. This decision is valid for all further routines in this transformation.
Figure 9.5 Query for the Type of Transformation Routines
If you choose AMDP, the next steps depend on the user interface you’re using. If you are in the SAP GUI, open the class editor (Transaction SE24). This editor displays a generated ABAP class with a cryptic name in the generation namespace /BIC/, which can’t be edited in the SAP GUI. The message indicates that you can only edit the class in the ABAP development tools. You must copy the class name and then open and edit the class in the ABAP development tools of the Eclipse development environment. After activating the class, you should go directly back to the SAP GUI, where the class is still displayed, then back to the transformation to save and activate it immediately. If you edit a transformation using the SAP BW modeling tools of the Eclipse environment, you don’t need to switch between the two development environments. The generated class is opened directly and can be edited in the ABAP development tools. After activation, you should save and activate the transformation as soon as possible.
338
9.2
Successive Transformations and Mixed Execution
Orphaned AMDP Classes in BW on HANA If you create an AMDP routine from a transformation in Transaction RSA1, an ABAP class for it is generated and stored. However, at that time, the transformation is not yet saved. You must click Save in the transformation. Repeatedly, although developers might implement the AMDP method PROCEDURE in the generated class, often they forget to save the associated transformation. The logical assignment between transformation and AMDP class thus disappears. If you forget to save the transformation, you must create the routine again, which generates a new class with a different class name. You can then copy the code from the original class, which has not been deleted, to the new class by following these steps: 1. Save the transformation as soon as possible after creating the AMDP class. 2. You can determine the names of orphaned AMDP classes using the creation date and the username of the creator in the TADIR table. Then, you can copy the source code. 3. After activating the transformation, check whether the assignment to the AMDP class has been saved by restarting Transaction RSA1. Then, navigate from the transformation to the associated AMDP class.
9.2 Successive Transformations and Mixed Execution Several transformations can lie between a source and a target if an InfoSource has been modeled between them, as shown in Figure 9.6. In a data transfer process, these transformations are executed one after the other. However, the execution capability of the two transformations may differ. Table 9.1 shows which execution options are possible for the data transfer process.
339
9
SQLScript in SAP Business Warehouse
Target
Upper transformation
InfoSource
Lower transformation
Source
Figure 9.6 Successive Transformations
Execution
Lower Transformation
Upper Transformation
ABAP execution possible
ABAP-enabled
ABAP-enabled
SAP HANA execution possible
SAP HANA-enabled
SAP HANA-enabled
Mixed execution possible
SAP HANA-enabled
Only ABAP-enabled
Table 9.1 Execution Options for Successive Transformations
Mixed execution is not possible if the lower transformation is only ABAPenabled. The reason for this limitation is that an ABAP transformation can also have a calculation scenario as its source. Conversely, a calculation scenario cannot access an ABAP transformation. InfoSource
Technically, you can have more than one InfoSource between source and target, but SAP recommends a maximum of two InfoSources per data flow. As a result, more transformations for which mixed execution is possible under the following condition: An ABAP-only transformation must not exist under an SAP HANA-only transformation. In the case of a mixed execution, error processing is not possible.
340
9.3
The Generated AMDP Classes
9.3 The Generated AMDP Classes There are differences between SAP BW on SAP HANA and SAP BW/4HANA with regards to the classes generated by the transformation (which contain the source code of the routines). In an SAP BW on SAP HANA system, a separate local AMDP class is generated for each routine. This always contains exactly one method with the name PROCEDURE. The name of the class is generated randomly. If the transformation is not saved after the routines have been created, the reference to the AMDP class is also not saved. If necessary, another AMDP class with a new, random name is created.
AMDP classes for SAP BW on SAP HANA
On SAP BW/4HANA systems, two local AMDP classes are generated for each transformation. The name of the classes consists of the prefix for the generation namespace /BIC/, the last 20 letters of the transformation key, and the suffixes _M and _A. For example,
AMDP class for SAP BW/4HANA
/BIC/ZY9NHHQCBA14H4IU4OW0_M /BIC/ZY9NHHQCBA14H4IU4OW0_A
The class with _A contains the active source code of the routines of a transformation. Breakpoints for debugging the routines must be set in this class. Changes to this class are technically possible, but have no effect on the transformation. The class that ends with _M is available for editing. After the class has been activated, the transformation must also be activated for the code to take effect. Setting breakpoints in this class has no effect. The two classes contains one method for each routine. The name of the methods depends on the type of routine, for example, GLOBAL_START or GLOBAL_EXPERT. The AMDP class itself is not transported to the subsequent systems. Instead, the source code is stored in the relevant metadata of the transformations. When the transformation is activated, the class is regenerated from the stored source code. Since the AMDP class is created as a local object, it can’t be transported.
341
Transport
9
SQLScript in SAP Business Warehouse
The classes are used to enter the source code and generate the corresponding database procedure, which is then included in the corresponding calculation scenario of the transformation. Figure 9.7 shows the integration of the procedure into the calculation scenario in an XML representation.
Figure 9.7 Calculation Scenario of a Transformation with an AMDP End Routine
9.3.1 Signature of AMDP Methods The interface of the AMDP methods is generated in such a way that is suitable for every individual transformation. All four routine types have the same four parameters: 쐍 Input table INTAB
The data is transferred to the routine using the IN parameter INTAB. 쐍 Output table OUTTAB
The result of the routine is written to the table parameter OUTTAB. To activate the AMDP class, this parameter must be filled via a corresponding SELECT query.
342
9.3
The Generated AMDP Classes
쐍 Output table ERRORTAB
Erroneous data records are written to this table. This information consists of two fields: – ERROR_TEXT (description of the error) – SQL__PROCEDURE__SOURCE__RECORD (field from the associated data record of INTAB) 쐍 Scalar parameter I_ERROR_HANDLING
This parameter has the value TRUE if the current procedure call queries the error table ERRORTAB. The data types for INTAB and OUTTAB depend on the relevant routine. Within the AMDP class, these data types are defined as types TN_T_IN and TN_T_OUT. Two standard fields exist in the table parameters: RECORD and SQL__PROCEDURE__SOURCE__RECORD.
RECORD The RECORD field is a character string that consists of 56 characters. After the transformation, the data records are sorted according to this field. This sorting can be relevant for the sequence of insertion into the target of the transformation. Initially, the RECORD field contains the concatenated fields REQUESTID, DATAPAKID, and RECORD from the source of the transformation. In successive transformations, this field will contain the value of the RECORD field from the preceding transformation. If the sort order is relevant in a scenario, you as the developer of the AMDP routine must ensure that the RECORD field is filled with a corresponding content. If, for example, you want to sort the data according to a date field and a time field, you can concatenate and write both fields together into the RECORD column. Alternatively, you can use the window function RANK() to generate a sequential number. Note that the field has the data type string and that an alphanumeric sorting takes place accordingly. To prevent, for example, 10 from preceding 2, you must use LPAD (, 56, '0') to add leading zeros, as shown in Listing 9.1.
343
9
SQLScript in SAP Business Warehouse
outtab = SELECT ... LPAD( RANK() OVER (ORDER BY ), 56, '0') AS "RECORD", SQL__PROCEDURE__SOURCE__RECORD FROM :intab ; Listing 9.1 Assigning a Sequential Number to the RECORD Field for Sorting
SQL__PROCEDURE__SOURCE__RECORD The field SQL__PROCEDURE__SOURCE__RECORD contains a unique key for data records in the INTAB table. The key ensures that entries in the error table ERRORTAB can be assigned to the relevant data records from the INTAB table. If new data records are generated in a routine, the value of the relevant source data record is to be transferred. Initially, the content of the field in the INTAB table corresponds to the content of the RECORD field.
9.3.2 Assigning the Output Tables The two output tables OUTTAB and ERRORTAB must be assigned within the SQLScript source code, as otherwise syntax errors will arise. This assignment is also necessary if you don’t want to perform error processing. Thus, a minimal implementation should look like Listing 9.2. This code corresponds to the initial code of the generated method of an end routine, even if we’ve formatted this code to be more appealing in the example. METHOD procedure BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY. OUTTAB = SELECT * FROM :INTAB; ERRORTAB = SELECT '' AS ERROR_TEXT, '' AS SQL__PROCEDURE__SOURCE__RECORD FROM DUMMY WHERE DUMMY 'X'; ENDMETHOD. Listing 9.2 Minimal Implementation of an End Routine
344
9.3
The Generated AMDP Classes
You can see that the ERRORTAB table remains empty in this implementation. An even more compact version to achieve the same result is the following: ERRORTAB = SELECT * FROM :ERRORTAB;
The OUTTAB table is filled with the exact same content from the INTAB table. Thus, this routine doesn’t change our data. You can now modify this initial code to suit your requirements. Note that the AMDP routines may only read data, since the method is marked as READ-ONLY.
9.3.3 Access to Data from Other Data Models If you are using other database tables, views, AMDP procedures, or functions, you must first add them using the USING clause in the METHOD statement. The example shown in Listing 9.3 represents a typical scenario: By means of a LEFT OUTER JOIN, the data of a generated SAP BW table is read into an INTAB table. However, the generated SAP BW tables are located in the generation namespace /BIC/. Because of the slash in the name, the SQLScript code, with its special case-sensitive notation, must be accessed in quotation marks. The ABAP statement METHOD is not case-sensitive, and in this case, you must not use any quotation marks. METHOD procedure BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING /bic/AZJB_TEST2. OUTTAB = SELECT ... FROM :INTAB AS T1 LEFT OUTER JOIN "/BIC/AZJB_TEST2" AS T2 ON ... ; ERRORTAB = SELECT * FROM :ERRORTAB; ENDMETHOD. Listing 9.3 USING Clause in AMDP Routines
345
Reading SAP BW data
9
SQLScript in SAP Business Warehouse
Tables of Advanced DataStore Objects If you want to read data from other advanced DataStore objects, you must access their tables or views, which are created automatically by SAP BW. The corresponding table and view names are created according to the following schema: /BIC/A
Three tables are always created, regardless of the advanced DataStore object type. However, not all three tables are actually used. In the following overview, the suffix for the table name is given in parentheses: 쐍 Input tables (1) New data is entered into this table where it will stay until the data is activated. A technical key consisting of request ID, data package, and sequential number of the data record serves as the key. The domain key of the advanced DataStore object is not relevant. 쐍 Active table (2) After activation, the data is stored in this table with its domain key. 쐍 Modification table (3)
This table contains all changes to the data of the active table. New data records are entered with the record mode N. When changes are made to the active data, two data records are created: The old state is stored with record mode X and the new state with an empty record mode. You should only read directly from the tables if you are sure that the advanced DataStore object type will not change. Since the tables are always generated, such a change would result in a syntax error. The generated views should be used instead. These views provide a stable interface to the advanced DataStore object data, regardless of whether the advanced DataStore object type changes or not. They are automatically adapted by SAP BW. 쐍 Extraction view (6) This view is used when data is to be extracted from the advanced DataStore object. 쐍 Reporting view (7)
This view always contains the advanced DataStore object data relevant for reporting. Accordingly, lookups should always be performed in this view.
346
9.3
The Generated AMDP Classes
For example, the input table for the advanced DataStore object ZJB_TEST, shown for example in Figure 9.8, has the technical name /BIC/AZJB_TEST2.
NOT NULL All field values written to the OUTTAB table must always contain a defined value. As shown in Figure 9.8, the associated table for an advanced DataStore object contains a NOT NULL check.
Figure 9.8 Definition of an Advanced DataStore Object Table (Active Data Table)
If, however, NULL values do occur, an error message will appear, as shown in Figure 9.9.
Figure 9.9 Error Message for NULL Values for Characteristics
347
9
SQLScript in SAP Business Warehouse
Since whether the corresponding columns are filled during an OUTER JOIN depends on the data, you should always use the COALESCE function (see Chapter 2, Section 2.2.13 for more details). Listing 9.4 shows an example. outtab = SELECT ... COALESCE( pplant.plantcat, ' ' ) AS plantcat, it.record , it.sql__procedure__source__record FROM :intab as it LEFT OUTER JOIN "/BI0/PPLANT" AS pplant ON it.plant = pplant.plant Listing 9.4 Protection against NULL Values with COALESCE Error handling
Alternatively, you can also use an appropriate error handling (Section 9.5) to check for NULL values and then transfer these data records to the ERRORTAB table.
9.4 The Individual Routines In addition to the transformation rules, a transformation can also consist of start, end, and field routines. The sequence of these routines is shown in Figure 9.10, but the routines are optional.
Transformation rule field 1, e.g., field routine or formula Start routine (optional)
Transformation rule field 2, e.g., field routine or formula
End routine (optional)
Transformation rule field N, e.g., field routine or formula
Figure 9.10 Routines in the Transformation Process
9.4.1 Start Routines A start routine is run at the start of a transformation, that is, before the individual fields are assigned and processed with the field rules. Accordingly,
348
9.4
The Individual Routines
the two table parameters INTAB and OUTTAB comprise the fields of the data source. The task of the start routine is typically to filter or add additional data records. Filters can already be specified in the definition of a data transfer process. Sometimes, however, you may need to restrict or change the amount of data at a later stage. This ability is useful, for example, if the filter criteria doesn’t refer directly to the source but can only be determined using a join with the data.
Tasks of the start routines
Conversely, sometimes, data records can still be supplemented in a transformation. This enrichment process is also best done in the start routine, so that the completed data is processed exactly like the original data in later steps of the transformation.
9.4.2 End Routines An end routine is performed as the last step of a transformation. For this reason, the field list of INTAB and OUTTAB contains the field names of the data target. The result of the end routine is transferred directly to the data target. Accordingly, this data may override the results of any other processing steps already carried out at that stage. Frequent applications for end routines are:
Use cases for end routines
쐍 Filtering data using the result of previous processing steps. 쐍 Calculation or derivation of multiple fields with (partially) common
logic. In this case, the use of an appropriate number of field routines results in a duplication of source code, which contradicts the Don’t Repeat Yourself (DRY) principle in software development. Poor maintainability and low transparency could result. 쐍 Dependencies among the fields to be determined. No defined execution
sequence exists for the field routines. Thus, a field routine can’t reliably refer to the result of another field routine, and therefore, an end routine will need to be used in this case. If fields are derived in the end routine of a transformation, for clarity, we recommend they not be assigned 1:1 in the field rules of the transformation.
349
9
SQLScript in SAP Business Warehouse
Instead, as shown in Figure 9.11 for the fields 0BASE_UOM and 0CO_AREA, you can assign a constant with an initial value and specify the corresponding rule name, in our case, “End Routine.”
Figure 9.11 Selecting the Fields Derived in the End Routine by a Corresponding Rule Name
9.4.3 Expert Routines An expert routine replaces the entire transformation logic. If an expert routine is created, field rules (1:1 mapping, formulas, lookups, and so on) are no longer possible. The INTAB table contains only the fields from the source, while the OUTTAB table contains the fields of the transformation target. All assignments, renaming, formatting, etc., must be carried out in the routine. Dummy implementation
Unlike the other routines, no initial coding is generated by SAP BW for the expert routine. The generated class therefore contains syntax errors and can’t be activated from the SAP GUI. You must first switch to Eclipse’s ABAP development tools to create and activate a syntax error-free version of the class. You can use the coding from Listing 9.5 to activate the transformation quickly, and the connection between AMDP class and transformation will be stored permanently. Of course, filling the OUTTAB table from itself doesn’t make much sense in practice. METHOD PROCEDURE BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY. outtab = SELECT * FROM :outtab;
350
9.4
The Individual Routines
errortab = SELECT * FROM :errortab; ENDMETHOD. Listing 9.5 Dummy Implementation of an Expert Routine
9.4.4 Field Routines The field routines determine the values for exactly one target field. One or more source fields, which are assigned in the definition of the rule details, are used for inputs, as shown in Figure 9.12. In contrast to the field names in ABAP, which are called for each individual data record, an AMDP field routine is run only once. All source fields in the INTAB table are available for this purpose. The OUTTAB table contains only the target field and the two technical fields RECORD and SQL__PROCEDURE__SOURCE_ _RECORD. In the generated calculation scenario of the transformation, the result of the field routine is combined with the rest of the data via a VERTICAL_UNION operation. For this reason, absolutely no data records must be removed or added, and the order of the records or the content of the fields RECORD and SQL__PROCEDURE__SOURCE__RECORD must not be modified.
Figure 9.12 Definition of a Field Routine with Multiple Source Fields
Field routines should only ever contain OUTER joins to avoid losing any data records. In addition, you must ensure that no data records are added.
351
Simultaneous processing of all values
9
SQLScript in SAP Business Warehouse
9.5 Error Processing and Error Stack Error processing can occur in all four routine types. As a result, the routine writes the values of the field SQL__PROCEDURE__SOURCE__RECORD of incorrect data records from the INTAB into the ERRORTAB table. In this table, you can also specify a suitable error text in the ERROR_TEXT column, as shown in Listing 9.6. errortab = SELECT 'Currency is empty!' AS ERROR_TEXT, SQL__PROCEDURE__SOURCE__RECORD FROM :intab WHERE currency = ' ' AND amount 0; Listing 9.6 Simple Error Determination from the Input Data of INTAB
In the error handling of the DTP, you can specify within the data transfer process how errors in the data of a request should be handled. Figure 9.13 shows the available options for error handling.
Figure 9.13 Setting Error Handling in the Data Transfer Process
Please Read Current SAP Notes If the data transfer process terminates or errors occur during modeling when using error handling and the error stack, you should search for suitable SAP Notes for your system status and send a message to SAP if necessary. Although a number corrections have been developed in this area, not all problems have been solved.
352
9.5
Error Processing and Error Stack
9.5.1 Processing Flow in the Data Transfer Process Each transformation, and thus also each routine, is run through twice when a data transfer process is executed. The first run searches for incorrect data records, and the second run determines the actual processing. Figure 9.14 shows the flow of a data transfer process with an error stack. Document
Item
1023 1023 1024 1024 1024 1025 1025 1026 1026 1026
10 20 10 20 30 10 20 10 20 30
Amount
Currency 123.23 2312.59 435.86 465.99 3128.23 12389 345.67 32.27 435.89 234.34
EUR EUR USD USD GBP GBP EUR EUR EUR
1st run of the routine: Write incorrect data from the INTAB to the ERRORTAB. Document
Item
1023 1023 1024 1024 1024 1025 1025 1026 1026 1026
10 20 10 20 30 10 20 10 20 30
Amount
Currency 123.23 2312.59 435.86 465.99 3128.23 12389 345.67 32.27 435.89 234.34
EUR EUR USD USD GBP GBP EUR EUR EUR
DTP: Determine all data of semantic groups with incorrect data. Document
Item
1023 1023 1024 1024 1024 1025 1025 1026 1026 1026
10 20 10 20 30 10 20 10 20 30
DTP: Filter the correct data for further processing
Amount
Item
1023 1023 1025 1025 1026 1026 1026
10 20 10 20 10 20 30
EUR EUR USD USD GBP GBP EUR EUR EUR
DTP: Write data from semantic groups with errors to the error stack.
Correct Data Document
Currency 123.23 2312.59 435.86 465.99 3128.23 12389 345.67 32.27 435.89 234.34
Error Stack Amount 123.23 2312.59 12389 345.67 32.27 435.89 234.34
Currency
Document
Item
EUR EUR GBP GBP EUR EUR EUR
1024 1024 1024
10 20 30
Amount
Currency
435.86 USD 465.99 USD 3128.23
2nd run of the routine: processing of the correct data in the INTAB into the result of the OUTTAB Document
Item
1023 1023 1025 1025 1026 1026 1026
10 20 10 20 10 20 30
Amount 123.23 2312.59 12389 345.67 32.27 435.89 234.34
Currency
Text
EUR EUR GBP GBP EUR EUR EUR
Euro Euro British pound British pound Euro Euro Euro
Figure 9.14 Processing Flow in the Data Transfer Process
353
9
SQLScript in SAP Business Warehouse
The Document field represents a semantic group in this case. In other words, if an item in a document is incorrect, the entire document is incorrect and should be filtered out. Data records without a valid currency are considered as containing errors, and the routine writes these records into the ERRORTAB table during the first run. The data transfer process then sorts out all data records that are in a semantic group together with incorrect data records. Second run
The correct data records are processed during the second run of the routine from the INTAB table into the OUTTAB table. The fact that the routine is run twice doesn’t necessarily mean that the runtime doubles. During the first run, the data transfer process queries only the output table, ERRORTAB; during the second run, only the output table OUTTAB is queried. If these output tables can be determined independently, the SAP HANA database will optimize the execution so that only the statements that are actually required are executed.
9.5.2 Example: Recognizing Incorrect Data in Table OUTTAB Sometimes, erroneous data can only be determined after the calculation of the OUTTAB table. For this reason, the ERRORTAB table is often determined via a SELECT query to the OUTTAB table, as shown in Listing 9.7. outtab = SELECT it.plant, pplant.plantcat FROM :intab AS it LEFT OUTER JOIN "/BI0/PPLANT" AS pplant ON it.plant = pplant.plant; ERRORTAB = SELECT 'Error!' AS error_text, SQL__PROCEDURE__SOURCE__RECORD FROM :outtab WHERE plant = ' ' --Errors from INTAB OR plantcat IS NULL --Join unsuccessful Listing 9.7 Error Determination from OUTTAB
In this simple example, our SELECT statement to table /BI0/PPLANT must be run twice, but this duplicated effort doesn’t matter much. However, for
354
9.5
Error Processing and Error Stack
transformations with long runtimes, you should consider whether you can determine the incorrect data without executing the actual logic.
9.5.3 Example: Finding Invalid Field Contents with Regular Expressions Non-permitted characters represent a typical pitfall in data processing with SAP BW. Which characters are allowed is set in Customizing for the SAP BW system. Normally, mainly control characters (such as a backspace or a carriage return) cause problems. As soon as data containing illegal characters is used in SAP BW as a key for InfoObjects, activation errors occur. Since advanced DataStore objects can also be modeled field-based, that is, without assigning InfoObjects, nonpermitted characters are not initially noticed. In addition to the non-permitted characters, errors will arise if characteristics values in SAP BW start with an exclamation mark or consist only of the hash character (#). In Listing 9.8, we’ve created an AMDP routine that looks for control characters in the TEXT column using regular expressions and writes the corresponding data records into the ERRORTAB table. This routine returns the INTAB table without any changes to the OUTTAB table. outtab = SELECT * FROM :intab; errortab = SELECT 'Check field content!' AS ERROR_TEXT, SQL__PROCEDURE__SOURCE__RECORD FROM :intab WHERE text LIKE_REGEXPR '.*[[cntrl]].*' OR text LIKE '!%' OR text = '#'; Listing 9.8 Check for Control Characters
This routine can easily be extended by adding more fields to be checked. Normally, however, not all fields need to be checked because these errors only occur in fields that are entered manually in the source system (especially by copy and paste) and where no check table is stored, for example, for posting texts. An alternative to the implementation shown in Listing 9.8 would be to replace the control characters with a space.
355
Error situations
9
SQLScript in SAP Business Warehouse
In this chapter, we saw how to use SQLScript to implement transformation routines in SAP BW. This enables you to speed up the processing of data in SAP BW enormously. In the next chapter, we'll explore how to write procedures that are easy to read and maintain.
356
Chapter 10 Clean SQLScript Code Any fool can write code that a computer can understand. Good programmers write code that humans can understand. – Martin Fowler
The source code of a program should meet different, sometimes contradictory, requirements. The primary requirements for code generally include the following: 쐍 Functional correctness
A program should do exactly what is specified. This goal seems obvious but is rarely achieved in its entirety. The reason for this shortcoming can be found as frequently in the specification as in the implementation of the program. 쐍 Good maintainability and scalability
Existing programs are often corrected and extended retroactively. This maintenance work should be without unexpected risks and side effects. 쐍 Good performance
Performance is often a decisive factor in database-related programming. 쐍 Production efficiency
The development time for a program usually plays an important role. Projects must be kept within the limits of the planned budget and deliver a certain functional scope for the respective milestones. To approach these primary requirements, extensive knowledge and experience in the relevant programming language and technology are required. In this chapter, we’ll provide some special hints about SQLScript as well as some general advice about what makes a good program.
357
10
Clean SQLScript Code
10.1 The Readability of the Code Source code is written once and read multiple times. Therefore, the most important prerequisite for achieving the requirements mentioned earlier is good readability of the source code. As developers, we’ve all been in the situation, during a troubleshooting process, of spending hours reading, understanding, and debugging a single method or procedure our predecessor created. Even after we’ve found and fixed an error, we know that the next error will mean considerable effort again. If we want to save ourselves and our colleagues from these nasty and lengthy debugging sessions, we should write code that makes debugging easy. Errors can’t hide themselves as easily in clean source code. The effect of changes to the code is more predictable. Beside some special tips for SQLScript, some general recommendations are valid for other programming languages. At this point, we would like to explicitly recommend the book Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin, which is also worth reading for experienced developers.
10.1.1 Formatting the Code Especially in SQL, good formatting is important because the source code of individual statements can run over many lines and procedures can often comprise many pages. With whitespace, you can indent lines at will, and line breaks are possible everywhere. In this section, we’ll make a few suggestions for consistent formatting. Ultimately, however, you must develop a consistent style within your company or development team, which will increase readability considerably.
Line Breaks In field lists, each field gets (at least) one line. While these line breaks make the source code longer, the order of the fields can be more easily changed as can finding and commenting out individual fields. A line break should precede the individual clauses of the SQL statements. In addition, each condition in a WHERE or ON clause should be located on a separate line.
358
10.1
The Readability of the Code
Blank Lines Blank lines should not occur within a statement but, instead, can be used to separate individual statements. In particular, the three sections of a block should be separated by blank lines: 쐍 Declaration of variables 쐍 Declaration of exception handlers 쐍 Statement list
Indentation and Alignment Indentations make the source code easier to read. For example, for field lists, fields should be indented, and for conditions, all comparison operators should be indented. In this book, we formatted the source code largely according to these suggestions. However, exceptions exist in this book because the number of characters per line is limited.
Automatic Code Formatting In ABAP, the pretty printer for ABAP is available, which is a relatively primitive tool for formatting the source code. A pretty printer has exactly two functions: to make indentations according to the nesting level and to capitalize (or lowercase) keywords. Compared to modern formatting tools for other programming languages, such as Java, these capabilities seem antiquated. For SQLScript procedures, unfortunately, no working formatting tool exists. A button in the Web-Based Development Workbench (WBDE) should create the right indentations, but this button only works with pure SQL and, at the same time, removes comments. This function is therefore not useful for procedures or anonymous blocks. Corresponding plug-ins exist for other editors, such as Notepad++. However, these plug-ins are not specifically tuned to SQLScript and therefore do not always deliver satisfactory results.
10.1.2 Mnemonic Names All database objects, variables, and parameters have names. If you choose these names sensibly, your source code will be easier to read. While this
359
10
Clean SQLScript Code
suggestion may seem commonsense, it is frightening how often badly chosen names are found in practice. Meaningful names
For example, variables are sometimes called simply TABLE1 or TABLE2. Using names that actually describe the meaning of these variables in the current context, such as LT_MATERIAL_UNUSED and LT_MATERIAL_TO_DELETE, would be better by making clear the intention of the developer. Thus, the reader of the source code doesn’t need to check all usage scenarios of a variable in order to get an idea its content.
Focus on the difference
When reading source code, easily being able to see where individual variables differ is important. Instead, the obvious similarities often occupy the most space. For example, a procedure called CLEANUP_MATERIAL() obviously deals with the processing of material. The names from the previous section could be shortened without any loss of information: LT_UNUSED and LT_TO_ DELETE.
Uniform terms
Another aspect concerning good names is the uniform use of terms. Each concept should have exactly one name. For example, the source code for the material in the ERP table MARA contains different names, such as MATNR, MATERIAL, MAT, ITEM, or ARTICLE. Each of these names is fine, but only one of these names should be used throughout. The best term is the one used by the business department. Conversely, different terms should also mean different concepts.
Procedure and function names
The name of a procedure or function should always express what it actually does. The caller should not experience any surprises. Favor longer names that describe precisely what you can expect from the procedure.
Hungarian Notation Hungarian notation refers to naming conventions where type information and additional properties of variables are included as prefixes in the names. In ABAP, often the following convention is followed, which we’ve extended a bit for SQLScript. The first digit determines the type of variable: 쐍 L—local variable 쐍 M—instance variable (ABAP only) 쐍 G—global or static variables (ABAP only) 쐍 I—input or importing parameter 쐍 E—exporting parameter (ABAP only)
360
10.1
The Readability of the Code
쐍 R—returning parameter (ABAP only) 쐍 O—OUT parameter (SQLScript only)
The second place determines the data type: 쐍 V—simple scalar variable 쐍 S—structure 쐍 T—table variable
Using this system, IV_MAX_ROWS should be easily recognized as a scalar input parameter and LT_MATERIAL as a local table variable. Such conventions should always be defined for the whole company or at least for the project team to achieve significant improvement in the readability of your source code.
10.1.3 Granularity of Procedures and Functions For the readability of source code, being able to grasp the code in its entirety at a glance can be helpful. Methods in Java should therefore not be longer than a page in the source text editor. According to Robert C. Martin in Clean Code, methods should be 20 lines long, not 100. Unfortunately, this limitation can’t be completely applied to SQLScript because individual statements can already run over several pages. The field list alone in a SELECT query to a wider table can run over 150 lines easily. Nevertheless, you should always strive to write procedures that can be easily grasped by a reader. If, for example, using larger SELECT statements is necessary in a procedure, a reader should at least be able to read these statements without problems, and they shouldn’t be too complex. The user-defined function (UDF) concept can be an elegant solution, as these functions allow you to outsource the subtasks in a query. More complex expressions in a field list should, for example, be encapsulated as functions, which has several advantages: 쐍 The logic in the expression can be given a meaningful description by the
function name, which further reduces the need for comments. 쐍 The complexity of the original source code is reduced, which increases
readability.
361
Outsourcing complexity
10
Clean SQLScript Code
쐍 The new function can easily be tested, which is usually not the case with
expressions in larger queries. 쐍 The function can be reused.
Listing 10.1 shows an example of how the readability of a query can be significantly impaired by expressions in the field list. SELECT id, -- format name lastname || ', ' || firstname AS name, -- Symbol for gender CASE WHEN sex = 'F' THEN NCHAR('9792') WHEN sex = 'M' THEN NCHAR('9794') ELSE '' END AS MW, -- add text for the team COALESCE(( SELECT team_text FROM team_text WHERE ID = team AND langu = 'DE' ), ( SELECT team_text FROM team_text WHERE ID = team AND langu = 'EN' ), '') AS team FROM users; Listing 10.1 Example of Complexity in Simple Queries Using UDFs
If you outsource the three expressions into UDFs, the query becomes considerably less complex as explanatory comments are no longer needed, as shown in Listing 10.2.
362
10.1
The Readability of the Code
SELECT id, udf_name_formatting(firstname, lastname) AS name, udf_symbol_for_gender(sex) AS mw, (SELECT text FROM udf_team_text() WHERE id = team) AS team FROM users ; Listing 10.2 Same Query with Outsourced Coding
Of course, creating UDFs requires additional initial development work, as shown in Listing 10.3. However, this work will pay off many times over if you can avoid errors or at least detect them at an early stage through this procedure. CREATE FUNCTION udf_name_formatting( iv_firstname NVARCHAR(20), iv_lastname NVARCHAR(20) ) RETURNS rv_name NVARCHAR(42) AS BEGIN rv_name = iv_lastname || ', ' || iv_firstname; END; CREATE FUNCTION udf_symbol_for_gender( iv_sex NVARCHAR(1) ) RETURNS rv_symbol NVARCHAR(1) AS BEGIN rv_symbol = CASE WHEN iv_sex = 'F' THEN NCHAR('9792') WHEN iv_sex = 'M' THEN NCHAR('9794') ELSE '' END; END; CREATE FUNCTION udf_team_text( ) RETURNS TABLE(id INT, text NVARCHAR(20)) AS BEGIN lt_team_id = SELECT DISTINCT id FROM TEAM_TEXT;
363
10
Clean SQLScript Code
RETURN SELECT input.id, COALESCE(de.team_text, en.team_text, '') AS text FROM :lt_team_id AS input LEFT OUTER JOIN team_text as de ON de.id = input.id AND de.langu = 'DE' LEFT OUTER JOIN team_text as en ON en.id = input.id AND en.langu = 'EN'; END; Listing 10.3 The Three Functions Used in Listing 10.2
10.1.4 Comments Comments are intended to help people understand the source code. Comments should only serve as explanations of the statements otherwise written for the machine. But if you really want to know what a procedure does, you’ll have to read the source code because the source code is usually updated more frequently than the corresponding comments are. For this reason, the possibility that outdated comments will send us on the wrong track is always a danger. A popular misconception is that many comments make source code more readable, as in the motto “A lot helps a lot.” Good source code should be intelligible without many comments. Extensive commenting only means that there is more text to scroll through to capture the content of a procedure. Comments are in principle superfluous and should be used sparingly and only if they provide real added value to reading the code.
Header Comments Header comments are at the beginning of source code units such as procedures, functions, or methods. These comments can have different tasks, for example:
364
10.1
The Readability of the Code
쐍 Describing the function of the source code unit 쐍 Holding metadata, such as creation time and author 쐍 Specifying a version history 쐍 Referring to legal aspects, such as authorship, copyright, and licenses
Personally, we often consider header comments superfluous. Small procedures with meaningful names do not need further descriptions. If the procedures are larger, consider decomposing the procedure before commenting. If you still think you need a header comment, it should summarize the function. In many projects, there is a duty to provide extensive header comments. However, in our experience, the actual source code is often shorter, easier to read, and more explicit than the associated comment. Extensive commenting can also cause developers to shy away from creating further procedures and functions because mandatory header comments increase the required effort considerably. Imagine how difficult the example shown in Listing 10.3 would be to read if each of the three functions contained extensive header comments.
Structure Comments Source code is often divided into different sections through comments. The comment assumes the function of a header comment for the section. Structure comments often facilitate reading the code. However, often structure comments are indications that a whole section can be outsourced to another procedure.
Explanatory Comments Wherever a developer has to think about why something was done a certain way or what actually happens at one point, an explanation is always helpful. If, for example, a more complex regular expression is used, an explanation is of course helpful.
Redundant Comments A comment that reflects exactly what is written in the code is superfluous. This form of comment often occurs when developers are forced to make a fixed number of comments per line of code. Redundant comments are less
365
Obligation to comment
10
Clean SQLScript Code
accurate than the actual source code and are rarely updated when changes are made. Listing 10.4 shows an example. --Declaration of a variable lv_a of type Integer: DECLARE lv_a INT; --Assign the value 0 to variable lv_a lv_a = 0; Listing 10.4 Redundant Comments Do Not Add Value
10.1.5 Decomposing Complex Queries The suggestions for easily readable source code we provided in the previous section were relatively general and can also be applied to other programming languages. Now, turning to the decomposition of complex queries, we’ll focus on an SQLScript-specific concept. A SELECT query can consist of a large number of relational algebra operations. Frequently, such queries can be split relatively easily into several small, more clear queries. Possible decompositions
In the following sections, we’ll offer a few suggestions for decompositions that have already proven themselves in SAP Business Warehouse (SAP BW) transformations for our projects. Let’s break down a query into its various parts, as follows: 쐍 Inbound projection
An inbound projection should be created for each database table used, which reduces the column list only to the fields relevant for the procedure. Calculations and derivatives that can be calculated within the table can already be made in this step. The selection of the relevant data should already be carried out here. 쐍 Aggregation step
If necessary, aggregations should be performed in a separate step. 쐍 Calculation step
If further calculations are necessary, e.g., because these calculations are based on aggregated data or if intermediate results need to be shared more than once, the corresponding calculation steps can be inserted. 쐍 Join step
Only the join of the tables involved takes place in this step. The individual field lists can be specified using asterisks (*), provided the field
366
10.1
The Readability of the Code
names are unique. That the field names are unique can be ensured in the inbound projection. 쐍 Outbound projection
The last step of a query is an outbound projection, which determines the number of columns, their sequence, and their names. This projection enables us to use asterisks (*) in the preceding steps. The outbound projection also facilitates maintenance, as ideally a new field is only added in the input and output projections. Trivial derivations and formatting can also be applied in the output projection. By separating the process into different steps, the causes of errors can be located and eliminated quickly. In the debugger, you can follow step by step what happens in the query. With a suitable naming convention, you can easily document the task of the individual steps in the names of the local table variables. Listing 10.5 shows an example of the decomposition of a query. The original SELECT statement is already quite confusing even though it involves only three tables and the expressions are simple. -- Original SELECT statement SELECT project, projects.title, SUM(tasks.planned_effort) AS planned_effort, SUM(tasks.effort) AS effort, ROUND(SUM(tasks.effort) /SUM(tasks.planned_effort)*100,0) || '%' AS perc, projects.estimated_effort FROM tasks LEFT OUTER JOIN projects ON projects.id=tasks.project WHERE tasks.status IN (SELECT id FROM status WHERE is_final = true) GROUP BY project, projects.title, projects.estimated_effort
367
Example
10
Clean SQLScript Code
ORDER BY ROUND(SUM(tasks.effort) /SUM(tasks.planned_effort)*100,0); -- Divided into steps: DO BEGIN -- Inbound projection STATUS lt_status_in = SELECT id FROM status WHERE is_final = true; -- Inbound projection TASKS lt_tasks_in = SELECT project, planned_effort, effort FROM tasks WHERE status in (SELECT * FROM :lt_status_in); -- Aggregation of the TASKS on PROJECTS lt_tasks_aggr = SELECT project, SUM(planned_effort) AS planned_effort, SUM(effort) AS effort FROM :lt_tasks_in GROUP BY project; -- Calculation on TASKS lt_tasks_calc = SELECT *, ROUND(effort/planned_effort*100) as perc FROM :lt_tasks_aggr; -- Inbound projection PROJECTS lt_projects_in =
368
10.1
The Readability of the Code
SELECT id, title, estimated_effort FROM projects; -- JOIN-step lt_projects_tasks = SELECT tasks.*, projects.* FROM :lt_tasks_calc AS tasks LEFT OUTER JOIN :lt_projects_in as projects ON tasks.project = projects.id ORDER BY tasks.perc; -- Outbound projection SELECT project, title, planned_effort, effort, perc || '%' as perc, estimated_effort FROM :lt_projects_tasks; END; Listing 10.5 Example of Splitting a Query into Multiple Steps
The decomposition in this example may seem somewhat exaggerated in some respects. Trivial steps could perhaps be summarized. But you can easily see that the readability of the code has improved considerably. When debugging, you can say for each of the steps what you expect as a result. You can try out for yourself that both versions deliver the same result. In fact, SAP HANA executes the exact same execution plan in both versions, which you can see in graphical representation using PlanViz, shown in Figure 10.1.
369
10
Clean SQLScript Code
Figure 10.1 Execution Plan of the Decomposed SELECT Statement
370
10.1
The Readability of the Code
10.1.6 Readable SQLScript Statements Even within an SQLScript statement, you can easily increase readability by considering the following aspects.
Parentheses Always using parentheses in calculations and conditions when different operators are involved makes it much easier for a human reader to understand the correct evaluation sequence.
No Short Forms Although some components of SQLScript statements are optional, writing them fully into the code makes understanding the statements easier. For example, the following two queries in Listing 10.6 differ only by a comma. Both are syntactically correct and provide a result. However, the results differ considerably. Can you tell right away what the difference is? SELECT * FROM colors sizes; SELECT * FROM colors, sizes; Listing 10.6 Example of Short Forms in SQLScript
If instead the statements are written out entirely, as shown in Listing 10.7, you’ll understand the underlying intention much more easily. SELECT * FROM colors AS sizes; SELECT * FROM colors CROSS JOIN sizes; Listing 10.7 The Same Example without Short Form
Notice how the first query is not desirable because you wouldn’t want the column COLORS to be assigned the alias SIZES. Writing out your statements also helps to avoid errors—a comma can always go missing.
371
10
Clean SQLScript Code
Using Column Names with Correlation Names As long as a column name is unique, either because it is read from only one table or because the column only occurs in one of the tables in the FROM clause, you can omit the correlation name (see Chapter 3, Section 3.2.2). However, including correlation names enables human readers to clearly understand which table a column name refers to and so should always be specified.
Always Specify a Column List for Writing Database Statements. In the INSERT statement, the assignment of values to columns is based on their position. As long as all columns in the statement are filled, you don’t have to explicitly specify the column sequence. Instead, the sequence is implicitly taken from the definition of the database table. However, a human reader will first need to read which columns are actually addressed. A further disadvantage is that the code won’t behave robustly when changes are made to the table definition.
Avoid Literals with Exactly One Space in Expressions In ABAP, empty character strings are stored as a single blank character . The session parameter ABAPVARCHARMODE was introduced to enable the SAP HANA database to cope with this behavior. If the parameter is set to TRUE, all literals that contain exactly one space character are replaced by an empty character string.. However, this behavior doesn’t make sense for expressions. For example, if you want to concatenate the first name and last name fields with a space, the space is removed. You can use the code shown in Listing 10.8 to test the behavior in the SQL console. SET 'ABAPVARCHARMODE' SELECT 'Peter' || ' ' SET 'ABAPVARCHARMODE' SELECT 'Peter' || ' '
= 'FALSE'; || 'Mueller' FROM DUMMY; = 'TRUE'; || 'Mueller' FROM DUMMY;
Listing 10.8 Code for Testing
372
10.2
Performance Recommendations
To use a blank character despite being the ABAP mode, you should use the function call CHAR(32), as shown in the following example: SELECT 'Peter' || CHAR(32) || 'Mueller' FROM dummy;
10.2 Performance Recommendations The actions shown in the previous section do not affect the performance of the queries; they serve only “human performance” during the development and maintenance of programs. To ensure that your queries are also processed optimally by the SAP HANA database, let’s discuss a few tips concerning runtime.
10.2.1 Reducing Data Volumes Restrict data volumes early and as much as possible. Runtime depends on both the number of data records and the number of columns. Accordingly, you should only read the data you really need.
10.2.2 Avoid Switching Between Row and Column Engines If data from the row store and data from the column store is used in a query, then a switchover takes place between the two engines involved. For this purpose, the data must be materialized, which costs runtime. Figure 10.1 shows an execution plan with both a column search and a row search operation. At the point of transition between the two, you can see the Materialize Result node.
10.2.3 Declarative Queries We’ve mentioned several times that only declarative queries can be optimized by SAP HANA. Imperative statements should be avoided whenever runtime is important.
373
10
Clean SQLScript Code
10.2.4 Scalar Functions In scalar UDFs, you should avoid using SELECT statements, which might have to be executed quite often. This limitation also includes access to the DUMMY table. As of SAP HANA 2.0, you can specify the keyword DETERMINISTIC after the parameter definition when creating functions. Then, the results of a UDF will always be buffered within a query, which is particularly useful if there are considerably fewer different entries than data records. A good example is the function UDF_SYMBOL_FOR_GENDER from Listing 10.3.
Optimization If you want to optimize your code beyond these recommendations, caution is advised. Always ask yourself, “Is it even worth it? Will optimizing affect the clean structure of my program?” There is no doubt that the grail of efficiency leads to abuse. Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97 % of the time: premature optimization is the root of all evil. This quotation by Donald E. Knuth from 1974(!) describes how performance optimizations carried out in anticipatory obedience can have a negative impact on the readability and maintainability of a program. First, write clean and well-structured code. Your code can be easily optimized later, when performance problems actually occur. The majority of the code is not located on the critical path, where optimizations can actually result in a significant improvement. For this reason, optimizations should always be based on a thorough analysis of the execution plan. The tools you need to perform this analysis are described in Chapter 11.
374
Chapter 11 Tests, Errors, and Performance Analysis In this chapter, we’ll cover methods and tools for finding and correcting errors and runtime bottlenecks.
In Chapter 10, you learned how to write good source code in SQLScript. For further optimizations, you’ll need information about what is not running optimally in a program. In this chapter, you’ll learn about the tools and procedures you can use to check the behavior of your programs. Verifying the complete correctness of a complex program or program part is generally not possible. However, normally during the course of a software lifecycle, tests are carried out at different times. The aim of testing is to reduce the probability of serious undiscovered errors. For us developers, being able to test the individual components of a system is especially important. These components include views, procedures, and functions in a database. Ideally, we can also check these objects (at least partially) automatically.
Correctness
If errors are detected, they must be analyzed. The cause of an error is often not immediately apparent. Then, the cause of the error must be gradually narrowed down using a systematic approach usually by reducing our focus step by step. This reduction happens along two dimensions:
Troubleshooting
쐍 On one hand, we can reduce the data necessary to reproduce the error—
ideally to exactly one dataset. For example, SAP Business Warehouse (SAP BW) transformations are often performed for several million data records, making troubleshooting considerably more difficult. If we can limit the associated data transfer process (DTP) so that the error also occurs for a single data record, the cause of the error often becomes obvious quickly. 쐍 On the other hand, we can gradually focus the program logic. Good mod-
ularization helps us to locate the faulty spot quickly. For this purpose,
375
11
Tests, Errors, and Performance Analysis
we’ll check, at each level from top to bottom, whether the program state, i.e., the variable values, still correspond to expectations. At what point can we recognize unexpected states? We’ll work our way through the different levels of the program: 쐍 The entire program 쐍 Individual procedures or functions 쐍 Individual statements
An important tool for this process is the debugger, which allows us to look over the system’s shoulder during program execution. The state of the program and the individual variables can be observed step by step. Performance
Especially with regard to an application on a database, performance is often an important concern. In addition to measuring the total runtime, knowing which parts of the design require how much time is important. For this purpose, you can display the execution plan of individual SQLScript statements as text or graphically via the PlanViz tool.
11.1 Testing SQLScript Code SQLScript code often refers to the state of the database, which makes automated testing difficult. Unfortunately, no framework exists for Test Driven Development (TDD) in SQLScript. In the SQL console, however, you can create (partially) automated tests yourself. We’ll walk through an example of this next.
11.1.1 SQL Console For easy testing SQL queries, the SQL console is the weapon of choice. When developing more complex queries and procedures, being able to adapt and execute these steps can be helpful. Note that you can save the editor content of the SQL console. Switching over to other tools, such as the debugger or execution plan analysis, can also simplify analysis from the SQL console. Development approach
Developing a procedure or function is usually an iterative process. First, the code is worked on until the object can be created without errors. Then (hopefully), the code will be tested until all test cases have been run to the
376
11.1
Testing SQLScript Code
developer’s satisfaction. Figure 11.1 shows the process during the development of a procedure.
Edit source code
Execute
Error message?
Yes
Execute tests
All tests successful? No
Figure 11.1 Development Cycle for a Procedure
A best practice is to write a complete script in the SQL console for this process at the start of the development that deletes all objects at the beginning. As a result, you can let the script run again and again until you are satisfied with the result. The script consists of the following steps: 쐍 Delete database objects 쐍 Create database objects 쐍 Create test cases 쐍 Execute test cases
The test cases can, for example, be stored in a database table or implemented as individual function calls. Listing 11.1 contains a script for creating and testing a simple user-defined function (UDF) that doesn’t access the database. This pattern for testing a function can be adapted to other functions as well. Creating a defined state in the database tables upfront often makes sense. --Delete database objects DROP TABLE test_square; DROP FUNCTION udf_square; --Create function CREATE FUNCTION udf_square(IN iv_value INT) RETURNS rv_result INT AS BEGIN rv_result = iv_value * iv_value; END;
377
Example
Yes
11
Tests, Errors, and Performance Analysis
--Create testcases CREATE TABLE test_square(value INSERT INTO test_square VALUES INSERT INTO test_square VALUES INSERT INTO test_square VALUES INSERT INTO test_square VALUES INSERT INTO test_square VALUES
INT, square INT); (0,0); (1,1); (2,4); (-1,1); (-2,4);
--Execute testcases SELECT value, square AS expected_value, udf_square(value) AS result, CASE WHEN udf_square(value) = square THEN 'OK' ELSE 'Error' END AS testresult FROM test_square; Listing 11.1 Development Cycle in a Script
11.1.2 Testing ABAP Managed Database Procedure Methods The ABAP development tools user interface contains the data preview—a useful function that enables you to call ABAP Managed Database Procedure (AMDP) methods to check their output. You can open the data preview by right-clicking an AMDP method and then selecting Run As • 1 Data Preview, as shown in Figure 11.2.
Figure 11.2 Calling the Data Preview of an AMDP Method
378
11.1
Testing SQLScript Code
For the data preview, a piece of ABAP code is generated that contains a syntactically correct call of the AMDP method. The input parameters may have to be programmed as well. In the example shown in Figure 11.3, you can find the suitable code of the data preview with the corresponding output.
Figure 11.3 Code and Result of an AMDP Data Preview
379
Data preview
11
Tests, Errors, and Performance Analysis
The data preview is particularly useful for debugging purposes. The code of AMDP routines in SAP BW transformations can also be called easily. Saving the data preview
Unfortunately, the source code of the data preview cannot be saved directly. If you want to create test cases that can be repeated, you must copy and paste the code into an ABAP report. Alternatively, you can also create corresponding ABAP unit tests in a test class.
11.1.3 The TRACE Statement To analyze intermediate results in table variables within a procedure, you can use the TRACE function. This function writes data to a local temporary table (LTT, see Chapter 6, Section 6.1.4): = TRACE();
The table SYS.SQLSCRIPT_TRACE enables you to determine the name of this LTT and read the data. Reading the trace result
Since the LTT only exists during the session in which it was created, the trace result must be analyzed in the same session as the procedure execution. As a result, you can only access the results using dynamic SQL, an example of which is shown in Listing 11.2. DROP PROCEDURE pr_trace; CREATE PROCEDURE pr_trace( OUT ot_result tasks) AS BEGIN lt_tasks = SELECT * FROM tasks; ot_result = TRACE(:lt_tasks); END; DO BEGIN DECLARE lv_sql VARCHAR(1000); DECLARE lv_table VARCHAR(100); CALL pr_trace(?); SELECT * FROM SYS.SQLSCRIPT_TRACE; SELECT table_name INTO lv_table FROM SYS.SQLSCRIPT_TRACE; lv_sql = 'SELECT * FROM ' || lv_table || ';';
380
11.2
The Debugger for SQLScript
EXECUTE IMMEDIATE lv_sql; END; Listing 11.2 Simple Example of the TRACE Statement
The TRACE statement also returns the inbound table as a result. You must then use this result for further coding; otherwise, the corresponding flow branch is removed by the optimizer, and the TRACE statement is not executed. The code, in a productive environment, should not use the TRACE statement because saving in the LTTs consumes a lot of runtime. Accordingly, TRACE statements should only be used during development and test phases.
Alternatives to the TRACE Statement Compared to the TRACE statement, the use of the SQLScript debugger is much less complicated. You don’t have to change your code first for troubleshooting purposes. Filtering with expressions and saving the contents of local table variables are also possible in the debugger.
11.2 The Debugger for SQLScript A debugger enables you to watch the system when it executes the program: You can see step by step what happens with each statement and how the values of each variable change. In the Eclipse development environment, two debuggers for SQLScript are relevant: the “normal” SQLScript debugger and the AMDP debugger. Note that the SQLScript debugger is part of the SAP HANA tools for Eclipse and the AMDP debugger is part of the ABAP development tools for Eclipse. Also, the SAP HANA Web-Based Development Workbench and the SAP Web IDE each have their own SQLScript debugger on board.
11.2.1 The SAP HANA Web-Based Development Workbench Debugger With SAP HANA SPS 09, the SAP HANA Web-Based Development Workbench received a full-fledged debugger for SQLScript. You can set breakpoints in
381
11
Tests, Errors, and Performance Analysis
procedures and step into the program code. External debugging for another user is also possible. Some features that you may know from the ABAP debugger are not available in SQLScript debuggers, including, for example, jumping to another statement during execution or changing variable values.
Requirements To use the SQLScript debugger in the SAP HANA Web-Based Development Workbench, you’ll need the role sap.hana.xs.debugger::Debugger. In addition, the configuration file xsengine.ini must contain the enabled parameter debugger enabled=true, as shown in Figure 11.4.
Figure 11.4 Configuring the SAP HANA Web-Based Development Workbench Debugger
382
11.2
The Debugger for SQLScript
If your system doesn’t contain the debugger section yet, you’ll need to rightclick the configuration file and select Add Section..., as shown in Figure 11.5. In this process, you must add the database parameter enabled = true.
Figure 11.5 Adding the Debugger Section
The Debugger Interface in the SAP HANA Web-Based Development Workbench If the prerequisites for debugging are fulfilled, the following should now be possible: In the source code of the procedures (not in the console!), you can click the line numbers to the left of the editor to open the context menu, as shown in Figure 11.6, or you can double-click the line to set a breakpoint.
Figure 11.6 Breakpoints in the Editor
The corresponding line number will be highlighted in red, as shown in Figure 11.7.
383
11
Tests, Errors, and Performance Analysis
Figure 11.7 Red Highlighting of the Line Number for Marking a Breakpoint Sample procedures
Listing 11.3 contains two procedures so you can test out the functions of the debugger: procedure B calls procedure A. To access the debugger after the breakpoint has been set, you only need to execute the corresponding procedure in the console: CALL b(?);. DROP PROCEDURE A;DROP PROCEDURE B; CREATE PROCEDURE A (IN iv_id INT, OUT ot_users users) AS BEGIN ot_users = SELECT * FROM users WHERE id >= :iv_id and id '1', ot_users=>lt_tmp1); CALL A(iv_id=>'20', ot_users=>lt_tmp20); ot_users = SELECT * FROM :lt_tmp1 UNION SELECT * FROM :lt_tmp20; END; CALL B(?); Listing 11.3 Two Procedures for Debugging
In the SAP HANA Web-Based Development Workbench, the debug browser will open on the right of the editor, as shown in Figure 11.8. The buttons for
384
11.2
The Debugger for SQLScript
controlling debugging process are located at the top of the header. Below these buttons is the area in which variables and expressions are displayed. At the bottom are two tabs: The first displays the Call stack, while the second displays a list of all Breakpoints.
Figure 11.8 The Debug Browser Displayed on the Right
You can also show or hide the debug browser via the menu item SQLDebugger • Debug Browser, as shown in Figure 11.9. You can close the debug browser again by clicking on .
Figure 11.9 Menu Item Debug Browser
385
11
Tests, Errors, and Performance Analysis
Executing the Code If you’ve set a breakpoint and execute your procedure, the debugger stops at the first breakpoint. The two buttons, (Continue) and (Single Step), allow you to control the further processing of the source code. If you click on the first button, the program continues to run—either to the next breakpoint or to the end. The other button always executes exactly one statement, and the debugger stops again. You cannot jump into a called procedure. If you want to debug procedure A from our example, you must also set a breakpoint in its source code. By clicking on , you can temporarily deactivate the breakpoints, and the icon changes will change red: . Click the icon again to reactivate your breakpoints. The button permanently deletes all breakpoints. The button (Connected) indicates that the debugger is currently connected to the editor. If you click on this button, the connection will be lost, and the icon will change to . You can only set breakpoints if the debugger is connected.
Viewing the Data Variables, parameters, and expressions are displayed in the central window of the debug browser. By right-clicking on a variable or expression, you can open a context menu, as shown in Figure 11.10, where you can, among other things, display the data of a local table or save it.
Figure 11.10 Variables and Expressions in the Debug Browser
386
11.2
The Debugger for SQLScript
Clicking on will open the expression editor, where you can enter any expression with reference to your local variables. This expression can then be evaluated. For scalar expressions, the result is directly displayed; for table expressions, you can access the display again via the context menu, as shown in Figure 11.10.
External Debugging To use the SAP HANA Web-Based Development Workbench debugger to connect to other sessions, in particular the sessions of other users, you must select the item Attach/Detach. You can then select the corresponding parameters in the dialog box that opens, shown in Figure 11.11. For example, if you want the debugger to stop in your interface when another SAP HANA user calls a procedure, you must set and specify a filter attribute.
Figure 11.11 Dialog for External Debugging
11.2.2 SQLScript Debugger in SAP HANA Studio Since version SAP HANA 1.0 SPS 05, you can also debug procedures using SAP HANA Studio. The normal debugging perspective of the Eclipse development environment is used in SAP HANA Studio, so that it should resemble other programming languages you know, such as ABAP or Java. For information on the authorizations required for debugging, see SAP Note 1942471.
387
11
Tests, Errors, and Performance Analysis
If you want to debug in Eclipse, you should switch to the debug perspective. Figure 11.12 shows this perspective with the following section: 1 Debug view (list of current debug sessions) 2 Breakpoints 3 Source text (the current line is selected) 4 Overview of variables 5 Detail view of a table variable
Figure 11.12 The Debug Perspective in Eclipse
Debugging a Procedure Starting the debugging process
To debug a single procedure, you must create an appropriate debug configuration. For this purpose, open the dialog for create, manage, and run configurations, as shown in Figure 11.13. Then, select SAP HANA Stored
388
11.2
The Debugger for SQLScript
Procedure on the left and create a new configuration via Debug Configurations.
Figure 11.13 Menu Item for Managing the Debug Configurations Found via the Bug Icon
You can then select the corresponding procedure via Procedure to Debug, as shown in Figure 11.14, and specify the required input parameters in the tab that opens next.
Figure 11.14 Selecting a Procedure in the Debug Configuration
389
11
Tests, Errors, and Performance Analysis
The Advanced tab allows you to define whether to debug only the specified procedure or whether the procedures called by that procedure should be included. This selection determines whether or not the respective procedures for debugging are recompiled. Debug configuration
You can start the debug configuration by clicking on Debug. The procedure is called according to the parameterization. To ensure that the debugger actually stops, you must first set a breakpoint by double-clicking on the line number or opening the context menu.
External Debugging If you want to debug for another user or session, you must also create a new configuration for it, as shown in Figure 11.15.
Figure 11.15 Debug Configuration for Debugging on Behalf of Another User
390
11.2
The Debugger for SQLScript
You must first define the SAP HANA system for which you want to debug. You can then either select an SAP HANA user or specify a database connection in the popup menu after starting the configuration.
11.2.3 AMDP Debugger in the ABAP Development Tools As of SAP HANA 1.0 SPS 9 and SAP NetWeaver 7.50, the AMDP debugger is also available. You can use this debugger to debug AMDP procedures without direct access to the SAP HANA database and without an SAP HANA user. This debugger is different than its ABAP counterpart, but both are well integrated into the same Eclipse interface. When debugging in ABAP code, you can also set breakpoints in the AMDP code for debugging. Only the debugging session display will indicate that you are now on a different level, as shown in Figure 11.16.
Figure 11.16 Debug Sessions When Debugging ABAP and AMDPs Together
Before the AMDP debugger existed, the SQLScript debugger had to be used at the database level. Some instructions on the internet are available, but don’t get confused by them. The most convenient way to debug AMDPs, whether part of an SAP BW transformation routine or not, is to use the AMDP debugger.
Checking the Availability of the AMDP Debugger The AMDP debugger is available for SAP HANA 1.0 SPS 9 and SAP NetWeaver 7.50 and higher. You can easily check out whether the AMDP debugger is available on your system: If you can add a breakpoint within the SQLScript code of an AMDP routine by double-clicking the line number (or the narrow strip to the left of the line), the AMDP debugger is available.
391
11
Tests, Errors, and Performance Analysis
Status of the AMDP Debugger and Breakpoints The AMDP debugger must be started before you can use it, which happens either automatically when you set a breakpoint or manually by selecting the option Activate AMDP Debugger from the context menu of the line numbers within the SQLScript code of an AMDP method, as shown in Figure 11.17.
Figure 11.17 Activating the AMDP Debugger via the Context Menu Breakpoints
A breakpoint is displayed in the AMDP debugger, as in the ABAP debugger, as a small round circle to the left of the line number, as shown in Figure 11.18. The color of the circle depends on the status of the breakpoint. Table 11.1 displays the different meanings.
392
11.2
The Debugger for SQLScript
Figure 11.18 Marking an Active Breakpoint to the Left of the Line Number
Color
Explanation
Blue
Only shortly after the breakpoint has been set. The routine must be recompiled for debugging.
Green
The breakpoint is confirmed, and the debugger is active.
Gray
The debugger is inactive. It can be activated via the context menu on the breakpoint.
White
The breakpoint is deactivated. It can be activated via the context menu on the breakpoint.
Table 11.1 Statuses of Breakpoint Highlighting
After 10 minutes of inactivity, the debugger deactivates itself. The reason for this automatic shutdown is the debugger requires relatively many resources on the ABAP server side when activated.
Debugging SAP BW Transformation Routines The AMDP debugger can also be used for troubleshooting SAP BW transformation routines. All you have to do is call the corresponding AMDP class in the ABAP development tools. In case of an SAP BW/4HANA system, you have to choose the_A class, as described in Chapter 9, Section 9.3. You can set a breakpoint at the desired spot in the corresponding method. Then, check whether the circle icon for the breakpoint is green and whether the AMDP debugger has been activated. When the data transfer process is executed, the AMDP debugger automatically stops at the breakpoint.
Misleading Options In some older versions of the SAP BW system, you have to use the option Parallel SAP HANA Execution for debugging with AMDP routines, as shown in Figure 11.19. Otherwise, the AMDP routines are not executed, and the debugger won’t stop at the breakpoint.
393
11
Tests, Errors, and Performance Analysis
This behavior obviously contradicts the labeling of the option Serially in the Dialog Process (for Debugging). You’ll have to try out each processing mode to see which works on your system.
Figure 11.19 Options for the Processing Mode in a Data Transfer Process
Debugging Routines in Older Versions For older versions, like SAP BW 7.40 or SAP HANA before SP09, the AMDP debugger is not available. A workaround allows you to generate a debug procedure. This procedure first determines the data of the INTAB by querying the respective calculation scenario before it calls the code of the AMDP routine. This debug procedure can be analyzed using the SQLScript debugger (Section 11.2.2). The exact procedure for debugging older versions is described in Thorsten Kessler’s blog (http://s-prs.de/v620804).
Debug Mode Versus Optimized Mode So that procedures can be analyzed with the AMDP debugger, they are recompiled in the so-called debug mode. In this mode, some optimizations that would be considered in the normal, optimized mode are not performed.
11.2.4 Debugging in the SAP Web IDE You can open the debugger in the SAP Web IDE either via the menu item View • Debugger, by clicking the bug icon on the right, or by pressing
394
11.2
The Debugger for SQLScript
(Ctrl) + (A). Once you’ve opened the debugger, a dialog box shows the
options for connecting the debugger, as shown in Figure 11.20.
Figure 11.20 Options for Connecting the Debugger
Figure 11.21 shows the user interface of the debugger in the SAP Web IDE on the right. The buttons for the step-by-step execution of a procedure can be found under the heading Debugger. In contrast to other debuggers, you can also navigate into procedure calls via the down arrow icon under the heading Debugger. Note that this feature is available only as of SAP HANA 2.0 SPS 03. You can access the buttons for connecting and disconnecting the session and for accessing the settings of the active connection via the Active Session dropdown list. Below this section is the Call Stack(s) section in which you can see the call hierarchy. The Variables and Expressions sections are arranged one behind each other as tabs. As in the SAP HANA Web-Based Development Workbench, you can specify expressions for analyzing the data here. You can display table-like data via the corresponding display content button in this section. The list of Breakpoints can be found at the
395
Debugger user interface of the debugger
11
Tests, Errors, and Performance Analysis
bottom of this section, where you can also create watchpoints, which are conditions under which the program flow should be stopped, e.g., when the value of a variable changes.
Figure 11.21 Overview of the SAP Web IDE Debugger Debugging a procedure
To debug a procedure, you must open its context menu by right-clicking on the procedure and select the option Open for Debugging, as shown in Figure 11.22.
Figure 11.22 Context Menu of the Procedure Name for Opening the Debugger
396
11.3
Performance Analysis
A tab will open with the source code of the procedure. As with the debugger in the SAP HANA Web-Based Development Workbench, you can click a line number to set or delete breakpoints. If you call the procedure now, processing will stop at the breakpoints, and you can view the variable values in the debugger area.
11.3 Performance Analysis Now that we’ve dealt with the correctness of the code and the debugging processes in this chapter, let’s introduce some tools in this section that you can use to analyze the runtime required to execute your query. Listing 11.4 contains a simple SQL query. This query is used for the runtime analysis examples in the following sections. You’ll see that even such a small query can provide a large amount of information about the execution. SELECT a.id AS task, a.title, b.firstname, b.lastname, b.email, t.team_text FROM tasks AS a LEFT OUTER JOIN users AS b ON a.assignee = b.id LEFT OUTER JOIN team_text AS t ON b.team = t.id; Listing 11.4 Simple SQL Query for Performance Analysis
11.3.1 Runtime Measurement The simplest and most important tool to improve the runtime is the runtime measurement. When executing code in the SQL console (both in SAP HANA Studio and in the SAP HANA Web-Based Development Workbench), the corresponding runtime for each statement is therefore displayed directly.
397
A simple SQL query
11
Tests, Errors, and Performance Analysis
Figure 11.23 shows the output of the SQL console for executing two SQL queries: First, the query from Listing 11.4 and then a variant of the same query in which all fields of the field list are queried with an asterisk (*). The output shows that the second query took twice as long as the first.
Figure 11.23 SQL Console Output with Runtime Information
Especially with small queries, runtimes cannot always be entirely reproduced, for example, because of other queries in other sessions. For this reason, you should carry out the runtime measurement several times and compare the results in order to obtain reliable measurement results. In our example, we obtained the measurement results shown in Table 11.2 for six execution runs. Query from Listing 11.4
Variant with * in the Field List
3 ms
6 ms
3 ms
7 ms
3 ms
6 ms
4 ms
6 ms
4 ms
5 ms
3 ms
5 ms
Table 11.2 Different Runtimes for the Two SQL Queries
As you can see in Table 11.2, the runtimes can fluctuate considerably. However, the result of this runtime measurement seems to be unambiguous: The query with a few named columns is considerably faster than the query with all columns.
398
11.3
Performance Analysis
11.3.2 Execution Plan To determine for which operations a query requires the longest runtime, we’ll need to look at the execution plan of the query, which shows how the database actually implements our query. Plan operators (POPs) are the components of this execution plan and are executed by different parts of the SAP HANA database—the so-called engines. These engines have each been optimized for individual tasks. In general, better performance can be achieved by avoiding switching between the various engines as much as possible. The designation of engines can be somewhat confusing, since two levels must be distinguished: Depending on how the data is processed, first a distinction exists between the column engine and the row engine. The following list contains an overview of the different engines of the SAP HANA database: 쐍 Row-based processing in the row engine is carried out every time data is
Row engine
read from a row store table. If only row store tables are involved in a query, processing takes place completely in the row engine. Even if window functions are involved, a change to the row engine takes place regularly. 쐍 In contrast, column engine refers to column-based processing. However,
Column engine
this term is an umbrella term for three additional engines that all follow a column-based approach. 쐍 The join engine has been optimized for the high-performance execution
Join engine
of joins and usually executes simple SQL. The plan operators for the join engine have the prefix “JE.” 쐍 The OLAP engine is useful for the execution of analytical queries that
OLAP engine
require the efficient execution of aggregations and calculations on a star schema. Plan operators on the OLAP engine start with the prefix “BW.” 쐍 The calculation engine processes the CE functions. However, their use in
SQLScript is not recommended. Still, the calculation engine is used when calculation views are executed. The corresponding plan operators contain the prefix “CE.”
399
Calculation engine
11
Tests, Errors, and Performance Analysis
EXPLAIN PLAN FOR The EXPLAIN statement causes the database to write information about the execution plan into the global temporary table (GTT) EXPLAIN_PLAN_TABLE. Since this table is a temporary table, you must retrieve the information within the same session, as shown in Listing 11.5, for example. EXPLAIN PLAN FOR SELECT a.id AS task, a.title, b.firstname, b.lastname, b.email, t.team_text FROM tasks AS a LEFT OUTER JOIN users AS b ON a.assignee = b.id LEFT OUTER JOIN team_text AS t ON b.team = t.id; SELECT * FROM explain_plan_table; DELETE FROM explain_plan_table; Listing 11.5 Example of Using the EXPLAIN PLAN Statement
With Plan Analysis in SAP HANA Web-Based Development Workbench, PlanViz in SAP HANA Studio, and Plan Analysis in the SAP Web IDE, enough useful tools are available for plan analysis. Therefore, we don’t see a use case for directly using the EXPLAIN PLAN statement.
11.3.3 Performance Analysis in the SAP HANA Web-Based Development Workbench In the SAP HANA Web-Based Development Workbench, you can also explicitly start a performance analysis in the SQL console, as shown in Figure 11.24. Then, the result of the execution is enriched with additional information, as shown in Figure 11.25, and two additional buttons are available for you to get additional information.
400
11.3
Figure 11.24 Option for Execution with Performance Analysis
Figure 11.25 Additional Runtime Information in the SQL Console
By clicking on , you can execute the query several times in the editor. This repetition will give you more reliable values for the runtime and show its fluctuations. Figure 11.26 shows the result of the first query in the example.
Figure 11.26 Result of Multiple Execution of a Query
The icon allows you to open a new browser page, which provides a tool for plan analysis. With Plan Analysis, you can view detailed information about the execution plan, as shown in Figure 11.27. In particular, you can also upload and download measurement data as PLV files. You can use these files to exchange runtime information between the various runtime analysis tools.
401
Performance Analysis
11
Tests, Errors, and Performance Analysis
Figure 11.27 Plan Analysis on the Web
11.3.4 PlanViz The PlanViz tool is used for the graphical display of an execution plan, which makes it easier to analyze the relatively large amounts of data found in an execution plan. PlanViz is a component of SAP HANA Studio. No equivalent exists in the SAP HANA Web-Based Development Workbench. However, you can save a PLV file in Plan Analysis and then reopen this file in Eclipse with PlanViz.
Calling PlanViz The easiest way to call PlanViz for a query is via the context menu of the editor in the SQL console in SAP HANA Studio, as shown in Figure 11.28. When you click on Visualize • Plan Execute, Eclipse switches to the PlanViz view, and the system displays an overview page with the most important information.
402
11.3
Figure 11.28 Calling PlanViz
Graphical Representation of the Execution Plan Unfortunately, the switchover between the overview page and the graphical display is hidden. As shown in Figure 11.29, you can see the Overview label and next to it the Executed Plan tab with a corresponding icon. If you click on the tab, the system switches to the graphical display shown in Figure 11.30.
Figure 11.29 Overview Page of PlanViz
403
Performance Analysis
11
Tests, Errors, and Performance Analysis
Figure 11.30 Graphical Representation of the Executed Plan Adapting the representation
In the area on the left, you can specify settings for the display. The Node Grouping option enables you to define whether you want operators to be displayed hierarchically, with each hierarchy level representing a box. In this mode, each box can then be opened or closed using the triangle icon in the upper right-hand corner of each box. Without grouping, all plan operators are displayed at the same level, as shown later in Figure 11.32. The Default Inner Plan setting defines which elements are displayed. If you select the Physical option, the system displays the execution plan that was actually run, including all plan operators. If you select Logical, an extremely simplified view is displayed instead. This view is useful especially for analyzing the actual amounts of data as it is displayed at every level. Figure 11.31 displays our small SQL example. The Node Detail option enables you to set different levels of detail for the displayed plan operators. The detailed view is best suited for most applications.
404
11.3
Performance Analysis
Figure 11.31 Logical Representation of the SQL Query with the Respective Data Volume
The graphical display of the execution plan allows you to see the critical path of the runtime via the context menu. This view will help you to find out where optimizations can be worthwhile and where you are unlikely to achieve improvement in overall performance.
Interpretation of the Graphical Execution Plan The execution plan is a directed graph that represents the processing of an SQL query. Each node corresponds to an elementary operation, each edge to a data flow between these nodes. The following information is displayed for each node in the physical representation of the execution plan: 쐍 Inclusive Time
The total time this node requires for executing its task. This time also contains the times of the nodes from which the procedure gets data. 쐍 Exclusive Time
This time is used for executing the operation. No times from other nodes are included.
405
Critical path
11
Tests, Errors, and Performance Analysis
The grouping boxes on each level display the aggregated runtime information as long as the boxes are collapsed. The number of rows passed to the target node is specified at the edges in the execution plan. Even for a fairly simple query (Listing 11.4), the execution plan can become difficult to read, as shown in Figure 11.32.
Figure 11.32 Graphical Display of the Execution in PlanViz without Grouping
406
11.3
In addition to the graphical display of the executed plan, other views are available in PlanViz. These views are displayed in Eclipse in the lower righthand area of several tabs and can provide a different perspective on the execution plan. These views are partly connected with the graphical representation, so that selecting individual elements in the other representation causes a highlighting.
Timeline The Timeline displays the execution time of individual plan operators along the time axis. If grouping is enabled in the graphical display, the operators in the timeline are also displayed hierarchically, as shown in Figure 11.33.
Figure 11.33 Timeline of the Plan Operators in the Timeline View
In this view, you can check the parallelism of processing. In our example, it is easy to see that the attributes are read in parallel.
Operator List The Operator List view provides all details for all plan operators in the execution plan as a table. Filter criteria can be entered in the upper area of the view to restrict the amount of data. Figure 11.34 shows that even for our sample query a large amount of data is collected. The information displayed here is more detailed than the data obtained via EXPLAIN PLAN.
407
Performance Analysis
11
Tests, Errors, and Performance Analysis
Figure 11.34 Operator List View of PlanViz
Tables Used The Tables Used view displays the database tables actually used for an SQL query, as shown in Figure 11.35. By double-clicking on a line, you can switch to the Operator List view with a filter on the plan operators that affect this table. In the performance analysis, you should always take a look at this view to check whether the database tables actually used and the number of entries meet your expectations.
Figure 11.35 Tables Used in an SQL Query
Performance Trace The Performance Trace view once again displays all plan operators as a table, as shown in Figure 11.36. However, the focus here is on the key figures, runtime, and number of rows.
408
11.3
Figure 11.36 Display of the Performance Trace View
PlanViz for SAP BW Queries When executing SAP BW queries, the analysis via PlanViz can also be helpful. This applies in particular if virtual data models with calculation views are also accessed. Since SAP BW queries cannot be executed in the SQL console, the PlanViz data must be imported as a file. To create such a file for a SAP BW query, you must execute it in SAP GUI in Transaction RSRT and then select the option, Execute + Debug. In the selection dialog that opens, shown in Figure 11.37, you must select the option Generate PlanViz File.
Figure 11.37 Debug Options in Transaction RSRT
409
Performance Analysis
11
Tests, Errors, and Performance Analysis
Next, the Save dialog displays, where you’ll specify a storage location and file name. You should use the file extension .plv so that the file can be loaded in SAP HANA Studio. Then, in SAP HANA Studio, you must switch to the PlanViz perspective where you’ll open the File... menu, and select the option Open File.
11.3.5 SQL Analyzer of the Database Explorer of the SAP Web IDE The database explorer of the SAP Web IDE contains the SQL Analyzer, a graphical tool that also enables you to analyze the execution plan. The SQL Analyzer is strongly reminiscent of PlanViz, but offers fewer configuration and display options in SAP HANA 2.0 SPS 03.
Call and User Interface The SQL Analyzer can be found via the popup menu of the Run button, as shown in Figure 11.38. After calling the menu item Analyze SQL, a new tab will be displayed that contains the Overview view, where you’ll see different tiles with information about the execution of the SQL statement, as shown in Figure 11.39. Tools
In the bottom area, you’ll find different tools similar in functionality to the tools found in PlanViz: 쐍 Operators: Plan operators 쐍 Timeline: Time sequence of the operators 쐍 Tables in Use: Tables and columns used in the query 쐍 Table Accesses: Table access
Figure 11.38 Popup Menu of the Run Button
410
11.3
Figure 11.39 Overview View of the Plan Analysis with Tiles
The tiles in the Overview view are linked to various tools: For example, when you click on the Tables in Use tile, the tool with the same name opens at the bottom.
Graphical Display of the Execution Plan The Plan Graph view shows a graphical display of the execution plan, as shown in Figure 11.40. In contrast to PlanViz, no options are available in this view. The nodes only contain the name of the plan operator and the gross/ net times. Additional information can only be displayed in a popup window by clicking on the individual node. For a complete representation of the execution plan, each node must be expanded layer by layer manually, which is pretty annoying even for very small queries. A large monitor with high resolution is helpful for the analysis. The graphic corresponds to the hierarchical view of PlanViz. However, the information about the number of data records between the individual nodes and the cross-node connection arrows is missing from this view. A
411
Performance Analysis
11
Tests, Errors, and Performance Analysis
comparison with Figure 11.40 shows that information content and overview are still better in PlanViz.
Figure 11.40 Graphical Representation of the Execution Plan
11.3.6 SQLScript Code Analyzer With SAP HANA 2.0 SPS 02, two procedures have been provided to analyze the source code of other procedures. The available check rules are contained in database table SYS.SQLSCRIPT_ANALYZER_RULES. Depending on the release, different rules are available, which we’ll summarize next. 쐍 Rules Available with SAP HANA SPS 02:
– UNNECESSARY_VARIABLE Search for unnecessary variables. A variable is redundant if it neither influences the output (parameters, result set) of the procedure nor changes the database status. – UNUSED_VARIABLE_VALUE Search for redundant assignments of values to a variable. If the variable is no longer read after an assignment, this assignment is unnecessary.
412
11.3
Performance Analysis
– UNCHECKED_SQL_INJECTION_SAFETY If dynamic SQL is executed in a procedure and an input parameter is included in the source code for this execution, this rule checks whether the parameter was previously secured with an appropriate procedure. This check can be performed either by escaping with the two procedures, ESCAPE_SINGLE_QUOTES or ESCAPE_DOUBLE_QUOTES, or by checking the input parameter via the procedure IS_SQL_INJECTION_ SAVE. – SINGLE_SPACE_LITERAL Search for literals from exactly one blank space character. Single blank spaces should be avoided, since the behavior of SAP HANA in this case depends on the ABAP VARCHAR mode. 쐍 Rules Available with SAP HANA SPS 03:
– USE_OF_UNASSIGNED_SCALAR_VARIABLE Search for scalar variables that were not assigned before read access. If, for example, a counter in a loop is incremented with X = X + 1, this results in NULL in each loop pass if the variable X had not been initialized with 0 first. – DML_STATEMENTS_IN_LOOPS If possible, data should not be deleted, inserted, or updated in loops. Instead, you should collect changes and execute them with a single statement. – USE_OF_CE_FUNCTIONS Checks if CE functions are used. These should be replaced by SQL statements, as they prevent optimization. – USE_OF_SELECT_IN_SCALAR_UDF For performance reasons, scalar UDFs should not contain any SELECT queries. – COMMIT_OR_ROLLBACK_IN_DYNAMIC_SQL This rule checks whether a COMMIT or ROLLBACK exists in the dynamic SQLScript code. We recommend only using these two transactioncontrolling statements in static SQLScript code. To find out which rules are actually available on your system, use the following query: SELECT * FROM sys.sqlscript_analyzer_rules;
413
Available rules
11
Tests, Errors, and Performance Analysis
In this table, you also select the relevant rules for the procedure calls. For example, you can filter them by category, as needed for the current check. Checking existing procedures
Two procedures available to perform the analysis: You can use ANALYZE_ SQLSCRIPT_OBJECTS to check existing procedures. The objects to be checked and the rules to be used are given to the procedure as parameters. Listing 11.6 shows an example of the call. DO BEGIN lt_rules = SELECT rule_namespace, rule_name, category FROM sqlscript_analyzer_rules; lt_objects = SELECT schema_name , procedure_name AS object_name, definition FROM procedures WHERE schema_name like 'JBRANDEIS'; CALL analyze_sqlscript_objects( :lt_objects, :lt_rules, lt_result_objects, lt_result_findings ); SELECT objects.*, findings.* FROM :lt_result_objects AS objects INNER JOIN :lt_result_findings AS findings ON objects.object_definition_id = findings.object_definition_id; END; Listing 11.6 Call of the SQLScript Code Analyzer for Existing Procedures
Checking the source code
You can add the source code for procedure definition to the procedure SQLSCRIPT_ANALYZER_RULES, which is then checked against the rules specified (see Listing 11.7).
414
11.3
DO BEGIN lt_rules = SELECT rule_namespace, rule_name, category FROM sqlscript_analyzer_rules; CALL analyze_sqlscript_definition( ' CREATE procedure check_me(IN iv_value INT, OUT ov_value INT) AS BEGIN DECLARE lv_unused VARCHAR(3) default '' ''; ov_value = iv_value; END; ', :lt_rules, lt_result_findings ); SELECT * FROM :lt_result_findings; END; Listing 11.7 Call of the SQLScript Code Analyzer for a New Procedure to be Created
The rules implemented so far leave a good impression. Compared to other tools for static code analysis, such as the Code Inspector for ABAP, the rules of the SQLScript Code Analyzer are relatively straightforward. However, the Code Analyzer is obviously designed to accommodate further rules provided at a later stage, as the new rules in SAP HANA SPS 03 show. The call as a procedure also be cumbersome at first. In the SAP Web IDE, you can have all rules checked by right-clicking on a procedure, which makes the Code Analyzer a practical tool for development.
415
Performance Analysis
Appendices A
Data Model for Task Management .............................................
419
B
List of Abbreviations .........................................................................
423
C
The Author ...........................................................................................
425
417
Appendix A Data Model for Task Management
Many examples in this book refer to a small demo data model for task management. Its main purpose is to provide a manageable set of known tables that you can use to try out different queries and statements. Our aim was not to design an optimal data model for task management purposes. Many fields are missing for real task management, such as priority or task categorization.
A.1 Overview of the Tables All entities are stored in tables of the same name. An ID of the integer type is used as the key in each table. Foreign key relationships are not defined as constraints in the table definition. Figure A.1 provides an overview of the data model. 쐍 The users of the system can be assigned as project managers to projects
and as processors to tasks. 쐍 All projects have a project manager, a start date, and a cost estimate. 쐍 Tasks are always assigned to one project and one processor. Tasks have a
status that can change during processing. The key figures for the planned and actual costs are stored as integers (hours). The percentage of completion should be on a scale of 0% to 100%. 쐍 The tasks log is supposed to record the changes to tasks. The status of the
tasks with time stamp and the agent can be stored in it. 쐍 The reference data for the status are flagged with regard to whether or
not the status is final, i.e. whether a task in this status is not to be updated any further. In addition, they have another flag for open tasks that are not (yet) processed.
419
A
Data Model for Task Management
Furthermore, a separate table STATUS_TEXT contains the language-dependent texts of the tasks. Likewise, the TEAM_TEXT table contains the texts of individual teams.
TASKS
PROJECTS
ID
INTEGER(10)
ID
INTEGER(10)
PROJECT
INTEGER(10)
TITLE
NVARCHAR(40)
TITLE
NVARCHAR(40)
PROJECT MANAGER
INTEGER(10)
DESCRIPTION
CLOB(2147483647)
ESTIMATED EFFORT
INTEGER(10)
STATUS
INTEGER(10)
START DATE
DATE(10)
ASSIGNEE
INTEGER(10)
STATUS
INTEGER(10)
PLANNED_EFFORT
INTEGER(10)
EFFORT
INTEGER(10)
CREATION_DATE
DATE(10)
DUE_DATE
DATE(10)
COMPLETION
INTEGER(10)
USERS ID
INTEGER(10)
FIRST NAME
NVARCHAR(20)
LAST NAME
NVARCHAR(20)
EMAIL
NVARCHAR(50)
GENDER
VARCHAR(1)
TEAM
INTEGER(10)
TASKS_LOG TASK
INTEGER(10)
TIMESTAMP
TIMESTAMP(27)
STATUS
INTEGER(10)
USERS
INTEGER(10)
TEAM_TEXT ID
INTEGER(10)
LANGUAGE
VARCHAR(2)
TEAM_TEXT
NVARCHAR(20)
STATUS ID
INTEGER(10)
INTEGER(10)
IS_FINAL
BOOLEAN(2)
LANGUAGE
VARCHAR(2)
IS_OPEN
BOOLEAN(2)
STATUS_TEXT
NVARCHAR(20)
STATUS_TEXT ID
Figure A.1 Overview of the Tables in the Demo Data Model
420
A.3
A.2 Data The data in the demo data model is either fictitious or has been created using a test data generator. In some cases, logical derivations were made using scripts to ensure a consistent set of data. If you need more data in your data model, you can generate data using an online test data generator such as https://www.generatedata.com or https://www.mockaroo.com.
A.3 Installation To install our demo data model, you’ll use four SQL scripts to create the necessary tables, procedures, and functions and to fill the tables with data. You can find the scripts at https://github.com/captainabap/SQLScript_for_SAP_ HANA. Copy the contents of the individual scripts to the clipboard and then open an SQL console for the database schema of your choice, e.g., the personal schema of your database user. Then, insert the scripts and execute each in sequence. Note that you must apply the following sequence: 쐍 01_Create_Tables_EN.sql 쐍 02_Create_Procedures_and_Functions_EN.sql 쐍 03_Fill_Tables_EN.sql 쐍 04_Check_Installation_EN.sql
After running a script, check in the console output to confirm that everything ran without errors. The final script queries the number of rows in the relevant tables, which allows you to check whether the data has loaded correctly. Please note that the German edition of the book has a slightly different demo data model. The scripts are not compatible, because the names of the tables, functions, and procedures are different. You can also save these script files locally and customize them as you like. For example, if you have too much test data, you can easily customize the corresponding script. To delete the created database objects again, we’ve provided a suitable script: 05_Delete_Data_Model_EN.sql.
421
Installation
Appendix B List of Abbreviations
Abbreviation
Meaning
ABAP
Advanced Business Application Programming
ADSO
Advanced DataStore object
ADT
ABAP development tools
AFL
Application function library
AMDP
ABAP Managed Database Procedures
ASE
Adaptive Server Enterprise: a database provided by Sybase, an SAP subsidiary
BW-MT
SAP BW modeling tools
BYOL
Bring Your Own Language
CDS
Core data services
CRUD
Create, read, update, delete
DCL
Data control language
DDL
Data definition language
DML
Data manipulation language
DTP
Data transfer process
GTT
Global temporary table
HCPR
SAP HANA composite provider
HDI
SAP HANA deployment infrastructure
LTT
Local temporary table
423
B
List of Abbreviations
Abbreviation
Meaning
PAL
Predictive analysis library
SAP BW
SAP Business Warehouse
SAP HANA
SAP High Performance Analytic Appliance
SHINE
SAP HANA Interactive Education
SLT
SAP Landscape Transformation
SQL
Structured Query Language
UDFs
User-defined functions
WBDW
SAP HANA Web-Based Development Workbench
SAP HANA XS
SAP HANA extended application services
SAP HANA XSA
SAP HANA extended application services, advanced model
SAP HANA XSC
SAP HANA extended application services, classic model
424
Appendix C The Author
Jörg Brandeis is an independent consultant, developer, and trainer with a focus on SAP BW, SAP HANA, and ABAP OO. He advises well-known customers on technical topics in the area of architecture and development. In addition, he is the leading independent trainer for SQLScript in Germany. Before that, he worked until mid-2015 as a development manager at zetVisions AG in Heidelberg. There he was responsible for the development and architecture of the SAP NetWeaver based products zetVisions CIM and SPoT. In this role, he gained extensive experience with agile development methods and clean code.
425
Index A ABAP ................................................................. 75 ABAP Managed Database Procedure (AMDP) .......................... 314 date format ............................................ 189 unit test .................................................... 316 ABAP Database Connectivity (ABDC) ...................................................... 329 ABAP Managed Database Procedure (AMDP) .............................................. 77, 301 ABAP .......................................................... 314 debugger .................................................. 391 field routine ............................................ 351 framework .............................................. 303 function ........................................... 302, 327 implementing a procedure ............... 307 method ..................................................... 305 objects ....................................................... 308 procedure ....................................... 302, 304 PROCEDURE method .......................... 342 recommendations ............................... 330 retroactive implementation ............ 315 testing the method .............................. 378 tools ........................................................... 338 ABAP_ALPHANUM() ................................ 169 ABAP_LOWER() .......................................... 171 ABAP_UPPER() ........................................... 171 ABS() ............................................................... 207 ACOS() ............................................................ 206 Adaptive Server Enterprise (ASE) .......... 56 ADD_*() ......................................................... 194 ADD_MONTHS_LAST() ........................... 194 ADD_MONTHS() ........................................ 194 ADD_WORKDAYS() .................................. 195 Advanced DataStore objects ................. 346 Aggregate expression .............................. 121 Aggregate function .................................. 121 Alias ................................................................ 115 Alias name ................................................... 158 Alignment .................................................... 359 Alpha conversion ...................................... 169
ALPHANUM ................................................. 167 ALTER TABLE ............................................... 289 Amount ......................................................... 207 APPLY_FILTER ............................................. 275 Array ............................................................... 260 access ........................................................ 261 as local variable .................................... 262 concatenate and split ......................... 263 generate ................................................... 261 table and .................................................. 264 ARRAY_AGG() ............................................. 265 AS BEGIN ................................................... 88, 91 ASCII ...................................................... 166, 184 character set .............................................. 60 ASIN() ............................................................. 206 Assigning an output table ..................... 344 Asterisk .......................................................... 116 ATAN() ........................................................... 206 ATAN2() ......................................................... 206 Automatic number assignment .......... 287 Autonomous transaction ...................... 269 AVG ................................................................. 123
B Basic arithmetic operations .................. 202 BEGIN AUTONOMOUS TRANSACTION ...... 269 block ............................................................. 80 Best practices .............................................. 357 BETWEEN ...................................................... 141 Binary data ................................................... 215 Binary data type ......................................... 213 Binary floating-point number ............. 201 BINTOHEX() ................................................. 215 BINTONHEX() .............................................. 215 BINTOSTR() .................................................. 215 BITCOUNT() ................................................. 218 BITSET() ......................................................... 216 BITUNSET() ................................................... 216 Blank characters ........................................... 60 Blank line ...................................................... 359
427
Index
BLOB ............................................................... 213 Block ................................................................. 80 anonymous ............................................... 82 comment .................................................... 61 BREAK ............................................................ 255 Breakpoint .......................................... 383, 392 Bring Your Own Language (BYOL) ........ 29 Bubble sort algorithm ............................. 265
C Calculation engine .................................... 399 Calculation engine plan operators (CE functions) ......................................... 160 Calendar week ............................................. 197 CALL .................................................................. 88 CALL DATABASE PROCEDURE .............. 330 Call stack ....................................................... 385 CARDINALITY() ........................................... 260 CASCADE ....................................................... 290 CASE .................................................................. 99 CASE expression ........................................ 117 searched ................................................... 118 simple ........................................................ 117 CAST() ............................................................. 218 CEIL() ............................................................... 204 CHAR() ........................................................... 184 Character string ......................................... 166 data type .................................................. 166 function .................................................... 169 literals ......................................................... 64 search within .......................................... 178 Client capability ........................................... 34 Client concept ............................................. 210 Client handling ........................................... 326 CLOB ............................................................... 169 Code pushdown ........................................... 59 Code-to-data paradigm ............................. 57 Colon ................................................................ 67 Column alias ............................................... 158 Column definition .................................... 285 Column engine ........................................... 399 Column list UPSERT ................................. 228 Column name ............................................. 115 Column store ....................................... 24, 286 Column-based storage .............................. 25
428
Comment ............................................... 61, 364 Commercial rounding ............................. 203 COMMIT ........................................................ 268 CompositeProvider ................................... 333 Compression ................................................. 26 CONCAT() ...................................................... 171 array ........................................................... 263 Concatenation ............................................ 170 Constraint ..................................................... 285 CONTAINS .................................................... 145 Content ............................................................ 39 CONTINUE .................................................... 255 Control character ....................................... 355 Conversion data type .................................................. 218 explicit ....................................................... 218 implicit ...................................................... 218 permissible .............................................. 219 CONVERT_CURRENCY() .......................... 210 CONVERT_UNIT() ...................................... 207 Core data services (CDS) ............................ 23 client .......................................................... 326 objects of a table function ................. 325 table function ...................... 302, 319, 320 view ............................................................ 319 Correlation name ............................ 116, 372 COS() ............................................................... 206 COSH() ............................................................ 206 Cosine ............................................................. 206 COT() ............................................................... 206 COUNT ................................................. 121, 123 CREATE FUNCTION ..................................... 90 CREATE PROCEDURE .................................. 83 CREATE TABLE ............................................. 284 CREATE TABLE AS ...................................... 288 CREATE TABLE LIKE .................................. 288 Critical path .................................................. 405 Cross-join ...................................................... 132 Currency conversion ................................ 210 CURRENT_DATE ......................................... 193 CURRENT_LINE_NUMBER ....................... 68 CURRENT_OBJECT_NAME ....................... 68 CURRENT_OBJECT_SCHEMA .................. 68 CURRENT_TIME ......................................... 193 CURRENT_TIMESTAMP ........................... 193 CURRENT_UTCDATE ................................ 193
Index
CURRENT_UTCTIME ................................ 193 CURRENT_UTCTIMESTAMP ................. 193
D Data control language (DCL) ................... 57 Data definition language (DDL) ............. 57 Data manipulation language (DML) ..... 57 Data model data ........................................................... 421 example ................................................... 419 installation ............................................. 421 table ........................................................... 419 task management ................................ 419 Data preview ............................................... 378 Data provisioning server .......................... 34 Data transfer process (DTP) .................. 335 Data type ......................................................... 73 composite ................................................... 73 convert ............................................ 169, 218 primitive ..................................................... 73 scalar ............................................................ 73 Data volume ............................................... 373 Database catalog ......................................................... 38 different systems .................................. 313 schema ........................................................ 36 write access ............................................. 221 Database explorer ..................................... 410 Database object ............................................. 36 DATE ............................................................... 185 DATS ............................................................... 189 DAYNAME() ................................................. 197 DAYOFYEAR() .............................................. 197 Deadlock ....................................................... 270 Debug browser ........................................... 384 Debugger ................................... 376, 381, 387 Debugging external ........................................... 387, 390 in SAP HANA Studio ............................ 390 Decimal floating-point number ......... 201 Declarative programming ..................... 110 DECLARE CONDITION ............................................ 277 CURSOR .................................................... 257 Declaring table variables ....................... 111
DEFAULT DECLARE .................................................. 234 IN parameter ............................................. 86 SCHEMA ...................................................... 87 DELETE .................................................. 232, 245 Delta merge operation ............................... 27 DETERMINISTIC ............................................ 91 Development environment ..................... 40 Deviating fiscal year ................................. 197 Dictionary compression ............................ 26 DISTINCT ...................................................... 114 DO BEGIN ........................................................ 82 DROP TABLE ................................................ 290 DUMMY ............................................................ 76 Dynamic SQL .............................................. 271
E Eclipse ............................................................... 41 debugger .................................................. 388 installation ................................................. 43 SAP Cloud platform ................................ 43 EMPTY ............................................................... 86 Empty date ................................................... 186 Empty result ................................................ 157 END .................................................................... 88 anonymous block .................................... 82 block ............................................................. 80 functions ..................................................... 91 End routine .................................................. 349 End-of-line comment ................................. 61 Engine ............................................................ 399 Equivalent join ........................................... 135 Error code ..................................................... 276 Error handling ................................... 276, 278 Error processing ........................................ 352 ERRORTAB .................................................... 344 Error-tolerant search .................................. 31 Escape expression ..................................... 140 ESCAPE_DOUBLE_QUOTES ................... 275 ESCAPE_SINGLE_QUOTES ..................... 275 Euclidean algorithm ................................ 256 Evaluation sequence of the operators .................................................... 70 EXCEPT .......................................................... 156 Exception, trigger ...................................... 277
429
Index
EXEC ................................................................ 271 EXEC SQL ....................................................... 329 EXECUTE IMMEDIATE ............................. 272 Execution plan ................................. 399, 405 Execution, mixed ...................................... 339 EXISTS ............................................................ 142 Expert routine ............................................ 350 EXPLAIN PLAN ............................................ 400 Exponent ...................................................... 203 Expression ...................................................... 72 regular ....................................................... 174 Expression editor ...................................... 387 Extended store server ............................... 33 EXTRACT() .................................................... 196
F FETCH INTO ................................................. 258 Field list .................................................. 72, 114 Field routine ................................................ 351 Fiscal year ..................................................... 197 Fixed-point number ................................. 201 Floating-point number ........................... 201 FLOOR() ......................................................... 204 Flow control ................................................. 249 FOR loop .............................................. 253, 257 Formatting ................................................... 358 FROM clause ................................................ 130 UPDATE .................................................... 227 Full outer join ............................................. 136 Function .......................................................... 78 Function call in the field list ................. 120
G Generic programming ............................ 271 GEO data ......................................................... 31 Global temporary table (GTT) ............... 248 Granularity .................................................. 361 Graph engine ................................................ 31 Graph processing ........................................ 31 Greatest common divisor ...................... 255 GROUP BY clause ............................. 121, 149 GROUPING SETS ........................................ 151
430
H Hamming distance ................................... 183 HAMMING_DISTANCE() ......................... 183 HAVING clause ........................................... 152 Header comment ....................................... 364 Hexadecimal representation ................ 215 HEXTOBIN() ................................................. 215 High Performance Analytic Appliance ................................................... 24 Hungarian notation ................................. 360
I Identifiers ....................................................... 65 IF ....................................................................... 249 IF_AMDP_MARKER_HDB ...................... 305 Imperative programming ...................... 233 implicit client handling .......................... 326 Implicit date conversion ........................ 187 IN ...................................................................... 141 Increment ..................................................... 294 Index server ................................................... 32 Index-based access .................................... 239 Infinite loop ................................................. 254 Initial value, variable ................................ 234 In-memory ..................................................... 25 Inner join ................................... 124, 133, 155 Input parameter, dynamic SQL ............ 274 INSERT .................................................. 222, 241 Insert-Only ..................................................... 27 Integer ............................................................ 201 INTERSECT .................................................... 155 Intersection .................................................. 155 Interval .......................................................... 141 INTO clause .................................................. 235 INTO clause EXEC ...................................... 273 IS ....................................................................... 144 IS_EMPTY ...................................................... 247 IS_SQL_INJECTION_SAVE ...................... 275 ISCLOSED ...................................................... 259 ISOWEEK() ..................................................... 197
Index
J Join .................................................................. condition ................................................. engine ....................................................... type ............................................................
M 132 133 399 132
L LAG ................................................................. 129 LANGUAGE ..................................................... 86 LANGUAGE SQLSCRIPT functions ..................................................... 91 LAST_DAY() ................................... 195 LCASE() .......................................................... 171 LEAD ............................................................... 129 Left outer join ............................................. 135 LEFT() .............................................................. 172 LENGTH() ...................................................... 170 Lexical element ............................................ 55 LIKE ................................................................. 140 LIKE_REGEXPR ........................................... 184 LIMIT .............................................................. 114 Limit ............................................................... 294 Line break .............................................. 60, 358 Linear dimension ......................................... 96 Linguistic search ................................ 31, 145 Literal ................................................................ 62 LN() ................................................................. 203 LOB .................................................................. 169 Local table variable ................................... 238 Local temporary table (LTT) .................. 249 Local variable ................................................. 67 LOCALTOUTC() ........................................... 198 LOCATE_REGEXPR() ........................ 175, 178 LOCATE() ....................................................... 178 LOG() .............................................................. 203 Logarithm .................................................... 203 Logging ......................................................... 269 Loop ................................................................ 253 LOWER() ........................................................ 171 LPAD() ............................................................ 180 LTRIM() .......................................................... 181
Map Merge ................................................... 161 Material number ....................................... 182 MAX ................................................................ 123 MAXVALUE .................................................. 295 MDC ................................................................... 35 MEMBER OF ........................................ 143, 262 MEMBER_AT() ............................................ 262 MERGE INTO ............................................... 229 MIN ................................................................. 123 MINVALUE ................................................... 295 MOD() ............................................................. 202 MONTHNAME() ......................................... 197 Multicontainer database ........................... 35 Multitenant database containers .......... 35
N Name server ................................................... 32 Naming .......................................................... 359 Native SQL .................................................... 301 NCHAR() ........................................................ 184 NCLOB ............................................................ 169 NDIV0() .......................................................... 202 NEXT_DAY( ) .................................. 195 Non-equivalent join ................................. 135 NOT EXISTS .................................................. 156 NOT NULL ..................................................... 285 NOT NULL DECLARE ................................. 234 NOTFOUND ................................................. 259 NOW() ............................................................. 193 NULL .................................................................. 74 NULL in aggregate functions ................ 124 NULLS FIRST ................................................ 153 NULLS LAST ................................................. 153 Number of rows ......................................... 247 Numerical data ........................................... 201 Numerical literal ........................................... 63 NVARCHAR .................................................. 166
O OCCURRENCES_REGEXPR() ......... 175, 179 OData ................................................................ 30 OFFSET ........................................................... 114
431
Index
OLAP engine ................................................ 399 ON .................................................................... 133 OPEN CURSOR ............................................ 258 Open SQL ............................................... 75, 301 OpenUI5 total ............................................... 30 Operator .......................................................... 69 Operator expression ................................ 117 Operator list ................................................ 407 OPTIONS READ-ONLY .............................. 307 ORDER BY ........................................... 127, 153 ORDINALITY ................................................ 264 OUTTAB ............................................... 344, 354 Overlapping ................................................. 237
P Parameter dynamic SQL ........................................... 272 example ...................................................... 96 named ......................................................... 88 trigger ........................................................ 299 view ............................................................ 293 Parameterization ......................................... 95 Parentheses .......................................... 70, 371 PARTITION BY ............................................. 127 Performance ................................................ 373 Performance analysis .................... 375, 397 Performance Trace .................................... 408 Personal schema .......................................... 36 Phonetic code ............................................. 183 Placeholders ................................................ 140 Plan operator .............................................. 399 PlanViz ........................................................... 402 POWER() ........................................................ 203 Predicate ......................................................... 73 Predictive analytics .................................... 32 Pretty printer .............................................. 359 PRIMARY KEY .............................................. 285 Primary key ....................................... 221, 285 Procedure ................................................ 78, 83 call ................................................................ 88 create ........................................................... 83 parameter list ........................................... 84 properties ................................................... 86 PUBLIC schema ............................................ 36 Public synonym ........................................... 38
432
Q Quantity ........................................................ 207 Quantity conversion ...................... 207, 210 QUARTER() .................................................... 197 Query result, dynamic SQL .................... 273 Query, decompose .................................... 366 Question mark .............................................. 89 Quotation marks ......................................... 65
R RAND_SECURE() ......................................... 206 RAND() ........................................................... 206 Random numbers ..................................... 206 Readability ................................................... 358 READS SQL DATA ......................................... 87 RECORD ......................................................... 343 RECORD_COUNT ....................................... 247 Regular expression ................................... 355 REPLACE ........................................................ 227 REPLACE_REGEXPR() ............. 175, 176, 179 REPLACE() ..................................................... 179 Repository ...................................................... 39 Request .......................................................... 335 Requirements analysis .............................. 95 Reserved words ............................................ 68 RESIGNAL ...................................................... 281 RESTART ........................................................ 296 RESTRICT ....................................................... 290 RETURNS ......................................................... 91 Reuse ................................................................ 78 Right outer join .......................................... 136 RIGHT() .......................................................... 172 ROLLBACK .......................................... 232, 268 ROUND() ........................................................ 203 Rounding ...................................................... 203 Row engine ................................................... 399 Row store ...................................................... 286 ROWCOUNT .......................................... 68, 259 ROWS clause ................................................ 128 RPAD() ............................................................ 181 RTRIM() .......................................................... 181 Runtime measurement ........................... 397
Index
S SAP Business Warehouse (SAP BW) query ......................................................... 409 transformation ..................................... 334 transformation routine ..................... 393 SAP Cloud Platform .................................... 43 SAP Fiori app .................................................. 30 SAP HANA database ..................................................... 24 deployment infrastructure .................. 48 introduction ....................................... 23, 24 SAP HANA database explorer ................. 48 SAP HANA deployment infrastructure (HDI) container ........................................ 30 SAP HANA deployment infrastructure (HDI) server ............................................... 33 SAP HANA extended services (SAP HANA XS) classic model ............................................. 29 server ............................................................ 33 SAP HANA extended services, advanced model (SAP HANA XSA) ... 29 server ............................................................ 33 SAP HANA Studio .................................. 40, 41 database connection ............................. 43 debugger .................................................. 387 SAP HANA Web-Based Development Workbench ......................................... 40, 45 SAP NetWeaver schema ............................ 37 SAP Web IDE ............................................ 40, 48 SAPUI5 total ................................................... 30 Savepoint ........................................................ 26 Scalar query .................................................... 73 Search ............................................................... 31 SEARCH table operator ........................... 246 SECONDDATE ............................................. 192 SECURITY MODE functions ..................... 91 SELECT ........................................................... 109 SELECT clause ............................................. 113 SELECT INTO ............................................... 236 SELECT query .............................................. 113 SELECT statement ..................................... 112 UPSERT ..................................................... 229 Self-join ......................................................... 132 Semantic search ........................................... 31
Semicolon ....................................................... 60 Separation of concerns ........................... 313 Sequence ....................................................... 294 change ...................................................... 296 delete ......................................................... 296 reset ........................................................... 296 Sequence of the operators ........................ 70 SERIES_GENERATE_DATE ...................... 162 Server component ....................................... 32 Session variable ......................................... 247 SET clause ..................................................... 226 Set operations ............................................. 154 SHORTTEXT ................................................. 168 Sign ................................................................. 207 SIGN() ............................................................. 207 SIGNAL ........................................................... 277 SIN() ................................................................ 206 Single container database ......................... 34 SINH() ............................................................. 206 Sinus ............................................................... 206 SLT schema ..................................................... 37 SOUNDEX() .................................................. 183 Special characters ......................................... 65 SQL ..................................................................... 56 SQL Analyzer ............................................... 410 SQL console .......................................... 50, 376 SQL injection ............................................... 275 SQL SECURITY ................................................ 87 SQL__PROCEDURE__SOURCE__ RECORD .................................................... 344 SQL_ERROR_CODE ............................ 68, 278 SQL_ERROR_MESSAGE .................... 68, 278 SQLScript ......................................................... 56 best practices ......................................... 357 performance ........................................... 373 readability ............................................... 371 test .............................................................. 376 SQLScript, Code Analyzer ....................... 412 SQRT() ............................................................ 203 Square root .................................................. 203 Start routine ................................................ 348 Statement ........................................................ 60 Streaming cluster ......................................... 34 String padding .................................................... 180 replace variable ..................................... 179
433
Index
String (Cont.) similarity .................................................. 183 trimming .................................................. 180 STRING_AGG ............................................... 123 Structure comment .................................. 365 Stub procedure ........................................... 310 SUBARRAY() ................................................. 264 Subquery ....................................................... 156 correlated ................................................. 125 in field lists .............................................. 124 SUBSTR_AFTER() ........................................ 173 SUBSTR_BEFORE() ..................................... 173 SUBSTR_REGEXPR() ........................ 173, 175 SUBSTRING() ............................................... 172 Subtracting sets ......................................... 156 SUM ...................................................... 121, 123 System architecture ................................... 32 System database .......................................... 35 System schema ............................................ 37 System variable ............................................ 67
T Table ............................................................... 284 alias ............................................................ 159 change ....................................................... 289 copy ............................................................ 288 create with SQL ...................................... 288 definition ................................................. 284 global temporary .................................. 311 local variable .......................................... 238 parameter ................................................ 310 type ................................................... 286, 291 variable .............................................. 74, 110 Table parameter ........................................... 74 Tables tables used ............................................... 408 Tabs ................................................................... 60 TAN() ............................................................... 206 TANH() ........................................................... 206 Task management .................................... 419 Temporary table ........................................ 248 Tenant .............................................................. 34 Tenant database ........................................... 35 Test ..................................... 100, 104, 375, 376 TEXT ................................................................ 169
434
Text mining ................................................... 31 TIME ................................................................ 191 Time ................................................................ 185 Time information ...................................... 191 Time zone ..................................................... 198 Timeline ........................................................ 407 TIMESTAMP ................................................. 192 TO_ALPHANUM() ...................................... 169 TO_DATE() .................................................... 188 TO_NVARCHAR .......................................... 169 TO_NVARCHAR() ....................................... 188 TO_TIME() ..................................................... 191 TO_VARCHAR() ....................... 169, 188, 191 TOP .................................................................. 114 TRACE ............................................................. 380 Transaction .................................................. 268 Transaction control .................................. 268 Transaction log ............................................. 26 Transaction RSA1 ....................................... 339 Transformation .......................................... 334 on SAP HANA .......................................... 336 routine ....................................................... 338 Transport ...................................................... 341 Triggers .......................................................... 296 Trigonometry .............................................. 206 TRIM_ARRAY() ............................................ 264 TRIM() ............................................................. 181 Troubleshooting ........................................ 375 TRUNCATE TABLE ...................................... 232
U UCASE() .......................................................... 171 UDF_SORT_2 ............................................... 251 UDF_SORT_3 ............................................... 252 UMINUS() ...................................................... 207 Unicode ......................................................... 166 UNICODE() .................................................... 184 UNION ............................................................ 154 Union .............................................................. 154 UNIQUE ......................................................... 285 UNNEST() ....................................................... 264 UPDATE ......................................................... 226 table operator ........................................ 243 UPPER() .......................................................... 171 UPSERT ........................................................... 227
Index
User-defined function (UDF) ......... 90, 361 create ........................................................... 90 implementation ....................................... 97 properties ................................................... 90 sample application ................................. 94 sample program flow ............................ 96 scalar ......................................................... 120 USING ............................................................ 307 view ............................................................ 310 WADP routine ........................................ 345 UTC ................................................................. 198 UTCTOLOCAL() ........................................... 198
V Value constant ................................................... VARBINARY ................................................. VARCHAR ..................................................... Variable ......................................................... local scalar .............................................. scalar ......................................................... visibility .................................................... VERTICAL_UNION ....................................
121 213 166 233 233 121 237 351
View ................................................................ 291 Visibility ........................................................ 237
W Watchpoint .................................................. 396 WBDW 씮 SAP HANA Web-Based Development Workbench WEEK() ........................................................... 197 WEEKDAY() .................................................. 197 WHEN MATCHED ...................................... 231 WHERE comparison ............................................. 138 with multiple values ............................ 139 WHERE clause DELETE ...................................................... 232 UPSERT ..................................................... 229 WHERE condition ...................................... 138 WHILE Loop ................................................. 254 Whitespace ..................................................... 60 Window functions .................................... 125 WITH clause ................................................. 147 WITH ENCRYPTION ..................................... 87 WITH ORDINALITY ................................... 264
435
Service Pages The following sections contain notes on how you can contact us.
Praise and Criticism We hope that you enjoyed reading this book. If it met your expectations, please do recommend it. If you think there is room for improvement, please get in touch with the editor of the book: [email protected]. We welcome every suggestion for improvement but, of course, also any praise! You can also share your reading experience via Twitter, Facebook, or email.
Supplements If there are supplements available (sample code, exercise materials, lists, and so on), they will be provided in your online library and on the web catalog page for this book. You can directly navigate to this page using the following link: http://www.sap-press.com/4862. Should we learn about typos that alter the meaning or content errors, we will provide a list with corrections there, too.
Technical Issues If you experience technical issues with your e-book or e-book account at SAP PRESS, please feel free to contact our reader service: [email protected].
About Us and Our Program The website http://www.sap-press.com provides detailed and first-hand information on our current publishing program. Here, you can also easily order all of our books and e-books. Information on Rheinwerk Publishing Inc. and additional contact options can also be found at http://www.sap-press.com.
i
Legal Notes This section contains the detailed and legally binding usage conditions for this e-book.
Copyright Note This publication is protected by copyright in its entirety. All usage and exploitation rights are reserved by the author and Rheinwerk Publishing; in particular the right of reproduction and the right of distribution, be it in printed or electronic form. © 2019 by Rheinwerk Publishing, Inc., Boston (MA)
Your Rights as a User You are entitled to use this e-book for personal purposes only. In particular, you may print the e-book for personal use or copy it as long as you store this copy on a device that is solely and personally used by yourself. You are not entitled to any other usage or exploitation. In particular, it is not permitted to forward electronic or printed copies to third parties. Furthermore, it is not permitted to distribute the e-book on the Internet, in intranets, or in any other way or make it available to third parties. Any public exhibition, other publication, or any reproduction of the e-book beyond personal use are expressly prohibited. The aforementioned does not only apply to the e-book in its entirety but also to parts thereof (e.g., charts, pictures, tables, sections of text). Copyright notes, brands, and other legal reservations as well as the digital watermark may not be removed from the e-book.
Digital Watermark This e-book copy contains a digital watermark, a signature that indicates which person may use this copy. If you, dear reader, are not this person, you are violating the copyright. So please refrain from using this e-book and inform us about this violation. A brief email to [email protected] is sufficient. Thank you!
ii
Trademarks The common names, trade names, descriptions of goods, and so on used in this publication may be trademarks without special identification and subject to legal regulations as such. All of the screenshots and graphics reproduced in this book are subject to copyright © SAP SE, Dietmar-Hopp-Allee 16, 69190 Walldorf, Germany. SAP, the SAP logo, ABAP, Ariba, ASAP, Concur, Concur ExpenseIt, Concur TripIt, Duet, SAP Adaptive Server Enterprise, SAP Advantage Database Server, SAP Afaria, SAP ArchiveLink, SAP Ariba, SAP Business ByDesign, SAP Business Explorer, SAP BusinessObjects, SAP BusinessObjects Explorer, SAP BusinessObjects Lumira, SAP BusinessObjects Roambi, SAP BusinessObjects Web Intelligence, SAP Business One, SAP Business Workflow, SAP Crystal Reports, SAP EarlyWatch, SAP Exchange Media (SAP XM), SAP Fieldglass, SAP Fiori, SAP Global Trade Services (SAP GTS), SAP GoingLive, SAP HANA, SAP HANA Vora, SAP Hybris, SAP Jam, SAP MaxAttention, SAP MaxDB, SAP NetWeaver, SAP PartnerEdge, SAPPHIRE NOW, SAP PowerBuilder, SAP PowerDesigner, SAP R/2, SAP R/3, SAP Replication Server, SAP S/4HANA, SAP SQL Anywhere, SAP Strategic Enterprise Management (SAP SEM), SAP SuccessFactors, The Best-Run Businesses Run SAP, TwoGo are registered or unregistered trademarks of SAP SE, Walldorf, Germany.
Limitation of Liability Regardless of the care that has been taken in creating texts, figures, and programs, neither the publisher nor the author, editor, or translator assume any legal responsibility or any liability for possible errors and their consequences.
iii