-
Notifications
You must be signed in to change notification settings - Fork 286
/
zcl_demo_abap_sql.clas.abap
2193 lines (1693 loc) · 83.9 KB
/
zcl_demo_abap_sql.clas.abap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"! <p class="shorttext"><strong>ABAP SQL</strong><br/>ABAP cheat sheet example class</p>
"!
"! <p>The example class demonstrates syntax and concepts related to ABAP SQL.<br/>
"! Choose F9 in ADT to run the class.</p>
"!
"! <h2>Note</h2>
"! <p>Find information on <strong>getting started with the example class</strong> and the
"! <strong>disclaimer</strong> in the ABAP Doc comment of class {@link zcl_demo_abap_aux}.</p>
CLASS zcl_demo_abap_sql DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES: if_oo_adt_classrun.
CLASS-METHODS:
class_constructor.
PROTECTED SECTION.
PRIVATE SECTION.
CLASS-METHODS: select_from_dbtab.
CLASS-DATA:
struct TYPE zdemo_abap_flsch,
itab TYPE TABLE OF zdemo_abap_flsch,
itab_res TYPE TABLE OF zdemo_abap_carr.
ENDCLASS.
CLASS zcl_demo_abap_sql IMPLEMENTATION.
METHOD class_constructor.
"Filling demo database tables.
zcl_demo_abap_aux=>fill_dbtabs( ).
ENDMETHOD.
METHOD if_oo_adt_classrun~main.
out->write( |ABAP cheat sheet example: ABAP SQL\n\n| ).
out->write( |Using SELECT for multiple purposes\n| ).
out->write( |1) Reading a single row from database table into a structure\n\n| ).
"Note that, although it is optional, a WHERE clause should always be
"specified for performance reasons and to restrict the read result.
"In the following SELECT statements, a simple WHERE condition is
"used to limit the number of found results.
"Reading all fields
"Reading into existing structure
SELECT SINGLE FROM zdemo_abap_flsch
FIELDS *
WHERE carrid = 'LH' AND connid = '400'
INTO @struct.
"Alternative syntax (no FIELDS), target variable declared inline
SELECT SINGLE *
FROM zdemo_abap_flsch
WHERE carrid = 'AA' AND connid = '17'
INTO @DATA(struct_1a).
out->write( data = struct name = `struct` ).
out->write( |\n| ).
out->write( data = struct_1a name = `struct_1a` ).
out->write( |\n| ).
"Reading selected fields
SELECT SINGLE carrid, connid, cityfrom, cityto
FROM zdemo_abap_flsch
WHERE carrid = 'AZ' AND connid = '555'
INTO @DATA(struct_1b).
"Alternative syntax (with FIELDS)
SELECT SINGLE
FROM zdemo_abap_flsch
FIELDS carrid, connid, cityfrom, cityto
WHERE carrid = 'DL' AND connid = '106'
INTO @DATA(struct_1c).
"When reading a selected set of fields into an existing target
"variable, the CORRESPONDING FIELDS OF addition in the INTO clause
"should be used. Other, not selected fields remain initial.
DATA struct_1d LIKE struct.
SELECT SINGLE carrid, connid, cityfrom, cityto
FROM zdemo_abap_flsch
WHERE carrid = 'DL' AND connid = '106'
INTO CORRESPONDING FIELDS OF @struct_1d.
out->write( data = struct_1b name = `struct_1b` ).
out->write( |\n| ).
out->write( data = struct_1c name = `struct_1c` ).
out->write( |\n| ).
out->write( data = struct_1d name = `struct_1d` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `2) Reading mutliple rows into an internal table` ) ).
"Reading all fields into an existing internal table
SELECT FROM zdemo_abap_flsch
FIELDS *
WHERE carrid = 'DL'
INTO TABLE @itab.
"Alternative syntax (no FIELDS), reading of a selected set of
"fields, internal table is declared inline
SELECT carrid, connid, cityfrom, cityto
FROM zdemo_abap_flsch
WHERE carrid = 'AZ'
INTO TABLE @DATA(itab_2a).
"When reading a selected set of fields into an existing target
"variable, the CORRESPONDING FIELDS OF addition in the INTO clause
"should be used. Other, not selected fields remain initial.
DATA itab_2b LIKE itab.
SELECT carrid, connid, cityfrom, cityto
FROM zdemo_abap_flsch
WHERE carrid = 'AZ'
INTO CORRESPONDING FIELDS OF TABLE @itab_2b.
out->write( data = itab name = `itab` ).
out->write( |\n| ).
out->write( data = itab_2a name = `itab_2a` ).
out->write( |\n| ).
out->write( data = itab_2b name = `itab_2b` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `3) SELECT loop: Sequentially reading multiple rows` ) ).
"In the example below, the individual rows that are read are
"modified before they are appended to an internal table.
DATA itab3 LIKE itab.
SELECT FROM zdemo_abap_flsch
FIELDS * "All fields
WHERE carrid = 'DL'
INTO @DATA(struct3).
"Further processing of the structure if the reading is successful
IF sy-subrc = 0.
"Modification: Converting miles to kilometers
IF struct3-distid = 'MI'.
struct3-distance = struct3-distance * '1.609344'.
struct3-distid = 'KM'.
ENDIF.
"Appending structure to an internal table
APPEND struct3 TO itab3.
ENDIF.
ENDSELECT.
out->write( data = itab3 name = `itab3` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `4) INTO CORRESPONDING FIELDS OF: Reading into existing` &&
` target variables that have a line type not matching the type of the data source` ) ).
"Note: The addition CORRESPONDING FIELDS OF is needed when using
"an existing variable to read data into, otherwise a type
"compatibility issue might arise because the SELECT statement fills
"the variable from left to right beginning with the first
"component. In the example below, the identically named fields have
"a matching type.
"Creating structure type, structure and internal table.
TYPES: BEGIN OF struc_type,
carrid TYPE zdemo_abap_flsch-carrid,
connid TYPE zdemo_abap_flsch-connid,
cityfrom TYPE zdemo_abap_flsch-cityfrom,
cityto TYPE zdemo_abap_flsch-cityto,
END OF struc_type.
DATA struc4 TYPE struc_type.
DATA itab4 TYPE TABLE OF struc_type.
"Reading into a structure that has not a matching type
SELECT SINGLE FROM zdemo_abap_flsch
FIELDS carrid, connid, cityfrom, cityto
WHERE carrid = 'AZ' AND connid = '555'
INTO CORRESPONDING FIELDS OF @struc4.
"Reading into an internal table that has not a matching type
SELECT FROM zdemo_abap_flsch
FIELDS *
WHERE carrid = 'AZ'
INTO CORRESPONDING FIELDS OF TABLE @itab4.
out->write( data = struc4 name = `struc4` ).
out->write( |\n| ).
out->write( data = itab4 name = `itab4` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `Clause variations and additions in SELECT statements` ) ).
"SELECT/FROM clause variants
out->write( |SELECT/FROM clause variants\n| ).
out->write( |5) Checking the existence of a row in a database table\n| ).
"Instead of @abap_true, you could also use 'X' in the example below.
SELECT SINGLE @abap_true
FROM zdemo_abap_flsch
WHERE carrid = 'AZ' AND connid = '555'
INTO @DATA(exists).
IF exists = abap_true.
out->write( `A line was found.` ).
ELSE.
out->write( `Nothing found.` ).
ENDIF.
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `6) DISTINCT addition: Removing duplicative rows from the result set` ) ).
"The example shows the comparison of statements with and without
"the use of DISTINCT. When used without DISTINCT, the result
"shows multiple entries whereas the statement with DISTINCT
"filters the duplicates out.
"DISTINCT addition
SELECT DISTINCT cityfrom
FROM zdemo_abap_flsch
WHERE carrid = 'LH' AND
cityto = 'NEW YORK'
INTO TABLE @DATA(itab_6a).
"Similar statement not using DISTINCT
SELECT cityfrom
FROM zdemo_abap_flsch
WHERE carrid = 'LH' AND
cityto = 'NEW YORK'
INTO TABLE @DATA(itab_6b).
out->write( data = itab_6a name = `itab_6a` ).
out->write( |\n| ).
out->write( data = itab_6b name = `itab_6b` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `7) SELECT list variants` ) ).
"Example 1: All fields
SELECT * FROM zdemo_abap_flsch
WHERE carrid = 'JL'
INTO TABLE @DATA(itab_7a).
"Example 2: Selected set of fields using a comma-separated list
SELECT carrid, connid, cityfrom, cityto FROM zdemo_abap_flsch
WHERE carrid = 'JL'
INTO TABLE @DATA(itab_7b).
"Example 3: Data source is explicitly specified;
"the last column in the select list is purposely specified without it; not mandatory in the case below
SELECT zdemo_abap_flsch~carrid,
zdemo_abap_flsch~connid,
zdemo_abap_flsch~airpfrom,
airpto
FROM zdemo_abap_flsch
WHERE carrid = 'JL'
INTO TABLE @DATA(itab_7c).
"Example 4: Data source is explicitly specified; all fields
SELECT zdemo_abap_flsch~*
FROM zdemo_abap_flsch
WHERE carrid = 'JL'
INTO TABLE @DATA(itab_7d).
"Example 5: Alias names defined for fields
"Data is read into a target variable declared inline
SELECT FROM zdemo_abap_flsch
FIELDS carrid AS carr,
connid AS conn,
cityfrom AS ctyfr,
cityto
WHERE carrid = 'JL'
INTO TABLE @DATA(itab_7e).
"Example 6: Data is read from a database table into an existing
"table but the line type does not match. The fields also have
"different names (but the same type). Due to the use of alias
"names, the fields are read into the corresponding fields.
TYPES: BEGIN OF struc_type_diff,
carr_id TYPE zdemo_abap_flsch-carrid,
conn_id TYPE zdemo_abap_flsch-connid,
city_from TYPE zdemo_abap_flsch-cityfrom,
city_to TYPE zdemo_abap_flsch-cityto,
END OF struc_type_diff.
DATA itab_7f TYPE TABLE OF struc_type_diff.
"In the simple case below, the addition CORRESPONDING FIELDS OF is not
"even necessary.
SELECT FROM zdemo_abap_flsch
FIELDS carrid AS carr_id,
connid AS conn_id,
cityfrom AS city_from,
cityto AS city_to
WHERE carrid = 'AZ'
INTO CORRESPONDING FIELDS OF TABLE @itab_7f.
"Example 7: Alias for the data source
SELECT ds~carrid, ds~connid
FROM zdemo_abap_flsch AS ds
WHERE carrid = 'JL'
INTO TABLE @DATA(itab_7g).
out->write( data = itab_7a name = `itab_7a` ).
out->write( |\n| ).
out->write( data = itab_7b name = `itab_7b` ).
out->write( |\n| ).
out->write( data = itab_7c name = `itab_7c` ).
out->write( |\n| ).
out->write( data = itab_7d name = `itab_7d` ).
out->write( |\n| ).
out->write( data = itab_7e name = `itab_7e` ).
out->write( |\n| ).
out->write( data = itab_7f name = `itab_7f` ).
out->write( |\n| ).
out->write( data = itab_7g name = `itab_7g` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `8) Reading from an internal table using SELECT` ) ).
"Note: The internal table from which to be read must be specified
"as host variable. The internal table should have an explicitly
"defined primary key.
DATA itab_read1 TYPE TABLE OF zdemo_abap_flsch
WITH NON-UNIQUE KEY mandt carrid connid.
"Reading from database table to fill an internal table.
SELECT FROM zdemo_abap_flsch
FIELDS mandt, carrid, connid, cityfrom, cityto
WHERE carrid = 'AA'
INTO TABLE @itab_read1.
"Reading from internal table.
SELECT FROM @itab_read1 AS itab
FIELDS *
WHERE carrid = 'AA'
INTO TABLE @DATA(itab_read2).
out->write( data = itab_read2 name = `itab_read2` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( 'INTO clause variants' ) ).
out->write( |9) UP TO: Limiting the number of returned table rows\n\n| ).
"Restricting the absolute number of returned table rows
"by specifying a number n in the addition UP TO n ROWS.
"In this case, the addition ORDER BY is also specified (but need not be specified).
"The rows of the hit list are sorted on the database server and only the number of
"sorted rows specified for UP TO n ROWS are passed to the result set. If the addition
"ORDER BY is not specified, n arbitrary rows that meet the WHERE condition are passed
"to the result set. If the ORDER BY clause does not sort the result set uniquely,
"it is not possible to define which rows are in the result set.
"Other examples here do not use the ORDER BY clause.
SELECT *
FROM zdemo_abap_flsch
WHERE carrid = 'LH'
ORDER BY carrid
INTO TABLE @DATA(itab_up)
UP TO 2 ROWS.
out->write( data = itab_up name = `itab_up` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `10) OFFSET: Returning only the table rows after a row with a specified count from the result set` ) ).
"In the example, data of all flights are retrieved, except for the 2 flights
"with the shortest flight time.
"To compare the result sets, there is one example with and one without the addition.
SELECT *
FROM zdemo_abap_flsch
WHERE carrid = 'LH'
ORDER BY fltime ASCENDING
INTO TABLE @DATA(itab_no_off).
out->write( data = itab_no_off name = `itab_no_off` ).
out->write( |\n| ).
SELECT *
FROM zdemo_abap_flsch
WHERE carrid = 'LH'
ORDER BY fltime ASCENDING
INTO TABLE @DATA(itab_w_off)
OFFSET 2.
out->write( data = itab_w_off name = `itab_w_off` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `11) Reading into individual elementary data objects` ) ).
"The field list and the INTO list must have the
"same number of elements.
"In the example, a structure and internal table are created
"to process the individually read fields within a SELECT loop.
"Structure and internal table to include the read result
DATA struct_ind TYPE struc_type.
DATA itab_ind TYPE TABLE OF struc_type.
SELECT FROM zdemo_abap_flsch
FIELDS carrid, connid, cityfrom, cityto
WHERE carrid = 'JL'
INTO (@DATA(carr_id),@DATA(conn_id),@DATA(city_from),
@DATA(city_to)).
IF sy-subrc = 0.
"Filling structure components with the individual values
struct_ind = VALUE #( carrid = carr_id
connid = conn_id
cityfrom = city_from
cityto = city_to ).
"Appending structure to internal table
APPEND struct_ind TO itab_ind.
ENDIF.
ENDSELECT.
out->write( data = itab_ind name = `itab_ind` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `12) Appending the result set to an existing internal table` ) ).
"APPEDNING TABLE
"In the example, the existing internal table has the same line type
"as the database table. The internal table from the previous
"example is used to have a table with entries.
SELECT *
FROM zdemo_abap_flsch
WHERE carrid = 'JL'
APPENDING TABLE @itab_up.
out->write( data = itab_up name = `itab_up` ).
out->write( |\n| ).
"APPENDING CORRESPONDING FIELDS OF TABLE
"In the example, the existing internal table has not a matching
"line type as the database table. First, an internal table table
"is filled using the INTO CORRESPONDING ... addition. Then, a
"statement with an APPENDING CORRESPONDING ... addition ensures
"that the existing content is kept and the target variable
"receives the read data in the corresponding fields.
DATA itab_corr TYPE TABLE OF struc_type.
"INTO CORRESPONDING FIELDS OF: Filling internal table anew
SELECT *
FROM zdemo_abap_flsch
WHERE carrid = 'LH'
INTO CORRESPONDING FIELDS OF TABLE @itab_corr
UP TO 2 ROWS.
"APPENDING CORRESPONDING FIELDS OF: Adding to existing table lines
SELECT *
FROM zdemo_abap_flsch
WHERE carrid = 'JL'
APPENDING CORRESPONDING FIELDS OF TABLE @itab_corr.
out->write( data = itab_corr name = `itab_corr` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `13) Reading into packages of a specified number of rows` ) ).
"After PACKAGE SIZE, the number of rows is specified denoting the number
"of rows to be inserted in the target object per iteration The internal
"table that is displayed shows all entries, i.e. all packages. Furthermore,
"a string table is filled and displayed to visualize the package size of each
"internal table per iteration.
DATA itab_pack TYPE TABLE OF zdemo_abap_flsch.
DATA pack_table TYPE string_table.
SELECT FROM zdemo_abap_flsch
FIELDS carrid, connid, cityfrom, cityto
WHERE carrid <> 'AZ' AND carrid <> 'DL'
INTO TABLE @DATA(itab_package)
PACKAGE SIZE 3.
IF sy-subrc = 0.
APPEND |Internal table lines processed: | &&
|{ lines( itab_package ) }| TO pack_table.
"Adding internal table content to another internal table
itab_pack = CORRESPONDING #( BASE ( itab_pack )
itab_package ).
ENDIF.
ENDSELECT.
out->write( data = pack_table name = `pack_table` ).
out->write( |\n| ).
out->write( data = itab_pack name = `itab_pack` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `14) Specifying an anonymous data object as target object` ) ).
SELECT *
FROM zdemo_abap_flsch
WHERE carrid = 'LH'
INTO TABLE NEW @DATA(dref)
UP TO 2 ROWS.
out->write( data = dref->* name = `dref->*` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `Excursion: ABAP SQL - Operands and Expressions` ) ).
out->write( |15) SQL operands\n\n| ).
"SQL operands are elementary operands in an ABAP SQL statement.
"Can be database table or view columns, a literal, host variables
"(i. e. global or local data objects escaped using @) or host
"expressions (@( ... )).
"The literals can be typed (using the type name and content within
"a pair of backquotes: char`abc`) with built-in ABAP Dictionary
"types or untyped.
"Regarding host expressions: Structures and internal tables are
"possible as host expressions for statements modifying the content
"of database tables as shown further down.
"The example below demonstrates possible operands.
DATA upto TYPE i VALUE 3.
SELECT FROM zdemo_abap_flsch
FIELDS
"Specifies a column of a data source directly using its name
cityfrom,
"Column selector ~ can be used to prefix every specified column.
"Here, it is optional. It is non-optional, e. g., if multiple data
"sources in an ABAP SQL statement are edited and the column name
"is not unique.
zdemo_abap_flsch~cityto,
'Lufthansa' AS name, "Untyped literal
char`X` AS flag, "Typed literal
@upto AS num, "Host variable
@( cl_abap_context_info=>get_system_date( ) ) AS date "Host expression
WHERE carrid = 'LH' "Untyped literal
AND countryfr = char`DE` "Typed literal
"Data object created inline and escaped with @
INTO TABLE @DATA(sql_operands)
"The following shows all options having the same effect
UP TO 3 ROWS. "Untyped numeric literal
"UP TO int4`3` ROWS. "Typed numerice literal
"UP TO @upto ROWS. "Host variable
"UP TO @( 10 - 7 ) ROWS. "Host expression
out->write( data = sql_operands name = `sql_operands` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `16) Numeric functions ` ) ).
"You can use built-in functions in ABAP SQL.
"Result: Value with the associated dictionary type.
"Arguments of the functions: Cover one or more SQL expressions.
SELECT SINGLE
carrname,
"Division, result rounded to an integer
div( 4, 2 ) AS div,
"Division, 3rd argument: result is rounded to the specified
"number of decimals
division( 1, 3, 2 ) AS division,
"Result is rounded to first greater integer
ceil( decfloat34`1.333` ) AS ceil,
"Result is the remainder of division
mod( 3, 2 ) AS mod,
"Result: Largest integer value not greater than the specified
"value
floor( decfloat34`1.333` ) AS floor,
"Returns the absolute number
abs( int4`-2` ) AS abs,
"Result is rounded to the specified position after the decimal
"separator
round( decfloat34`1.337`, 2 ) AS round
FROM zdemo_abap_carr
WHERE carrid = 'AA'
INTO @DATA(numeric_functions).
out->write( data = numeric_functions name = `numeric_functions` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `17) String functions` ) ).
SELECT SINGLE
carrid, "LH
carrname, "Lufthansa
url, "http://www.lufthansa.com
"Concatenates strings, ignores trailing blanks
concat( carrid, carrname ) AS concat,
"Concatenates strings, number denotes the blanks that are inserted
concat_with_space( carrid, carrname, 1 ) AS concat_with_space,
"First letter of a word -> upper case, all other letters ->
"lower case; note that a space and other special characters means
"a new word.
initcap( url ) AS initcap,
"Position of the first occurrence of the substring specified
instr( carrname,'a' ) AS instr,
"String of length n starting from the left of an expression;
"trailing blanks are ignored
left( carrname, 4 ) AS left,
"Number of characters in an expression, trailing blanks are
"ignored
length( url ) AS length,
"Checks if expression contains a PCRE expression;
"case-sensitive by default (case_sensitive parameter can be
"specified)
"Notes on the result: 1 = found, 0 = not found
"PCRE below: Searches a period that is followed by any character
like_regexpr( pcre = '\..',
value = url ) AS like_regex,
"Returns position of a substring in an expression,
"3rd parameter = specifies offset (optional)
"4th parameter = determines the number of occurrences (optional)
locate( carrname, 'a', 0, 2 ) AS locate,
"Searches a PCRE pattern, returns offset of match;
"many optional parameters: occurrence, case_sensitive, start,
"group
locate_regexpr( pcre = '\..', "Period followed by any character
value = url,
occurrence = 2 ) "2nd occurrence in the string
AS locate_regexpr,
"Searches a PCRE pattern, returns offset of match + 1;
"many optional parameters: occurrence, case_sensitive, start,
"group
locate_regexpr_after( pcre = '.', "Any character
value = url,
occurrence = 1 ) AS locate_regexpr_after,
"Removes leading characters as specified in the 2nd argument,
"trailing blanks are removed
ltrim( carrname, 'L' ) AS ltrim,
"Counts all occurrences of found PCRE patterns
occurrences_regexpr( pcre = '\..',
value = url ) AS occ_regex,
"Replaces the 2nd argument with the 3rd in an expression
replace( carrname,'a','#' ) AS replace,
"Replaces a found PCRE expression;
"more parameters possible: occurrence, case_sensitive, start
replace_regexpr( pcre = '\..',
value = url,
with = '#' ) AS replace_regex,
"Extracts a string with the length specified starting from the
"right
right( carrname, 5 ) AS right,
"Expands string to length n (2nd argument); trailing blanks
"produced are replaced by the characters from the (3rd) argument
"Note that if n is less than the string, the expression is
"truncated on the right.
rpad( carrname, 12, '#' ) AS rpad,
"All trailing characters that match the character of the 2nd
"argument are removed; trailing blanks are removed, too
rtrim( carrname, 'a' ) AS rtrim,
"Returns a substring; 2nd argument = position from where to start;
"3rd argument: length of the extracted substring
substring( carrname, 3, 3 ) AS substring,
"Searches for a PCRE expression and returns the matched substring
"More parameters possible: occurrence, case_sensitive, start, group
substring_regexpr( pcre = '\...',
value = url ) AS substring_regexpr,
"All lower case letters are transformed to upper case letters
upper( carrname ) AS upper
FROM zdemo_abap_carr
WHERE carrid = 'LH'
INTO @DATA(string_functions).
out->write( data = string_functions name = `string_functions` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `18a) Special functions` ) ).
SELECT SINGLE
carrid,
"Conversion functions
"When used: Special conversions that cannot be handled in a
"general CAST expression
"Type conversion: string of fixed length (e.g. of type c) to
"variable length string of type string
to_clob( carrid ) AS clob,
"Byte string -> character string
bintohex( raw`3599421128650F4EE00008000978B976` ) AS bintohex,
"Character string -> byte string
hextobin( char`3599421128650F4EE00008000978B976` ) AS hextobin,
"Byte field of type RAW to a byte string (BLOB) of type RAWSTRING
to_blob( raw`3599421128650F4EE00008000978B976` ) AS blob,
"Unit conversion function
"More parameters are available.
"Converts miles to kilometers
unit_conversion( quantity = d34n`1`,
source_unit = unit`MI`,
target_unit = unit`KM` ) AS miles_to_km,
"Date and time functions
"There are plenty of functions; the below functions are a
"selection.
add_days( @( cl_abap_context_info=>get_system_date( ) ), 4
) AS add_days,
add_months( @( cl_abap_context_info=>get_system_date( ) ), 2
) AS add_months,
is_valid( @( cl_abap_context_info=>get_system_date( ) ) ) AS date_is_valid,
is_valid( @( cl_abap_context_info=>get_system_time( ) ) ) AS time_is_valid
FROM zdemo_abap_carr
WHERE carrid = 'AA'
INTO @DATA(special_functions).
"Retrieving type information using RTTI to demonstrate the effect
"of type conversions like to_clob etc.
"type_kind: g (character string with variable length),
"C (character string of fixed length), X (binary), y (byte string)
DATA(components) = CAST cl_abap_structdescr(
cl_abap_typedescr=>describe_by_data( special_functions )
)->components.
out->write( data = components name = `components` ).
out->write( |\n| ).
out->write( data = special_functions name = `special_functions` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `18b) coalesce Function` ) ).
"The null value is a special value that is returned by a database. It indicates an
"undefined value or result. Note that, in ABAP, there are no special null values. Do
"not confuse the null value with a type-dependent initial value. When using SELECT
"statements to read data, null values can be produced by, for example, outer joins.
"When the null values are passed to a data object, they are transformed to the
"type-dependent initial values. For more information, refer to the ABAP Keyword Documentation.
"The following example uses a left outer join to intentionally create null values. For
"this purpose, two demo database tables of the ABAP cheat sheet repository are cleared and
"populated with specific values to visualize null values.
DELETE FROM zdemo_abap_tab1.
DELETE FROM zdemo_abap_tab2.
MODIFY zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 1 char1 = 'a' char2 = 'y' )
( key_field = 2 char1 = 'b' char2 = 'z' ) ) ).
MODIFY zdemo_abap_tab2 FROM TABLE @( VALUE #( ( key_field = 1 char1 = 'a' )
( key_field = 2 char1 = 'a' )
( key_field = 3 char1 = 'b' )
( key_field = 4 ) ) ).
"Note that for the entry 'key_field = 4' no char1 value was passed.
"char1 is a shared column of the two database tables, and which is used in
"the ON condition of the join. Since there is no entry in char1 for 'key_field = 4',
"the joined values are null in that case.
"The coalesce function is used to replace null values produced by an outer join with
"a different value.
SELECT tab2~key_field,
coalesce( tab1~char1, '-' ) AS coalesced1,
coalesce( tab1~char2, '#' ) AS coalesced2,
"A coalesce function is a short form of a complex
"case distinction such as the following:
CASE WHEN tab1~char1 IS NOT NULL THEN tab1~char1
ELSE '?'
END AS coalesced3
FROM zdemo_abap_tab2 AS tab2
LEFT OUTER JOIN zdemo_abap_tab1 AS tab1 ON tab1~char1 = tab2~char1
INTO TABLE @DATA(join_w_null).
out->write( data = join_w_null name = `join_w_null` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `19) Aggregate Expressions` ) ).
"Consist of aggregate functions and aggregate the values of
"multiple rows of the result set of a query into a single value.
"The example shows a selection of available functions.
SELECT
carrid,
"Average value of the content of a column in a row set
AVG( fltime ) AS fltime1,
"AVG with data type specification for the result
AVG( fltime AS DEC( 14,4 ) ) AS fltime2,
"Maximum value of the results in a row set
MAX( fltime ) AS max,
"Minimum value
MIN( fltime ) AS min,
"Sum of the results in a row set.
SUM( fltime ) AS sum,
"Returns the number of rows in a row set.
"The following two have the same meaning.
COUNT( * ) AS count2,
COUNT(*) AS count3,
"Chains the results in a row set.
"An optional separator can be specified
STRING_AGG( airpfrom, ', ' ) AS string_agg
FROM zdemo_abap_flsch
WHERE carrid = 'LH'
GROUP BY carrid
INTO TABLE @DATA(agg_exp).
out->write( data = agg_exp name = `agg_exp` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `20a) Arithmetic Expressions` ) ).
SELECT SINGLE
carrid,
"Arithmethic expressions
"operators + - *
"Note that / is not allowed in integer expressions as the one below
( 1 + 2 ) * 3 AS calc,
"/ used in an expression using type adjustment in ABAP SQL.
"A cast expression converts the value of the operands to the
"specified dictionary type. The result is a representation of the
"source value in the specified type.
CAST( 1 AS D34N ) / CAST( 2 AS D34N ) AS ratio
FROM zdemo_abap_carr
WHERE carrid = 'AA'
INTO @DATA(arithmetic_sql_expr).
out->write( data = arithmetic_sql_expr name = `arithmetic_sql_expr` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `20b) Cast Expressions` ) ).
SELECT SINGLE
carrid,
"A cast expression converts the value of the operands to the
"specified dictionary type. The result is a representation of the
"source value in the specified type.
CAST( 1 AS D34N ) / CAST( 2 AS D34N ) AS ratio,
CAST( connid AS INT4 ) AS connidnum,
CAST( @( cl_abap_context_info=>get_system_date( ) ) AS CHAR ) AS dat
FROM zdemo_abap_fli
WHERE carrid = 'AA'
INTO @DATA(cast_expr).
out->write( data = cast_expr name = `cast_expr` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `20c) String Expressions` ) ).
SELECT SINGLE
carrid,
"String expression using && to concatenate two character strings;
"the result of the concatenation must not be longer than
"255 characters.
carrid && char`_` && carrname AS concat
FROM zdemo_abap_carr
WHERE carrid = 'AA'
INTO @DATA(string_expr).
out->write( data = string_expr name = `string_expr` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `20d) Case Expressions` ) ).
SELECT SINGLE
carrid,
"Simple case distinction
"The expression compares the values of an operand with other
"operands. Result: The first operand after THEN for which the
"comparison is true. If no matches are found, the result specified
"after ELSE is selected.
CASE currcode
WHEN 'EUR' THEN 'A'
WHEN 'USD' THEN 'B'
ELSE 'C'
END AS case_simple,
"Complex case distinction
"The expression evaluates logical expressions. Result: The first
"operand after THEN for which the logical expression is true. If no
"logical expressions are true, the result specified after ELSE is
"selected.
CASE WHEN length( carrname ) <= 5 THEN 'small'
WHEN length( carrname ) BETWEEN 6 AND 10 THEN 'mid'
WHEN length( carrname ) BETWEEN 11 AND 15 THEN 'large'
ELSE 'huge'
END AS case_complex
FROM zdemo_abap_carr
WHERE carrid = 'AA'
INTO @DATA(case_expr).
out->write( data = case_expr name = `case_expr` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `20e) Null Expressions` ) ).
SELECT
carrid,
carrname,
"The type of the null value is determined by the context.
"When the null value is passed to the internal table,
"it is converted to the initial value. In the first case,
"it is ' '. In the second case, it is 0..
CASE WHEN length( carrname ) > 12 THEN char`X`
ELSE NULL
END AS long_name,
CAST( NULL AS INT1 ) AS null_val
FROM zdemo_abap_carr
INTO TABLE @DATA(null_expr).
out->write( data = null_expr name = `null_expr` ).
**********************************************************************
out->write( zcl_demo_abap_aux=>heading( `21) Window expressions (1)` ) ).
"A simple window is constructed in the OVER clause,
"window functions - here aggregate functions - are applied.
"To narrow the entries in the resulting table, duplicates