0% found this document useful (0 votes)
5 views

WhoIsMrjQL - Copy (2)

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

WhoIsMrjQL - Copy (2)

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 72

Who

Is
Mr.jQL?
By V.Kazimirchik, last update: Thu, 22 Jun 2017 04:00 UTC

jQL is able to do much more than you think...


Contents

1 Preface 4

2 Basics 5
2.1 List records in a table . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 VOC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3 Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4 Record delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.5 Count number of records . . . . . . . . . . . . . . . . . . . . . . . . 10
2.6 List records that match a condition . . . . . . . . . . . . . . . . . . 10
2.7 Count records that match a condition . . . . . . . . . . . . . . . . . 11
2.8 Expand a condition ("or") . . . . . . . . . . . . . . . . . . . . . . . 11
2.9 Explicit "OR" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.10 Numeric / string comparison . . . . . . . . . . . . . . . . . . . . . . 12
2.11 Check if a field is populated in all records . . . . . . . . . . . . . 12
2.12 Sort the output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.13 Limit the output . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.14 Show several fields . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.15 Sort by several fields . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.16 If we don’t need the @ID in the output . . . . . . . . . . . . . . . . 14
2.17 Reverse sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.18 List several particular records . . . . . . . . . . . . . . . . . . . . 14
2.19 LIKE operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.20 EVAL usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.21 Totals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.22 Formatting the output . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.23 Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.24 Breaks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.25 SELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.26 Select lists saving and restoring . . . . . . . . . . . . . . . . . . . 28
2.27 Save something else than @ID . . . . . . . . . . . . . . . . . . . . . . 30
2.28 More EVAL usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.29 SELECT on SELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.30 Negative SELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.31 Reverse SELECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.32 Select concat files . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.33 More operation with saved SELECT lists . . . . . . . . . . . . . . . . 38
2.34 Copy records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.35 Delete records . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.36 "Dump" a record . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.37 Search for data in a table . . . . . . . . . . . . . . . . . . . . . . . 42
2.38 Brief statistics on file records . . . . . . . . . . . . . . . . . . . 43

3 Advanced usage 43
3.1 I-descriptors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
3.2 Address fields by numbers . . . . . . . . . . . . . . . . . . . . . . . 48
3.3 Default output for empty fields . . . . . . . . . . . . . . . . . . . . 49
3.4 Show records size . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.5 EVERY clause . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.6 Usage of standard jBC functions . . . . . . . . . . . . . . . . . . . . 52
3.7 Usage of custom jBC subroutines for EVAL . . . . . . . . . . . . . . . 56
3.8 Sort by EVAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

// Page 2
3.9 Multi-valued output change with BY-EXP . . . . . . . . . . . . . . . . 59
3.10 Paragraphs with jQL statements . . . . . . . . . . . . . . . . . . . . 60
3.11 EXPLAIN keyword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.12 Get information from another table . . . . . . . . . . . . . . . . . . 64
3.13 Use other dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.14 User exits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

4 Some more examples 67


4.1 See if there’s a discrepancy between F.TSA.STATUS and running tSA agents 67
4.2 See the time of STMT.ENTRY records creation up to a second . . . . . 67
4.3 See how many fields are populated in a table . . . . . . . . . . . . . 67
4.4 How to display only the last value of a field . . . . . . . . . . . . 68
4.5 See on which work day an FT was created (based on its @ID) . . . . . 68
4.6 Get account balance history . . . . . . . . . . . . . . . . . . . . . . 69
4.7 See the longest batches in the last COB: . . . . . . . . . . . . . . . 70
4.8 See active T24 users . . . . . . . . . . . . . . . . . . . . . . . . . . 70
4.9 See all active sessions in detail . . . . . . . . . . . . . . . . . . . 71

// Page 3
1 Preface

jQL is (a bit) SQL-like query language that is used in jBASE / TAFC to list, se-
lect and count data in tables (read: files).
Unfortunately jQL doesn’t have line continuation capability so to provide copy-
pasting of long examples from this book it’s advised to create a small jBC pro-
gram that will accept the manual input (or pasted several lines of output) and ac-
cumulate the query text until the empty line is entered:

* jql.b

the_req = ''
LOOP
PROMPT '>> '
INPUT chunk
chunk = TRIM(chunk, ' ', 'B')
IF chunk EQ '' THEN BREAK
IF chunk[1,2] EQ '//' THEN CONTINUE ;* page breaks in this book ;
the_req := ' ' : chunk
REPEAT

IF the_req EQ '' THEN STOP


CHAIN the_req

Example:
 
jsh modelbank ~ --> jql
>> LIST F.SPF
>> RUN.DATE SITE.NAME
>>
 

@ID... RUN.DATE... SITE.NAME..........................

SYSTEM 20150420 Model Bank R15-AMR

1 Records Listed

As you might have noticed, this example is from T24 Model Bank (as

well as all others).

The user input will be shown as:


 
Command
 
Results will be shown as:
Results

// Page 4
2 Basics

2.1 List records in a table

Full list:
 
LIST F.USER
 

@ID................. PAYSUSER3
USER.ID............. PAYSUSER3
USER.NAME........... PAY USER
SIGN.ON.NAME........ PAYUSER3
END.TIME............ 2400
...
RECORD.STATUS.......
CURR.NO............. 1
INPUTTER............ 44958_INPUTTER__OFS_SEAT
DATE.TIME........... 1504241622
AUTHORISER.......... 44958_INPUTTER_OFS_SEAT
CO.CODE............. GB0010001
DEPT.CODE........... 1
AUDITOR.CODE........
AUDIT.DATE.TIME.....
SALT................
ROLE.COMPANY.RESTR..
USER.ROLES..........
OFFLINE.SMS.ROLE....
TXN.COMMIT.LOG......

@ID................. BUILDUSER98
@ID................. BUILDUSER98
USER.ID............. BUILDUSER98
USER.NAME........... BUILDUSER 98
SIGN.ON.NAME........ TELLER98
CLASSIFICATION...... INT
...

The output is long, press Q to stop it. Pause on each screen can be overridden
with "(N":
 
LIST F.USER (N
 

...
...
ROLE.COMPANY.RESTR..
USER.ROLES..........
OFFLINE.SMS.ROLE....
TXN.COMMIT.LOG......

127 Records Listed

// Page 5
List particular record:
 
LIST F.USER 'INPUTTER'
 
@ID................. INPUTTER
@ID................. INPUTTER
USER.ID............. INPUTTER
USER.NAME........... INPUTTER
SIGN.ON.NAME........ INPUTT
CLASSIFICATION...... INT
...

List particular field:


 
LIST F.USER INPUTTER
 
@ID............. INPUTTER................................

PAYSUSER3 44958_INPUTTER__OFS_SEAT
BUILDUSER98 21692_OFFICER__OFS_SEAT
BUILDUSER40 13788_OFFICER__OFS_SEAT
BUILDUSER8200 80099_OFFICER__OFS_SEAT
BUILDUSER34 19108_OFFICER__OFS_SEAT
...

In the latter case INPUTTER is field name rather than @ID so both

queries work for F.USER where INPUTTER record presents.

Try the same on another table to see the difference:


 
LIST F.SPF INPUTTER
 
@ID... INPUTTER................................

SYSTEM 13526_INPUTTER

 
LIST F.SPF 'INPUTTER'
 
** Error [ 202 ] **
Record 'INPUTTER' is not on file.

No Records Listed

2.2 VOC

Where is F.SPF located after all? It’s not in bnk.run... Instead there’s a jBASE
file called VOC where pointers to files are recorded (among other stuff).

// Page 6
Let’s see what’s inside:
 
LIST VOC
 
NAME.............................................. TYPE

F.DX.REVAL.DET.ENHANCED F
F.GENERATE.ENTRY.WRK F
F.RUN.GRP.PERF.TAKEON F
F.SA.RATIOS F
F.SC.CCY.RANK F
...

File location is in the field #2:


 
LIST VOC 'F.SPF' *A2
 
VOC......... *A2...........

F.SPF ..\bnk.data\eb
\F_SPF

"*A2" means "field #2". Actually jQL doesn’t use a dictionary here

- just returns the Nth field of a record.

We can force jQL to work hard using some big field number; "time" will show us the
speed of execution:
 
time LIST VOC 'F.SPF' *A999999999
 
VOC......... *A999999999...

F.SPF

1 Records Listed

usr: 42.52 sys: 0.00 elapsed: 0m42.53s

We can also address the file by full path:


 
LIST ..\bnk.data\eb\F_SPF
 
DICT ..\bnk.data\eb\F_SPF

SYSTEM

1 Records Listed

In this example we don’t see fields, just an @ID. Why? See the next chapter.

// Page 7
2.3 Dictionary

How jQL knows there’s a field called INPUTTER? Every (or nearly every) table has
a dictionary (that is also a file). Its location is indicated in VOC entry (field
#3):
 
CT VOC F.SPF
 

F.SPF

001 F
002 ..\bnk.data\eb\F_SPF
003 ..\bnk.dict\F_SPF]D

CT command outputs raw contents of a record with field numbers on

the left (another similar one is LIST-ITEM). CT doesn’t require quotes

in @ID while LIST-ITEM and LIST do.

"Pure" jBASE doesn’t create VOC entries for data files; when the file

is created its dictionary resides in the same directory; files are

searched not through VOC entry but with the usage of environment vari-

able JEDIFILEPATH.

Instead of listing ..\bnk.dict\F_SPF]D, we can use DICT keyword to see INPUTTER


field information:
 
CT DICT F.SPF INPUTTER
 

INPUTTER
001 D
002 93
003
004 INPUTTER
005 40L
006 M
007
008
...

What we can see here is that this is multi-valued ("M" in field #6) data field ("D"
in field #1), 93 is field position; it is to be displayed as left-justified 40 char-
acters.

// Page 8
Dictionary for T24 applications are created automatically from con-

tents of STANDARD.SELECTION (SS) record (so it makes no sense to cre-

ate your own dictionary entries in the dictionary itself; for this

purpose user fields of SS should be used).

SS record for SPF (fragment):


Model Bank R15-AMR STANDARD SELECTION FIELDS INPUT

FILE.NAME......... SPF
-----------------------------------------------------------------------------
1.84 SYS.FIELD.NAME. INPUTTER
2.84 SYS.TYPE....... D
3.84. 1 SYS.FIELD.NO 93
4.84. 1 SYS.VAL.PROG IN2A
5.84 SYS.CONVERSION.
6.84 SYS.DISPLAY.FMT 40L
7.84 SYS.ALT.INDEX.. N
8.84. 1 SYS.IDX.FILE
9.84 SYS.INDEX.NULLS
10.84 SYS.SINGLE.MULT M
11.84 SYS.LANG.FIELD. N
12.84 SYS.GENERATED.. Y
13.84. 1 SYS.CNV.TYPE
14.84. 1 SYS.REL.FILE
-----------------------------------------------------------------------------
06 DEC 2016 21:50:21 USER (22 APR) VKAZIMIRCHIK [22410,IPAGE 73 >>91>>>
ACTION
AWAITING PAGE INSTRUCTIONS

2.4 Record delimiters

Records in jBASE files are strings delimited with 3 types of delimiters:


• @FM: field mark (ASCII 254).
• @VM: value mark (ASCII 253).
• @SM: sub-value mark (ASCII 252).

So we can also see the third field of VOC entry using:


 
LIST VOC 'F.SPF' EVAL "FIELD(@RECORD,@FM,3)"
 

VOC......... FIELD(@RECORD,@FM,3)

F.SPF ..\bnk.dict\F_SPF]D

// Page 9
EVAL keyword can be used for constructing the output on-the-fly. Many

(but not all) jBC functions can be used there.

@FM can be also addressed as @AM; there is also @TM - text mark (ASCII

251) - but normally it doesn’t appear in a record. @RECORD contains

the full record, @ID can also be used in a query.

2.5 Count number of records


 
COUNT FBNK.ACCOUNT
 

1637 Records counted

 
COUNT FBNK.CUSTOMER
 

451 Records counted

2.6 List records that match a condition


 
LIST FBNK.ACCOUNT WITH ACCOUNT.OFFICER EQ '55'
 
The output is too long, so list @IDs only:
 
LIST FBNK.ACCOUNT WITH ACCOUNT.OFFICER EQ '55' ONLY
 

@ID................

76902
74764
75965
...
74737
65765
USD156000001
74799
75957
USD1415600010001
74721
USD156010001

25 Records Listed

// Page 10
When a multi-valued field content is queried, the result will contain records in
which at least one value matches the request:
 
LIST FBNK.ACCOUNT WITH ALT.ACCT.ID EQ 'GB65463' ALT.ACCT.ID FMT '25L'
 

@ID................ ALT.ACCT.ID..............

65463 GB65463
GB16NWBK60161300065463

2.7 Count records that match a condition


 
COUNT FBNK.ACCOUNT WITH ACCOUNT.OFFICER EQ '55'
 

25 Records counted

2.8 Expand a condition ("or")


 
COUNT FBNK.ACCOUNT WITH ACCOUNT.OFFICER EQ '55' '14'
 

137 Records counted

"IN" keyword can also be used:


 
LIST F.TSA.SERVICE USER WITH USER IN 'SEAT.USER' 'AUTHORISER'
 

@ID............................................... K.USER...................

SG1/AM.BACKVALUE.SERVICE AUTHORISER
BNK/EB.CREATE.FILE.UPLOAD SEAT.USER
EU1/AM.BACKVALUE.SERVICE AUTHORISER
MF1/AM.BACKVALUE.SERVICE AUTHORISER
BNK/DW.BULK.PROCESSING AUTHORISER
BNK/DW.EXTRACT AUTHORISER
BNK/T24.UPLOAD.PROCESS SEAT.USER
EU1/OL.VAL.REPS AUTHORISER
SG1/OL.VAL.REPS AUTHORISER
MF1/OL.VAL.REPS AUTHORISER

10 Records Listed

// Page 11
2.9 Explicit "OR"

The query above can be more formal:


 
COUNT FBNK.ACCOUNT WITH ACCOUNT.OFFICER EQ '55' OR ACCOUNT.OFFICER EQ '14'
 
137 Records counted

This form has to be used if we check different fields:


 
COUNT FBNK.ACCOUNT WITH ACCOUNT.OFFICER EQ '55' OR OTHER.OFFICER EQ '55'
 
25 Records counted

2.10 Numeric / string comparison

Do we need to put ’55’ into quotes? It’s not mandatory for numeric constants:
 
COUNT FBNK.ACCOUNT WITH ACCOUNT.OFFICER EQ 55 OR OTHER.OFFICER EQ 55
 
25 Records counted

2.11 Check if a field is populated in all records


 
COUNT FBNK.ACCOUNT WITH ACCOUNT.OFFICER EQ ''
 
No Records counted

Same effect using: COUNT FBNK.ACCOUNT WITHOUT ACCOUNT.OFFICER

2.12 Sort the output


 
LIST FBNK.ACCOUNT WITH ACCOUNT.OFFICER EQ '55' ONLY BY @ID
 
@ID................

65757
65765
74721
74737
74764
...

// Page 12
2.13 Limit the output
 
LIST FBNK.ACCOUNT WITH ACCOUNT.OFFICER EQ '55' ONLY SAMPLE 5
 

@ID................

76902
74764
75965
74818
76732

5 Records Listed

Sort won’t work correctly with "SAMPLE" clause.

If we use SAMPLE with BY / BY.DSND - jQL firstly will take n sam-

ples and secondly will sort them so it’s not the same as "TOP n" in

MS SQL.

2.14 Show several fields


 
LIST FBNK.ACCOUNT WITH CUSTOMER NE '' CUSTOMER CURRENCY
 

@ID................ CUSTOMER.. CURRENCY

76902 100182 USD


75067 190057 GBP
14095 100394 GBP
14087 100394 EUR
75938 100283 GBP
....

2.15 Sort by several fields

Ascending / descending attribute can be different for different fields

used in the sorting.

 
LIST FBNK.ACCOUNT WITH CUSTOMER NE '' CUSTOMER CURRENCY BY CUSTOMER
BY CURRENCY
 

// Page 13
@ID................ CUSTOMER.. CURRENCY

75132 66052 EUR


75183 66052 GBP
75213 66052 SGD
75043 66052 USD
77844 100100 GBP
78158 100100 GBP
74958 100100 USD
....

2.16 If we don’t need the @ID in the output


 
LIST FBNK.ACCOUNT WITH CUSTOMER NE '' CUSTOMER CURRENCY BY CUSTOMER
BY CURRENCY ID.SUPP
 
CUSTOMER.. CURRENCY

66052 EUR
66052 GBP
66052 SGD
66052 USD
100100 GBP
100100 GBP
100100 USD
....

2.17 Reverse sort


 
LIST FBNK.ACCOUNT WITH CUSTOMER NE '' CUSTOMER CURRENCY BY CUSTOMER
BY.DSND CURRENCY
 
@ID................ CUSTOMER.. CURRENCY

75043 66052 USD


75213 66052 SGD
75183 66052 GBP
75132 66052 EUR
74958 100100 USD
75302 100100 USD
....

2.18 List several particular records


 
LIST F.ABBREVIATION 'AC' 'FT' 'DC'
 

// Page 14
@ID............... AC
@ID............... AC
ABBREVIATION.CODE. AC
ORIGINAL.TEXT..... ACCOUNT
RECORD.STATUS.....
CURR.NO........... 2
INPUTTER.......... 1_201312m
DATE.TIME......... 1504211226
AUTHORISER........ 58929_INPUTTER_OFS_MB.OFS.AUTH
CO.CODE........... GB0010001
DEPT.CODE......... 1
AUDITOR.CODE......
AUDIT.DATE.TIME...

@ID............... FT
@ID............... FT
ABBREVIATION.CODE. FT
ORIGINAL.TEXT..... FUNDS.TRANSFER
RECORD.STATUS.....
CURR.NO........... 1
INPUTTER.......... 1_R14m
DATE.TIME......... 1504211226
AUTHORISER........ 58929_INPUTTER_OFS_MB.OFS.AUTH
CO.CODE........... GB0010001
DEPT.CODE......... 1
AUDITOR.CODE......
AUDIT.DATE.TIME...

@ID............... DC
@ID............... DC
ABBREVIATION.CODE. DC
ORIGINAL.TEXT..... DATA.CAPTURE
RECORD.STATUS.....
CURR.NO........... 1
INPUTTER.......... 78833_OFFICER__OFS_SEAT
DATE.TIME......... 1504241610
AUTHORISER........ 78833_OFFICER_OFS_SEAT
CO.CODE........... GB0010001
DEPT.CODE......... 1
AUDITOR.CODE......
AUDIT.DATE.TIME...

We have something called "ABBREVIATION.CODE" that looks like a rep-

etition of the @ID. Also, why @ID is listed twice? The answers are

in the dictionary.

// Page 15
 
CT DICT F.ABBREVIATION ABBREVIATION.CODE
 

ABBREVIATION.CODE
001 D
002 0
003
004 ABBREVIATION.CODE
005 35L
006 S

Data field 0 is the @ID. We can use its name instead of @ID if we like. There’s
also a special record "@" in the dictionary that contains field names that are to
be output in the LIST command by default:
 
CT DICT F.ABBREVIATION @
 

@
001 PH
002 @ID ABBREVIATION.CODE ORIGINAL.TEXT RECORD.STATUS CURR.NO
INPUTTER DATE.TIME AUTHORISER CO.CODE DEPT.CODE AUDITOR.CODE
AUDIT.DATE.TIME

@ID is mentioned in this record so it’s repeated one more time (it wouldn’t be if
we use ID.SUPP).
For some applications "@" record isn’t properly populated in Model Bank. For ex-
ample:
 
CT DICT FBNK.FUNDS.TRANSFER @
 

@
001 PH
002 FT1

So:
 
LIST FBNK.FUNDS.TRANSFER
 

@ID...................... FT1.

FT15112TRNLJ ACIB
FT15112DKF1D OC
FT15112DV9G8 AC
FT15112WVXLX AC
....

// Page 16
2.19 LIKE operator

LIKE (synonym MATCHES) can be used to match a string to a pattern.

List all accounts whose category starts with "1":


 
LIST FBNK.ACCOUNT CATEGORY WITH CATEGORY LIKE "'1'..."
 
@ID................ CATEGORY

76902 1001
75067 1001
14095 1001
GBP1720507450001 17205
14087 1001
USD140300001 14030
USD1590599990001 15905
....

Same output can be obtained using:


 
LIST FBNK.ACCOUNT CATEGORY WITH CATEGORY EQ "1]"
 
Here we’ll see categories that contain the digit "1":
 
LIST FBNK.ACCOUNT CATEGORY WITH CATEGORY EQ "[1]"
 
Or:
 
LIST FBNK.ACCOUNT CATEGORY WITH CATEGORY LIKE "...'1'..."
 
And here we’ll see categories that start and end with "1". This way...
 
LIST FBNK.ACCOUNT CATEGORY WITH CATEGORY LIKE "'1'...'1'"
 
...or this:
 
LIST FBNK.ACCOUNT CATEGORY WITH CATEGORY LIKE "'1'0X'1'"
 
The output is the same in both cases:
@ID................ CATEGORY

76902 1001
75067 1001
14095 1001
...
78174 1001
77186 1001
EUR144210001 14421
GBP1001199990001 10011
...

// Page 17
0X means "any number of any characters". Knowing that category number is always
numeric, we can rephrase this query to check only for numeric characters:
 
LIST FBNK.ACCOUNT CATEGORY WITH CATEGORY LIKE "'1'0N'1'"
 
And here we’ll output categories that start and end with "1" and have length of
@ID = 5:
 
LIST FBNK.ACCOUNT CATEGORY WITH CATEGORY LIKE "'1'3N'1'"
 
@ID................ CATEGORY

EUR144210001 14421
GBP1001199990001 10011
USD1404100010001 14041
EUR1444100010001 14441
USD144610001 14461
USD143010001 14301
USD143110001 14311
USD1122100010001 11221
GBP1000199990001 10001
GBP1444100010001 14441
...

List internal accounts (starting with 3 alpha characters followed by any number
of digits):
 
LIST FBNK.ACCOUNT ONLY WITH @ID LIKE "3A0N"
 
@ID................

GBP1720507450001
USD140300001
USD1590599990001
USD1405506800001
EUR150050001
GBP1430600790001
...

Now limit the number of digits to 9:


 
LIST FBNK.ACCOUNT ONLY WITH @ID LIKE "3A9N"
 
@ID................

USD140300001
EUR150050001
EUR144210001
USD141950001
USD149550001
USD150200001
USD190050001
....

// Page 18
Now show only those that start with 3 alpha characters and contain "04" sequence:
 
LIST FBNK.ACCOUNT ONLY WITH @ID LIKE "3A...'04'..." BY @ID
 

@ID................

CHF1404400010001
CHF1418504500001
CHF1430400060001
CHF1430400110001
CHF1430400790001
EUR1404400010001
EUR1418504120001
EUR1430400060001
EUR1430400110001
...

To use several matches we’ll have to use "OR". Only if that’s an exact match we
can use a @VM-delimited dynamic array of values to match to:
 
LIST FBNK.ACCOUNT CATEGORY WITH CATEGORY MATCHES "1001" : @VM : "6001"
 

@ID................ CATEGORY

76902 1001
75067 1001
14095 1001
14087 1001
75938 6001
77763 6001
77933 1001
....

Not only we have "LIKE" - we have "UNLIKE" too (now we know where social networks
get their ideas :)
 
LIST FBNK.ACCOUNT ONLY WITH @ID UNLIKE "3A..."
 

@ID................

76902
75067
14095
14087
75938
77763
77933
77957
79103
81237
76748
...

// Page 19
If strings like "3A" etc are searched in the data, they have to be enclosed in quotes:
 
LIST FBNK.CUSTOMER WITH TOWN.COUNTRY LIKE "...EC3N..."
 

No Records Listed

 
LIST FBNK.CUSTOMER WITH TOWN.COUNTRY LIKE "...'EC3N'..."
 

@ID.......................... 100279
CUSTOMER.CODE................ 100279
MNEMONIC..................... CANTERFITZ
SHORT.NAME................... Canterfitzgerald
NAME.1....................... Canterfitzgerald
NAME.2.......................
STREET....................... 1 AMERICA SQUARE
TOWN.COUNTRY................. LONDON EC3N 2LT
...

It’s highly recommended to enclose matched expression in double quotes and lit-
eral strings in it in single quotes, otherwise there might be syntax errors:
 
LIST FBNK.CUSTOMER SHORT.NAME WITH SHORT.NAME LIKE T...
 

@ID....... SHORT.NAME.........................

101013 Temenos Equity Fund


100252 Tradition (Uk) Ltd
190130 TOM SHAW
190022 Thomas
...

 
LIST FBNK.CUSTOMER WITH SHORT.NAME LIKE T...(Uk)...
 

Error in Statement "LIST FBNK.CUSTOMER SHORT.NAME WITH SHORT.NAME


LIKE T...(Uk)..."
Dictionary record ... is missing.

 
LIST FBNK.CUSTOMER SHORT.NAME WITH SHORT.NAME LIKE "T...'(Uk)'..."
 

@ID....... SHORT.NAME.........................

100252 Tradition (Uk) Ltd


190045 T-mobile (Uk) Ltd

// Page 20
2.20 EVAL usage

We can use expressions that are evaluated at run-time. Basic func-

tions and expressions can be used there.

Format the output. Firstly let’s get unformatted numbers:


 
LIST FBNK.ACCOUNT WITH WORKING.BALANCE WORKING.BALANCE
 
@ID................ WORKING.BALANCE....

GBP1720507450001 19.7
14087 -530000
75938 5100
USD1405506800001 -0.01
77957 -10000
GBP1430600790001 0
....

Note that the account GBP1430600790001 was included but its balance is 0.
Correct solution to this issue is something like:
 
LIST FBNK.ACCOUNT WITH WORKING.BALANCE NE '' AND WORKING.BALANCE NE '0'
WORKING.BALANCE
 
Hope we don’t get 0.00’s as well :)) Not in the first screen at least:
@ID................ WORKING.BALANCE....

GBP1720507450001 19.7
14087 -530000
75938 5100
USD1405506800001 -0.01
77957 -10000
79103 -500
USD1405503490001 -0.01
81237 14900
76748 203500
GBP1280000060001 -794261.24
...

We could also use EVAL: ...WITH EVAL "WORKING.BALANCE*1" NE 0

Let’s format the balance to have 2 digits after dot:


 
LIST FBNK.ACCOUNT WITH WORKING.BALANCE NE '' AND WORKING.BALANCE NE '0'
EVAL "FMT(WORKING.BALANCE,'R2')"
 

// Page 21
@ID................ FMT(WORKING.BALANCE,"R2")

GBP1720507450001 19.70
14087 -530000.00
75938 5100.00
USD1405506800001 -0.01
77957 -10000.00
79103 -500.00
USD1405503490001 -0.01
....

If you don’t like the second column header, amend it:


 
LIST FBNK.ACCOUNT WITH WORKING.BALANCE NE '' AND WORKING.BALANCE NE '0'
EVAL "FMT(WORKING.BALANCE,'R2')" COL.HDR 'Balance'
 

@ID................ Balance............

GBP1720507450001 19.70
14087 -530000.00
75938 5100.00
USD1405506800001 -0.01
77957 -10000.00
79103 -500.00
USD1405503490001 -0.01
....

Now put a dollar sign before amounts (and limit selection only to diplay USD ac-
counts):
 
LIST FBNK.ACCOUNT WITH WORKING.BALANCE NE '' AND WORKING.BALANCE NE '0'
AND CURRENCY EQ 'USD' EVAL "FMT(WORKING.BALANCE,'R2$')" COL.HDR 'Balance'
 

@ID................ Balance............

USD1405506800001 $-0.01
77957 $-10000.00
79103 $-500.00
USD1405503490001 $-0.01
81237 $14900.00
82147 $500.00
76147 $12970.83
74098 $-350000.00
...

Group thousands with comma:


 
LIST FBNK.ACCOUNT WITH WORKING.BALANCE NE '' AND WORKING.BALANCE NE '0'
AND CURRENCY EQ 'USD' EVAL "FMT(WORKING.BALANCE,'R2,$')" COL.HDR 'Balance'
 

// Page 22
@ID................ Balance............

USD1405506800001 $-0.01
77957 $-10,000.00
79103 $-500.00
USD1405503490001 $-0.01
81237 $14,900.00
82147 $500.00
76147 $12,970.83
74098 $-350,000.00
USD1280001010001 $250,000.00
...

Trying to put "DB" after negative amounts but it looks like it works other way around
in this release:
 
LIST FBNK.ACCOUNT WITH WORKING.BALANCE NE '' AND WORKING.BALANCE NE '0'
AND CURRENCY EQ 'USD' EVAL "FMT(WORKING.BALANCE,'R2,D$')" COL.HDR 'Balance'
 

@ID................ Balance............

USD1405506800001 $0.01
77957 $10,000.00
79103 $500.00
USD1405503490001 $0.01
81237 $14,900.00DB
82147 $500.00DB
76147 $12,970.83DB
74098 $350,000.00
USD1280001010001 $250,000.00DB
...

If we still want it working, here we are:


 
LIST FBNK.ACCOUNT WITH WORKING.BALANCE NE '' AND WORKING.BALANCE NE '0'
AND CURRENCY EQ 'USD' EVAL "FMT(WORKING.BALANCE*-1,'R2,D$')"
COL.HDR 'Balance'
 

@ID................ Balance............

USD1405506800001 $0.01DB
77957 $10,000.00DB
79103 $500.00DB
USD1405503490001 $0.01DB
81237 $14,900.00
82147 $500.00
76147 $12,970.83
74098 $350,000.00DB
USD1280001010001 $250,000.00
...

// Page 23
Changing "D" before a dollar to "C", we’ll get "CR" output after positive amounts,
again we need to multiply the amount by -1 to get the correct output:
 
LIST FBNK.ACCOUNT WITH WORKING.BALANCE NE '' AND WORKING.BALANCE NE '0'
AND CURRENCY EQ 'USD' EVAL "FMT(WORKING.BALANCE*-1,'R2,C$')"
COL.HDR 'Balance'
 

@ID................ Balance............

USD1405506800001 $0.01
77957 $10,000.00
79103 $500.00
USD1405503490001 $0.01
81237 $14,900.00CR
82147 $500.00CR
76147 $12,970.83CR
74098 $350,000.00
USD1280001010001 $250,000.00CR
...

2.21 Totals
 
LIST FBNK.ACCOUNT WITH CURRENCY EQ 'EUR' AND WORKING.BALANCE NE ''
AND WORKING.BALANCE NE '0' TOTAL WORKING.BALANCE
 

@ID................ WORKING.BALANCE....

14087 -530000
76748 203500
15307 -525000
EUR1720500190001 0.46
EUR1721000010001 3830.86
....
EUR1418507190001 -168517.87
36668 -36087268.95
14637 789071.88
11312 -40374.75
===================
*** 25536691.95

Use "(N" option not to wait on page breaks:


 
LIST FBNK.ACCOUNT WITH CURRENCY EQ 'EUR' AND WORKING.BALANCE NE ''
AND WORKING.BALANCE NE '0' TOTAL WORKING.BALANCE (N
 
If you want the totals only, suppress the details (DET-SUPP):
 
LIST FBNK.ACCOUNT WITH CURRENCY EQ 'EUR' AND WORKING.BALANCE NE ''
AND WORKING.BALANCE NE '0' TOTAL WORKING.BALANCE DET-SUPP
 

// Page 24
@ID................ WORKING.BALANCE....

*** 25536691.95

81 Records Listed

Another example:
 
LIST F.USER TOTAL ATTEMPTS.SINCE DET-SUPP
 

@ID............. ATTEMPTS.SINCE

*** 19

Average value of a field:


 
LIST F.USER AVERAGE ATTEMPTS.SINCE COL.HDR "Average failed login attempts"
DET-SUPP
 

@ID............. Average failed login attempts

*** 0.1496

2.22 Formatting the output

Customize page header (HEADING):


 
LIST FBNK.ACCOUNT WITH CURRENCY EQ 'EUR' AND WORKING.BALANCE NE ''
AND WORKING.BALANCE NE '0' TOTAL WORKING.BALANCE HEADING "Page 'P3'"
 

Page 1
@ID................ WORKING.BALANCE....

14087 -530000
76748 203500
15307 -525000
EUR1720500190001 0.46
EUR1721000010001 3830.86
...
Page 2
@ID................ WORKING.BALANCE....

74397 -100000
75256 6000000
76678 10000
...

// Page 25
Formatting the column width. Try 1:
 
LIST VOC TYPE SAMPLE 5
 

VOC......... TYPE

F.DX.REVAL.D F
ET.ENHANCED
F.GENERATE.E F
NTRY.WRK
F.GT.SYSTEM. F
PARAMETER$NA
U
F.RUN.GRP.PE F
RF.TAKEON
F.SA.RATIOS F

Correct (FMT):
 
LIST VOC @ID FMT "35L" TYPE SAMPLE 5 ID-SUPP
 

VOC................................ TYPE

F.DX.REVAL.DET.ENHANCED F
F.GENERATE.ENTRY.WRK F
F.GT.SYSTEM.PARAMETER$NAU F
F.RUN.GRP.PERF.TAKEON F
F.SA.RATIOS F

List company @IDs like they are shown in T24:


 
LIST F.COMPANY ID.SUPP @ID FMT "##-###-####" COL.HDR 'Company id'
 

Company id

GB-001-0003
GB-001-0005
SG-001-0001
SG-002-0102
EU-001-0001
SG-002-0101
GB-001-0002
GB-001-0004
SG-002-0100
GB-001-0001

// Page 26
2.23 Aliases

"AS" keyword can be used to save typing.

 
LIST FBNK.ACCOUNT WITH CUSTOMER NE '' EVAL "CUSTOMER:'/':CURRENCY" AS SORTING
BY SORTING
 

@ID................ SORTING...

75132 66052/EUR
75183 66052/GBP
75213 66052/SGD
75043 66052/USD
77844 100100/GBP
78158 100100/GBP
74958 100100/USD
75302 100100/USD
...

2.24 Breaks
 
LIST FBNK.ACCOUNT BY ACCOUNT.OFFICER BREAK.ON ACCOUNT.OFFICER
 

@ID................ ACCOUNT.OFFICER

CAD1091500010001 1
CAD1591500010001 1
CADUSD1401600010001 1
...
USDSGD1401600010001 1
USDXAU1902200010001 1
XAUUSD1902200010001 1

***

75914 2
80756 2
80764 2
80772 2
80799 2

***

29823 3
74567 3
74586 3
...

// Page 27
Use break to calculate totals:
 
LIST FBNK.ACCOUNT WITH CURRENCY EQ USD TOTAL WORKING.BALANCE BY OPENING.DATE
BREAK.ON EVAL "OPENING.DATE[1,4]" COL.HDR 'Open year' DET-SUPP
 

@ID................ WORKING.BALANCE.... Open year..

5000 1998
0 2007
0 2008
0 2010
0 2013
0 2014
86068541.84 2015
===================
*** 86073541.84

2.25 SELECT

Change LIST clause to SELECT, in most cases that will work. Simple one:
 
SELECT FBNK.ACCOUNT WITH CURRENCY EQ 'EUR' AND WORKING.BALANCE NE ''
 

128 Records selected

>

We don’t have any output like in SQL. Note that prompt has changed - we have an
active SELECT list. We can now enter another jQL command that will be applied to
selected IDs only (or whatever was saved to this list).
To clear the current select list the command CLEARSELECT can be used.
Sort is done the same way as in LIST (SSELECT sorts by @ID so the following 2 queries
will produce the same result):
 
SELECT FBNK.ACCOUNT WITH CURRENCY EQ 'EUR' AND WORKING.BALANCE NE '' BY @ID
 
 
SSELECT FBNK.ACCOUNT WITH CURRENCY EQ 'EUR' AND WORKING.BALANCE NE ''
 

2.26 Select lists saving and restoring

Select lists can be saved to and retrieved from the directory on T24 application
server (bnk.run/&SAVEDLISTS& by default).
 
SELECT FBNK.ACCOUNT WITH CURRENCY EQ 'EUR' AND WORKING.BALANCE NE ''
 

128 Records selected

// Page 28
 
>SAVE.LIST ACCT
 

128 record(s) saved to list 'ACCT'

 
GET.LIST ACCT
 

128 Records selected

 
LIST FBNK.ACCOUNT WORKING.BALANCE SAMPLE 5
 

@ID................ WORKING.BALANCE....

14087 -530000
76748 203500
15307 -525000
EUR1720500190001 0.46
EUR1721000010001 3830.86

5 Records Listed

After the second command the prompt returns back to normal since we don’t have the
active SELECT list now.
Numbered lists can also be used, numbers can be from 0 to 9:
 
SELECT FBNK.ACCOUNT TO 1
 

1637 Records selected

Note that the prompt hasn’t changed - default SELECT list (0) isn’t populated.
 
SELECT FBNK.CUSTOMER TO 2
 

451 Records selected

 
GET.LIST 1
 

1637 Records selected

>

Numbered SELECT lists are not persistent and are available only till

the end of a current session.

// Page 29
Relogin, try again:
 
GET.LIST 1
 

1 is not a list name

2.27 Save something else than @ID


 
SELECT FBNK.ACCOUNT WITH CUSTOMER NE '' AND WORKING.BALANCE NE ''
AND WORKING.BALANCE NE '0' SAVING CUSTOMER
 

687 Records selected

 
>SAVE.LIST CUST
 

687 record(s) saved to list 'CUST'

See the results:


 
CT &SAVEDLISTS& CUST
 

CUST
001 100394
002 100283
003 100315
004 100100
005 190049
006 189992
007 100392
....

Sort this list:


 
SORT-LIST CUST
 

List 'CUST' sorted with 687 records

See results again:


 
001 10000083
002 10000083
003 10000083
004 10000083
005 10000083
006 100100
007 100100
 

// Page 30
Note that it’s a text-like sort rather than numeric.

Remove duplicates (via sort option):


 
SORT-LIST CUST (U
 

List 'CUST' sorted with 198 records

We could remove duplicates in the initial command (UNIQUE keyword):


 
SELECT FBNK.ACCOUNT WITH CUSTOMER NE '' AND WORKING.BALANCE NE ''
AND WORKING.BALANCE NE '0' SAVING UNIQUE CUSTOMER
 

198 Records selected

 
>CLEARSELECT
 

[528] List '0' cleared.

2.28 More EVAL usage

Concatenation:
 
SELECT FBNK.ACCOUNT WITH CUSTOMER NE '' AND WORKING.BALANCE NE ''
AND WORKING.BALANCE NE '0' SAVING UNIQUE EVAL "CUSTOMER:'*':CURRENCY"
 

299 Records selected

 
>SAVE.LIST CUST2
 

299 record(s) saved to list 'CUST2'

 
SORT-LIST CUST2
 

List 'CUST2' sorted with 299 records

Resulting list:
CUST2
001 10000083*USD
002 100100*GBP
003 100100*USD
004 100105*USD
005 100106*USD
006 100107*USD
...

// Page 31
Formatting:
 
LIST F.SPF EVAL "OCONV(ICONV(MAINTENANCE.DATE,'D'),'D')"
 

@ID... OCONV(ICONV(MAINTENANCE.DATE,"D"),"D")

SYSTEM 31 DEC 2018

Calculations:
 
LIST F.SPF EVAL "ICONV(MAINTENANCE.DATE,'D')-DATE()"
COL.HDR 'Days left to renew the T24 license' ID.SUPP
 

Days left to renew the T24 license

755

Prepare a list for DL.DEFINE:


 
SELECT F.VERSION SAMPLE 30 SAVING EVAL "'VERSION>':@ID"
 
Result:
001 VERSION>AA.ARR.TERM.AMOUNT,AA.PA
002 VERSION>SY.DCD.DECISION,INPUT
003 VERSION>SECURITY.SUPP,AUDIT
004 VERSION>FUNDS.TRANSFER,CORP.INDIRECT.CLG
005 VERSION>PP.INBOUND.OUTBOUND.CDWMP,REVERSE
006 VERSION>AA.ARR.AZ.DEPOSIT,
007 VERSION>BENEFICIARY,AI.NEW.LOCAL.AMEND.PREVIEW
008 VERSION>TSA.SERVICE,MANAGE
...

Basic syntax test (leaving as little non-relevant information on the screen as pos-
sible):
 
LIST . SAMPLE 1 EVAL "OCONV(DATE(),'D')" ID-SUPP
 

OCONV(DATE(),"D")

09 JUN 2017

Suppress headings as well (HDR-SUPP):


 
LIST . SAMPLE 1 EVAL "OCONV(DATE(),'D')" ID-SUPP HDR-SUPP
 
Even further - suppress column headings (COL-HDR-SUPP):
 
LIST . SAMPLE 1 EVAL "OCONV(DATE(),'D')" FMT "25L" ID-SUPP HDR-SUPP
COL-HDR-SUPP
 

// Page 32
09 JUN 2017

More tests:
 
LIST . SAMPLE 1 EVAL "TIMEDATE()" FMT "25L" ID-SUPP HDR-SUPP COL-HDR-SUPP
 

19:56:30 09 JUN 2017

 
LIST . SAMPLE 1 EVAL "ABS(-42)" ID-SUPP HDR-SUPP COL-HDR-SUPP
 

42

 
LIST . SAMPLE 1 EVAL "FMT(42, 'R%7')" ID-SUPP HDR-SUPP COL-HDR-SUPP
 

0000042

 
LIST . SAMPLE 1 EVAL "'ABCDEFXYZ'[4,3]" ID-SUPP HDR-SUPP COL-HDR-SUPP

DEF
 
 
LIST . SAMPLE 1 EVAL "DOWNCASE('ABCDEFXYZ')[3]" ID-SUPP HDR-SUPP COL-HDR-SUPP

xyz
 

2.29 SELECT on SELECT

When we have an active SELECT list, we can apply other jQL command on top of it.
for example, we want to select accounts that present both in LIVE and HIS files
(note that in history @IDs have a suffix ";n", where n is record number hence the
EVAL in SAVING clause):
 
SELECT FBNK.ACCOUNT$HIS SAVING UNIQUE EVAL "FIELD(@ID,';',1)"
 

97 Records selected

 
>SELECT FBNK.ACCOUNT
 

...
** Error [ 202 ] **
Record 'USD141820001' is not on file.
** Error [ 202 ] **
Record 'USD140440001' is not on file.

52 Records selected

>

// Page 33
We still have the active SELECT list that we can save or use any other way.

To avoid "** Error [ 202 ] **" messages the option "(R" can be used

in the second query, e.g. SELECT FBNK.ACCOUNT (R

Consequent SELECT can be done on another table, provided that @IDs match:
 
SELECT FBNK.ACCOUNT LIKE "0N" SAVING UNIQUE CUSTOMER
 

251 Records selected

 
>SELECT FBNK.CUSTOMER SAVING UNIQUE SECTOR
 

18 Records selected

 
>LIST FBNK.SECTOR ONLY
 

2001
2002
3501
2005
1001
1501
3001
3505
1503
3504
2000
1499
3503
3003
1002
3002
3502
1000

18 Records Listed

2.30 Negative SELECT

ACCOUNT records that are only in history (e.g. closed):


 
SELECT FBNK.ACCOUNT$HIS SAVING UNIQUE EVAL "FIELD(@ID,';',1)"
 

97 Records selected

97 accounts have at least one history record.

// Page 34
 
>NSELECT FBNK.ACCOUNT
 

45 Records selected

Of them - 45 accounts do not present in LIVE file. Let’s check it:


 
>SELECT FBNK.ACCOUNT (R
 

No Records selected

2.31 Reverse SELECT


 
COUNT FBNK.ACCOUNT
 

1637 Records counted

 
SELECT FBNK.ACCOUNT WITH ACCOUNT.OFFICER EQ '55'
 

25 Records selected

Now select accounts that are not assigned to account officer 55:
 
>XSELECT FBNK.ACCOUNT
 

1612 Records selected

>

Of course we could do it using "NE ’55’" but XSELECT might be handy

when we work with pre-saved SELECT lists.

2.32 Select concat files

Concat files (like CUSTOMER.ACCOUNT) have all their data in a single field. For
example:
 
LIST FBNK.CUSTOMER.ACCOUNT
 
Though there’s only one line of output for each @ID, tt doesn’t mean that there’s
only one account opened for each customer.

// Page 35
@ID....... @ID....... CUSTOMER.CODE ACCOUNT.NUMBER..

190086 190086 190086 74012


100121 100121 100121 74063
100124 100124 100124 74098
100110 100110 100110 74136
100109 100109 100109 74117
...

"CT" will show full records:


 
CT FBNK.CUSTOMER.ACCOUNT
 

190086
001 74012
002 74028
003 74039
004 74047
005 74055

100121
001 74063

100124
001 74098

100110
001 74136

100109
001 74117
002 74128
003 74152
...

If we want to select all the data in such tables we can use QSELECT:
 
QSELECT FBNK.CUSTOMER.ACCOUNT
Record Keys : *
 

976 Records selected

 
>SAVE.LIST CA
 

976 record(s) saved to list 'CA'

 
CT &SAVEDLISTS& CA
 

// Page 36
CA
001 74012
002 74028
003 74039
004 74047
005 74055
006 74063
007 74098
008 74136
009 74117
010 74128
...

Same effect can be achieved with "SELECT FBNK.CUSTOMER.ACCOUNT SAV-

ING EVAL "@RECORD"".

If we want to select all values of a particular field, BSELECT can be used:


 
BSELECT FBNK.LIMIT.COL.ALLOC.WORK LIMIT.ID
 

145 Records selected

 
>SAVE.LIST LIM
 

145 record(s) saved to list 'LIM'

 
CT &SAVEDLISTS& LIM
 

LIM
001 100285.0008300.01
002 120012.0002400.01
003 120012.0008100.01
004 120012.0008110.01
005 120016.0002400.01
006 120016.0008100.01
007 120016.0008110.01
008 100345.0002400.01
009 100345.0008100.01
010 100345.0008110.01
011 120019.0002100.01
012 120019.0002110.01
013 120019.0002400.01
014 111661.0010100.01.111660
015 111661.0011000.01.111660
...

// Page 37
2.33 More operation with saved SELECT lists

Compare active account officers list (i.e. ones that have assigned accounts) for
2 companies:
 
SELECT FBNK.ACCOUNT SAVING UNIQUE ACCOUNT.OFFICER
 

36 Records selected

 
>SAVE.LIST AOFF1
 

36 record(s) saved to list 'AOFF1'

 
SELECT FEU1.ACCOUNT SAVING UNIQUE ACCOUNT.OFFICER
 

9 Records selected

 
>SAVE.LIST AOFF2
 

9 record(s) saved to list 'AOFF2'

Looks like all 9 officers that have accounts in the company with mnemonic EU1 also
have accounts in the company BNK:
 
AND-LISTS AOFF1 AOFF2
 

9 Records selected
>

Let’s now compare FBNK.ACCOUNT - LIVE and NAU files.


 
SELECT FBNK.ACCOUNT$NAU
 

28 Records selected

 
>SAVE.LIST ACNAU
 

28 record(s) saved to list 'ACNAU'

 
SELECT FBNK.ACCOUNT
 

1637 Records selected

 
>SAVE.LIST ACLIVE
 

// Page 38
1637 record(s) saved to list 'ACLIVE'

Records presenting in both lists:


 
AND-LISTS ACNAU ACLIVE
 

1 Records selected

 
>CLEARSELECT
 

[528] List '0' cleared.

Records presenting in at least one list:


 
OR-LISTS ACNAU ACLIVE
 

1664 Records selected

 
>CLEARSELECT
 

[528] List '0' cleared.

Records presenting in one list but not in another:


 
XOR-LISTS ACNAU ACLIVE
 

1663 Records selected

>

2.34 Copy records

This isn’t exactly jQL, but anyway...


It’s possible to copy records from one table to another; this would be the low-
level copy (with all possibly severe consequences to T24).
Directories are also considered as files (type UD) in jBASE so...
Copy a particular record:
 
COPY FROM F.COMPANY TO &TEMP& GB0010001
 

1 records copied

Copy all records:


 
COPY FROM F.COMPANY TO &TEMP& ALL
 

// Page 39
'GB0010001' already exists
9 records copied

Force an overwrite:
 
COPY FROM F.COMPANY TO &TEMP& ALL OVERWRITING
 
 
10 records copied
 
Change target record name:
 
COPY FROM F.COMPANY TO &TEMP& GB0010001,GB-copy
 

1 records copied

See the results:


 
jsh modelbank ~ -->cmd
 

Microsoft Windows [Version 6.1.7601]


Copyright (c) 2009 Microsoft Corporation. All rights reserved.

 
C:\home\kzm\t24env\r15\bnk\bnk.run>dir "&TEMP&"
 

Volume in drive C is Windows


Volume Serial Number is 78C1-B74C

Directory of C:\home\kzm\t24env\r15\bnk\bnk.run\&TEMP&

12/06/2017 19:13 <DIR> .


12/06/2017 19:13 <DIR> ..
12/06/2017 19:20 5 308 EU0010001
12/06/2017 19:20 5 346 GB-copy
12/06/2017 19:20 5 346 GB0010001
12/06/2017 19:20 5 303 GB0010002
12/06/2017 19:20 5 295 GB0010003
12/06/2017 19:20 5 295 GB0010004
12/06/2017 19:20 5 311 GB0010005
12/06/2017 19:20 5 316 SG0010001
12/06/2017 19:20 5 346 SG0020100
12/06/2017 19:20 5 308 SG0020101
12/06/2017 19:20 5 308 SG0020102
11 File(s) 58 482 bytes
2 Dir(s) 346,170,978,304 bytes free

 
type "&TEMP&\GB0010001"
 

// Page 40
Model Bank R15-AMR
18 Place De Philosophes,]CH 1205 Geneva,]Switzerland
BNK
1

N
1
AA.ACCOUNT.CLOSURE.DETAILS]AA.ARRANGEMENT.ACTIVITY]AA.SIMULATION.CAPTURE]...
...
82
55607_INPUTTER
1506091201
12987_AUTHORISER
GB0010001
1

Inside resulting text files @FMs were changed to end-of-line char-

acters, @VMs and @SMs stay as they are (@VMs in the output above were

replaced with "]"). Technically these text files can be corrected

and written back to F.COMPANY but that can be recommerded only if

no other way of doing this is available and it should be done with

extreme caution.

2.35 Delete records

Delete the particular record (let’s clean up the mess from the previous example):
 
DELETE &TEMP& GB0010001
 

1 record(s) deleted.

Delete selected records:


 
SELECT &TEMP& LIKE "'SG'..."
 

4 Records selected

 
>DELETE &TEMP&
 

// Page 41
4 record(s) deleted.

Delete all records:


 
CLEAR-FILE &TEMP&
 

2.36 "Dump" a record


 
I-DUMP F.USER 'INPUTTER'
 

INPUTTER^INPUTTER^INPUTT^INT^1^GB0010001]GB0010002]EU0010001]SG0010001]SG00201
00]GB0010005]GB0010003]GB0010004]SG0020101]SG0020102^1^20170101M0601^20150429^
20171231^0^2400^999^9^^^^ALL^ALL.PG^^A 2 B C D E F H I L P R S V^^^^^NO^NO^NO^
NO^DDMM^^20161020^141258^dgxip61waupu3EPi5qzqUKrhN9BQbMwNvwf7cWERgVw=^20160825
^^^^Y^^]^00^^^^^^^^,.^^^^^SUPER.USER^^^^^^^^^^^^^^1^^^^^kbB3GZav2O^^^^^^^^^^17
^60370_OFFICER__OFS_SEAT^1504291521^60370_OFFICER_OFS_SEAT^GB0010001^1^

2.37 Search for data in a table


 
SEARCH FBNK.SECTOR
String :Orgs
String :
Record Keys : *
 

4 Records selected

>

 
SEARCH F.EB.ERROR
String :E-100500
String :
Record Keys : *
 

1 Records selected

 
>LIST F.EB.ERROR
 

...
RESERVED1.3.....
RESERVED1.4.....
RESERVED1.5.....
NUMERIC.ID...... E-100500

// Page 42
2.38 Brief statistics on file records
 
STAT FBNK.STMT.ENTRY
 

Statistics of record length :


total = 8180906 average = 370.8647 count = 22059

Full statictics can be obtained using jstat command.

 
jstat -v FBNK.STMT.ENTRY
 

File Path = ..\bnk.data\ac\FBNK_STMT_ENTRY


File Type = JR, Hash method = 5,
Created = Mon May 19 19:53:07 2008
Frame size = 4096, OOG Threshold = 2048
File size = 46157824, Freespace = 0 frames
Internal Modulo = 3/7/19, External Modulo = 31
Inode no. = 231133, Device no. = 46924
Accessed = Wed Jun 10 13:16:14 2015,
Modified = Wed Jun 10 13:16:14 2015
Backup = YES, Log = YES, Rollback = YES, Secure updates = YES
Deallocate pointers : NO Deallocate frames NO
Revision level = 1
Record Bytes = 8983716, Record Count = 22059
Bytes/Record = 407, Bytes/Group = 877
Data Frames = 10240, Ptr Frames = 399
OOG Bytes = 0, OOG Frames = 0
Sum Squares = 3753900786, Std Dev Mean = 474

3 Advanced usage

3.1 I-descriptors

They can be considered as "virtual fields". They also present in file dictionary
(type "I").
Examples from CUSTOMER:
Fields concatenation:
 
CT DICT FBNK.CUSTOMER NAME.ADDRESS
 

NAME.ADDRESS
001 I
002 SHORT.NAME:' ':NAME.1:' ':NAME.2:' ':STREET:' ':TOWN.COUNTRY
003

// Page 43
Usage - the same as "regular" fields:
 
LIST FBNK.CUSTOMER NAME.ADDRESS
 
 
@ID....... NAME.ADDRESS......................................

190113 DONALD DONALD DONALD 1


188888 BBH Inhouse Custodian BBH Inhouse Custodian BBH In
house Custodian 125 Finsbury Pavement LONDON
122122 PWM Relationship Manager PWM Relationship Manager
model US
100362 Seabrook Enterprises Inc Seabrook Enterprises Inc
100 GALLERIA PARKWAY N.W SUITE 580 ATLANTA GA 303
30 USA
120110 Impex Associates Impex Associates Impex Associates
P.O. Box 83594 Montreal
....
 
Contents can be queried as well:
 
LIST FBNK.CUSTOMER NAME.ADDRESS WITH NAME.ADDRESS LIKE "...'JAPAN'..."
 
 
@ID....... NAME.ADDRESS......................................

100341 Keizo Saji Mr Keizo Saji 1 40 DOJIMAHAMA 2 CHOME


KITA-KU OSAKA 530 JAPAN
100473 Bank Of Tokyo Bank Of Tokyo TOWER BUILDINGS 1002
TOKYO - JAPAN
100269 Akio Morita Mr Akio Morita 6 735 KITASHINAGAWA TO
KYO 141-0001 JAPAN
100707 Bank Of Tokyo Bank Of Tokyo 7-1 MARUNOUCHI 2 CHOM
E CHIYOTO - KU TOKYO 100-8388 JAPAN
100700 Sumitomo Tokyo Sumitomo Bank And Trust Tokyo 20 K
OBE STREET TOKYO JAPAN
100393 Tadahiro Yoshida Mr Tadahiro Yoshida 1 KANDAIZUMI
-CHO CHIYODA-KU TOKYO 101-8642 JAPAN
100274 Takemitsui Takizaki Mr Takemitsui Takizaki 1 3 14
HIGASHI-NAKAJIMA HIGASHI-YODOGAWA OSAKA JAPAN

7 Records Listed
 
I-descriptor with logic:
 
CT DICT FBNK.CUSTOMER CHECK.LIAB
 

CHECK.LIAB
001 I
002 CUSTOMER.LIABILITY ; IF @1 NE "" AND @1 NE @ID THEN "" ELSE @ID
003

// Page 44
"@1" means "the result of the first expression"; expressions are de-

limited with semicolon. We can use the same notation in EVAL.

 
LIST FBNK.CUSTOMER EVAL "CUSTOMER.LIABILITY ; IF @1 NE ''
AND @1 NE @ID THEN '' ELSE @ID" COL.HDR 'Check Liab'
 

@ID....... Check Liab

190113 190113
188888 188888
122122 122122
100362 100362
120110 120110
100436 100436
101001 101001
101013 101013
100341 100341
100263 100263
190063 190063
190071 190071
111803
...

Another example of multiple expressions - add 1 year to the current date (won’t
adjust for leap year of course, that would be a bit more complex):
 
LIST . SAMPLE 1 EVAL "OCONV(DATE(),'DG');(@1[1,4]+1);@2:@1[5,4]"
 

20180613

Negative number can also be used:


 
LIST . EVAL '1;2;3;4;5;6;7;8;9;10;11;12;@-2' SAMPLE 1 ID-SUPP
 

10

Plain "@" returns the last expression:


 
LIST . EVAL '1;2;3;4;5;6;7;8;9;10;11;12;@' SAMPLE 1 ID-SUPP
 

12

Back to I-descriptors. Routine call:


 
CT DICT FBNK.CUSTOMER LAST.DATE.TIME
 

// Page 45
LAST.DATE.TIME
001 I
002 DATE.TIME<1,1> ; SUBR("FULL.DATE.TIME", @1)
003

 
LIST FBNK.CUSTOMER DATE.TIME LAST.DATE.TIME
 

@ID....... DATE.TIME...... LAST.DATE.TIME.

190113 1504291604 201504291604


188888 1504241614 201504241614
122122 1504291601 201504291601
100362 1504241614 201504241614
120110 1504241615 201504241615
100436 1504241614 201504241614
....

Or - easier to read - like this:


 
LIST FBNK.CUSTOMER DATE.TIME EVAL "FMT(LAST.DATE.TIME,'####-##-## ##:##')"
 

@ID....... DATE.TIME...... FMT(LAST.DATE.TIME,"####-##-## ##:##")

190113 1504291604 2015-04-29 16:04


188888 1504241614 2015-04-24 16:14
122122 1504291601 2015-04-29 16:01
100362 1504241614 2015-04-24 16:14
120110 1504241615 2015-04-24 16:15
100436 1504241614 2015-04-24 16:14
101001 1504291519 2015-04-29 15:19
...

Local reference fields are also I-descriptors:


 
CT DICT FBNK.CUSTOMER CU.EFF.DATE
 

CU.EFF.DATE
001 I
002 LOCAL.REF<1,2>
003
004 CU.EFF.DATE
005 11R
006 S

Link to another table (via routine call):


 
CT DICT FBNK.CUSTOMER SECTOR.NAME
 

// Page 46
SECTOR.NAME
001 I
002 SECTOR; SUBR("ENQ.TRANS","SECTOR", @1, "SHORT.NAME")
003

So see the results of the following query:


 
LIST FBNK.CUSTOMER NAME.ADDRESS CHECK.LIAB LAST.DATE.TIME CU.EFF.DATE
SECTOR.NAME
 

@ID............ 190113
NAME.ADDRESS... DONALD DONALD DONALD 1
CHECK.LIAB..... 190113
LAST.DATE.TIME. 01504291604
CU.EFF.DATE....
SECTOR.NAME.... Unable to open F0.SECTOR

@ID............ 188888
NAME.ADDRESS... BBH Inhouse Custodian BBH Inhouse Custodian BBH...
CHECK.LIAB..... 188888
LAST.DATE.TIME. 01504241614
CU.EFF.DATE....
SECTOR.NAME.... Unable to open F0.SECTOR
...

Something went wrong... In fact, ENQ.TRANS requires the prior login to T24 (so
T24 COMMON areas are populated). Let’s do this, then go back to jsh, then repeat
this query:
@ID............ 190113
NAME.ADDRESS... DONALD DONALD DONALD 1
CHECK.LIAB..... 190113
LAST.DATE.TIME. 201504291604
CU.EFF.DATE....
SECTOR.NAME.... Individuals Particuliers

@ID............ 188888
NAME.ADDRESS... BBH Inhouse Custodian BBH Inhouse Custodian BBH Inhouse...
CHECK.LIAB..... 188888
LAST.DATE.TIME. 201504241614
CU.EFF.DATE....
SECTOR.NAME.... Broker Courtiers

@ID............ 122122
NAME.ADDRESS... PWM Relationship Manager PWM Relationship Manager model US
CHECK.LIAB..... 122122
LAST.DATE.TIME. 201504291601
CU.EFF.DATE....
SECTOR.NAME.... Staff Personnel
...

// Page 47
SECTOR.NAME is multi-valued (as per SECTOR dictionary) and if we don’t want the
second value to appear, it’s quite easy:
 
LIST FBNK.CUSTOMER NAME.ADDRESS CHECK.LIAB LAST.DATE.TIME CU.EFF.DATE
EVAL "EXTRACT(SECTOR.NAME,1,1)"
 

3.2 Address fields by numbers

As it was already communicated, the notation "*An" (where n is field number) can
be used for that. This is called "A correlative".
See F.USER fields ##1, 2 and 3:
 
LIST F.USER *A1 *A2 *A3
 

@ID............. *A1........... *A2........... *A3...........

PAYSUSER3 PAY USER PAYUSER3 INT


BUILDUSER98 BUILDUSER 98 TELLER98 INT
BUILDUSER40 BUILDUSER.40 USER40 INT
BUILDUSER8200 BUILDUSER8200 DHAMO1 INT
BUILDUSER34 BUILDUSER34 USER34 INT
GTUSER GTS USER GTSUSER INT
...

F1 can also be used instead of *A1, F2 instead of *A2 - there are

such VOC records but they do not present for numbers bigger than 10.

 
LIST VOC WITH @ID LIKE "'F'0N"
 

NAME.............................................. TYPE

F9 D
F7 D
F4 D
F5 D
F2 D
F3 D
F10 D
F8 D
F1 D
F6 D

10 Records Listed

These records look like:


 
CT VOC F9
 

// Page 48
F9
001 D
002 9
003
004
005 15T
006 S

How to see positions of fields in a table:


 
LIST DICT F.SECURITY.MASTER WITH *A1 EQ 'D' EVAL "FMT(F2,'R%3')" AS POS BY POS
 

DICT F.SECURITY.MASTER POS.........

@ID 000
SECURITY.CODE 000
COMPANY.NAME 001
DESCRIPT 002
SHORT.NAME 003
MNEMONIC 004
COMPANY.DOMICILE 005
SECURITY.DOMICILE 006
...

Another method to get a field by number - field #2 (NUMERIC.CCY.CODE) in this ex-


ample:
 
LIST FBNK.CURRENCY EVAL "OCONV(@ID,'A2')"
 

GBP 826
CAD 124
LKR 144
SEK 752
TWD 901
CHF 756
...

3.3 Default output for empty fields


 
LIST FBNK.FUNDS.TRANSFER$HIS EVAL "OCONV(OVERRIDE,\S;*;'NULL'\)"
 

@ID...................... OCONV(OVERRIDE,"S;*;"NULL"").......

FT150838302S;1 DR.GT.BACKVALUE~}DEBIT VALUE EXCEEDS


MAX BACKVALUE
EXCESS.ID~}You have an Excess of & &
on Limit &~{USD~}-50000~}111482.000AD
CA.03~{USD~{-50000~{78228~{111482~{~{1114
82.0000100.03~{

// Page 49
FT15093FD0P2;1 NULL
FT150837LQQR;1 BNK.DIFF.CCY~}Intermediary not Resid
ent of Pay Ccy
ACCT.UNAUTH.OD~}Unauthorised overdra
ft of & & on account &.~{USD~}107693.
15~}20467~{USD~{107693.15~{20467~{100283
~{210~{~{
FT150836PKCL;1 NULL
FT1509014MCW;1 NULL
FT15093JDNY6;1 NULL
...

3.4 Show records size


 
LIST F.SPF *A9999
 

SYSTEM 649

LIST F.SPF EVAL "OCONV(@ID,'ANL')"

SYSTEM 649

*A9999 and *A9998 are special numbers; the latter shows the number

of output line.

 
LIST FBNK.CURRENCY *A9998
 

@ID *A9998........

GBP 1
CAD 2
LKR 3
SEK 4
TWD 5
CHF 6
AZN 7
GEL 8
SAR 9
DKK 10
ZAR 11
...

Same result can be achieved with:


 
LIST FBNK.CURRENCY EVAL "OCONV(@ID,'ANI')"
 

// Page 50
Length of record can also be obtained using special notation "@RECORD" that we al-
ready used:
 
LIST F.SPF EVAL "LEN(@RECORD)"
 

SYSTEM 649

3.5 EVERY clause

As we saw before, when we select a record with a condition refer-

ring to multi-valued field, by default selection will return those

records where at least one value of this field satisfies the selec-

tion criteria. EVERY clause allows to override this behaviour.

 
COUNT FBNK.CURRENCY WITH CURRENCY.MARKET EQ 1
 

34 Records counted

 
COUNT FBNK.CURRENCY WITH EVERY CURRENCY.MARKET EQ 1
 

28 Records counted

So we have 6 CURRENCY records that have at least one value of CURRENCY.MARKET other
than 1:
 
LIST FBNK.CURRENCY CURRENCY.MARKET WITH CURRENCY.MARKET NE 1
 

@ID CURRENCY.MARKET

GBP 1
10
CAD 1
10
EUR 1
10
SGD 1
10
NZD 1
10
USD 1
10

6 Records Listed

// Page 51
3.6 Usage of standard jBC functions
 
LIST . SAMPLE 1 EVAL "DOWNCASE('ABCDEFXYZ')" ID-SUPP HDR-SUPP COL-HDR-SUPP
 

abcdefxyz

 
LIST . SAMPLE 1 EVAL "'abcdefxyz' MATCHES DOWNCASE('ABCDEFXYZ')"
ID-SUPP HDR-SUPP COL-HDR-SUPP

1
 
 
LIST . SAMPLE 1 EVAL "OCONV(DATE(),'DG')" ID-SUPP HDR-SUPP COL-HDR-SUPP
 

20170612

 
LIST . SAMPLE 1 EVAL "ABS(-1000)" ID-SUPP HDR-SUPP COL-HDR-SUPP
 

1000

 
LIST FBNK.ACCOUNT EVAL "ISDIGIT(@ID)" ID-SUPP HDR-SUPP COL-HDR-SUPP
 
 
Error in attribute definition item ISDIGIT(@ID)
Error in Itype:
Cannot locate Basic subroutine ISDIGIT
 

Some jBC functions can’t be used...

MATCHES will help here:


 
LIST FBNK.ACCOUNT @ID EVAL "@ID MATCHES '0N'" ID-SUPP HDR-SUPP COL-HDR-SUPP
 

...
81086 1
81698 1
USD143050001 0
78042 1
79747 1
17205 1
24732 1
USD1000115100001 0

 
LIST . SAMPLE 1 EVAL "CHAR(64)" ID-SUPP HDR-SUPP COL-HDR-SUPP
 

// Page 52
 
LIST FBNK.CUSTOMER$HIS EVAL "FIELD(@ID,';',1)"
 

100336;2 100336
100338;2 100338
190148;1 190148
100112;1 100112
190073;1 190073
111658;1 111658
111617;1 111617
100295;1 100295
100242;1 100242
...

 
LIST FBNK.CUSTOMER$HIS EVAL "CONVERT(';', '-', @ID)"
 

100336;2 100336-2
100338;2 100338-2
190148;1 190148-1
100112;1 100112-1
190073;1 190073-1
111658;1 111658-1
111617;1 111617-1
100295;1 100295-1
100242;1 100242-1
...

 
LIST FBNK.SECTOR SHORT.NAME EVAL "DCOUNT(SHORT.NAME,@VM)" AS values
 

@ID. SHORT.NAME..... values.........

1503 Retail Broker 1


1002 Staff 2
Personnel
1499 Individuals 2
Particuliers
1599 Brokers 2
Courtiers
1601 Clrg Agents 2
Compensateurs
...

We used CONVERT earlier to change semicolons to dashes; OCONV can also be used for
similar purpose, especially if we want to replace a substring with something of
a different length:
 
LIST FBNK.SECTOR EVAL "OCONV(SHORT.NAME,'MCC;':@VM:'; / ')"
COL.HDR 'Short names' FMT '35L'
 

// Page 53
@ID. Short names........................

1503 Retail Broker


1002 Staff / Personnel
1499 Individuals / Particuliers
1599 Brokers / Courtiers
1601 Clrg Agents / Compensateurs
2003 Subsidiary Comp / Filiales
2005 Retail SME / PME
3001 Banks / Banques
...

 
LIST FBNK.ACCT.ACTIVITY EVAL "FIELD(@ID,'-',1)" COL.HDR 'Account '
EVAL "SUM(TURNOVER.DEBIT)" EVAL "SUM(TURNOVER.CREDIT)" ID.SUPP
 

Account SUM(TURNOVER.DEBIT) SUM(TURNOVER.CREDIT)

GBP1418502370001 -2493.19 2493.19


GBP1091500010001 0 2500
76187 -238667.92 81107.62
SGD1280000030001 0 4100000
USD1460000020001 -6000 6000
14017 -2501166.67 23502527.78
...

 
LIST . SAMPLE 1 EVAL "ICONV('20161231', 'D') - ICONV('20151231', 'D')" ID-SUPP
HDR-SUPP COL-HDR-SUPP
 

366

 
LIST F.COMPANY EVAL "FMT(DATE.TIME,'##-##-## ##:##')"
 

GB0010003 15-05-14 07:28


GB0010005 15-05-14 07:29
SG0010001 15-05-14 07:29
SG0020102 15-05-14 07:29
EU0010001 15-05-14 07:28
SG0020101 15-05-14 07:29
GB0010002 15-05-14 07:28
GB0010004 15-05-14 07:28
SG0020100 15-05-14 07:29
GB0010001 15-06-09 12:01

 
LIST . SAMPLE 1 EVAL "INDEX('HayHayNeedleHayHay', 'Needle', 1)" ID-SUPP
HDR-SUPP COL-HDR-SUPP
 

// Page 54
 
LIST FBNK.ACCOUNT EVAL "LEN(@ID)"
 

@ID................ LEN(@ID)..

76902 5
75067 5
14095 5
GBP1720507450001 16
14087 5
75938 5
USD140300001 12
USD1590599990001 16
....

 
LIST FBNK.ACCT.ACTIVITY TURNOVER.CREDIT EVAL "MAXIMUM(TURNOVER.CREDIT)"
 

GBP1418502370001-201503 2493.19 2493.19


GBP1091500010001-201504 2500 2500
76187-201504 51200
29907.62
51200
SGD1280000030001-201504 4000000 4000000
100000
USD1460000020001-201504 1000 5000
5000
14017-201503 23500000 23500000
2527.78
...

 
LIST . SAMPLE 1 EVAL "STR('*', 42)" ID-SUPP HDR-SUPP COL-HDR-SUPP
 

**********
**********
**********
**********
**

 
LIST . SAMPLE 1 EVAL "STR('*', 42)" FMT '42L' ID-SUPP HDR-SUPP COL-HDR-SUPP
 

******************************************

 
LIST . SAMPLE 1 EVAL "TIMEDATE()" FMT '42L' ID-SUPP HDR-SUPP COL-HDR-SUPP
 

21:00:10 12 JUN 2017

 
LIST FBNK.CUSTOMER WITH EVAL "INDEX(NAME.1,' ',1)" GT 0 NAME.1
EVAL "TRIM(NAME.1,' ','R')"
 

// Page 55
@ID....... NAME.1............................. TRIM(NAME.1," ", "R")...

190048 Mr Harris Vogel Mr Harris Vogel


190016 Mr Robin Peterson Mr Robin Peterson
190022 Mr Thomas Jones Mr Thomas Jones
190053 Mr Chris Klein Mr Chris Klein
190044 Mr Peter Hall Mr Peter Hall
190116 Mr Chris Klein Mr Chris Klein
100363 Intl Business Machines Intl Business Machines
...

 
LIST FBNK.TARGET EVAL "DQUOTE(EXTRACT(DESCRIPTION,1,1))"
EVAL "SQUOTE(EXTRACT(DESCRIPTION,1,2))"
 

7 "Corporate Entity" 'Entreprise'


20 "Portfolio Holder" 'Investisseur'
999 "Others" 'Autres'
...

Get current PID:


 
LIST . SAMPLE 1 EVAL "SYSTEM(1037)" FMT '40L' COL.HDR 'PID' ID-SUPP
 

PID.....................................

3128

Get screen size:


 
LIST . SAMPLE 1 EVAL "SYSTEM(2):'x':SYSTEM(3)" FMT '40L' COL.HDR 'Screen Size'
 

Screen Size.............................

144x56

3.7 Usage of custom jBC subroutines for EVAL

Imagine that we want to show LIMIT records only for customers who have accounts
with certain categories. To fulfil a task like this let’s write and compile the
jBC subroutine that will prepare a @VM-delimited list for use in MATCH:

SUBROUTINE ListGet(ret_list, sel_query)


*-------------------------------------------------------------
EXECUTE sel_query CAPTURING output RTNLIST ret_list

CHANGE @FM TO @VM IN ret_list


RETURN
END

// Page 56
Note that the first parameter is a return one and it will be omit-

ted in the jQL query.

jQL query:
 
LIST FBNK.LIMIT WITH EVAL
"CUST.NO MATCHES ListGet
('SELECT FBNK.ACCOUNT WITH CATEGORY EQ 1001 1002 1003
SAVING UNIQUE CUSTOMER')"
EQ 1 ONLINE.LIMIT
 

@ID............................. ONLINE.LIMIT.......

100182.0012510.01.100182 1000000.00
100182.0018000.01.100182 1000000.00
111661.0015115.01.111661 3000000.00
111661.0005215.01.111661
188927.0015400.01.188928 20000000.00
...

Another example: list all SECURITY.MASTER records with "GOOD" ratings (backslashes
can be used as quotes as you can see):
 
LIST F.SECURITY.MASTER WITH EVAL "RATING MATCHES
ListGet('SELECT F.EB.RATING WITH SL.HVCRE.RATING EQ \GOOD\')" EQ 1 RATING
 

@ID......... RATING

100048-000 4
100027-000 2
100054-000 6
100062-001 4
100011-100 4
100059-000 5
600104-000 2
100015-000 5
000423-000 2
100063-000 5
...

It’s often necessary to get a value of some environment variable. Unfortunately


jQL doesn’t support neither "%var%" notation as in Windows nor Unix-like one with
preceding dollar sign; jBC subroutine GETENV() inside EVAL results in the error.
We can create a custom subroutine to achieve that:

SUBROUTINE EnvGet(ret_data, env_key)


*-------------------------------------------------------------
IF NOT(GETENV(env_key, ret_data)) THEN ret_data = ''
RETURN
END

// Page 57
Example:
 
LIST . SAMPLE 1 EVAL "EnvGet('TAFC_HOME')" FMT '40L'
COL.HDR 'TAFC home' ID-SUPP
 
TAFC home...............................

C:\home\kzm\t24env\r15\TAFC

3.8 Sort by EVAL

Example with EVAL routine usage - sorted by the second part of @ID:
 
LIST FBNK.LIMIT WITH EVAL
"CUST.NO MATCHES ListGet
('SELECT FBNK.ACCOUNT WITH CATEGORY EQ 1001 1002 1003
SAVING UNIQUE CUSTOMER')" EQ 1 ONLINE.LIMIT
BY EVAL "FIELD(@ID,'.',2)"
 
@ID............................. ONLINE.LIMIT.......

M000000004.0000100.01.129034 100000.00
100182.0005200.01.100182
111661.0005200.01.111661
188919.0005200.01.188919
188919.0005205.01.188919
...
...
...
M000000001.0038300.01.100803 2000000.00

Another example where we use an alias to both show and sort by:
 
LIST FBNK.SEC.ACC.MASTER CONTRIBUTIONS WITHDRAWALS
EVAL "MAXIMUM(SUM(WITHDRAWALS):@FM:SUM(CONTRIBUTIONS))" AS summ
BY.DSND summ
 
@ID.............. CONTRIBUTIONS..... WITHDRAWALS....... summ...........

100472-950 0 0 7012041.07
7012041.07 707637.06
100461-940 0 0 4567231.68
633121.43 4567231.68
100472-940 0 0 3981892.51
1251657.27 3981892.51
111602-1 0 0 1366958.42
1366958.42 0.00
100297-2 0 0 1023662.78
1023662.78 350004.02
100292-1 0 0 960010.89
960010.89 241281.39

// Page 58
"AS" is sensitive to keywords; if we use "AS sum" we’ll get an er-

ror:

Error in AS clause.

3.9 Multi-valued output change with BY-EXP

In the following example we’ll output associated VERSION fields AUTOM.FIELD.NO,


AUT.OLD.CONTENT and AUT.NEW.CONTENT for those VERSIONs where there’s 3 such as-
sociations.

Usual way:

 
LIST F.VERSION WITH EVAL "DCOUNT(AUTOM.FIELD.NO,@VM)" EQ 3 AUTOM.FIELD.NO
AUT.OLD.CONTENT AUT.NEW.CONTENT BY.DSND @ID
 

@ID............. VERSION,DESIGNER
AUTOM.FIELD.NO.. RECORDS.PER.PAGE FIELDS.PER.LINE LANGUAGE.CODE-1
AUT.OLD.CONTENT.
AUT.NEW.CONTENT. 1 MULTI 1

@ID............. TRANS.DOCUMENT,RECORD.DOCUMENT
AUTOM.FIELD.NO.. STATUS STATUS.DATE DOC.SEQUENCE
AUT.OLD.CONTENT.
AUT.NEW.CONTENT. 1 !TODAY 1

@ID............. TELLER.FINANCIAL.SERVICES,BILL.PAYMENT
AUTOM.FIELD.NO.. TRANSACTION-1 BENEFICIARY.ID-1 SURROGATE.AC-1
AUT.OLD.CONTENT.
AUT.NEW.CONTENT. Bill-Pay BENEFICIARY>@ID BENEFICIARY>BEN.ACCT.NO

@ID............. TELLER,VAULT.TO.TILL
AUTOM.FIELD.NO.. TRANSACTION.CODE TELLER.ID.2 TELLER.ID.1
AUT.OLD.CONTENT.
AUT.NEW.CONTENT. 102 9999 !CURRENT.TELLER.1

...

With BY.EXP:
 
LIST F.VERSION WITH EVAL "DCOUNT(AUTOM.FIELD.NO,@VM)" EQ 3 AUTOM.FIELD.NO
AUT.OLD.CONTENT AUT.NEW.CONTENT BY.DSND @ID BY.EXP AUTOM.FIELD.NO
 

// Page 59
@ID............. VERSION,DESIGNER
AUTOM.FIELD.NO.. FIELDS.PER.LINE
AUT.OLD.CONTENT.
AUT.NEW.CONTENT. MULTI

@ID............. VERSION,DESIGNER
AUTOM.FIELD.NO.. LANGUAGE.CODE-1
AUT.OLD.CONTENT.
AUT.NEW.CONTENT. 1

@ID............. VERSION,DESIGNER
AUTOM.FIELD.NO.. RECORDS.PER.PAGE
AUT.OLD.CONTENT.
AUT.NEW.CONTENT. 1

@ID............. TRANS.DOCUMENT,RECORD.DOCUMENT
AUTOM.FIELD.NO.. DOC.SEQUENCE
AUT.OLD.CONTENT.
AUT.NEW.CONTENT. 1

@ID............. TRANS.DOCUMENT,RECORD.DOCUMENT
AUTOM.FIELD.NO.. STATUS
AUT.OLD.CONTENT.
AUT.NEW.CONTENT. 1

@ID............. TRANS.DOCUMENT,RECORD.DOCUMENT
AUTOM.FIELD.NO.. STATUS.DATE
AUT.OLD.CONTENT.
AUT.NEW.CONTENT. !TODAY
...

Note that both BY.EXP and BY-EXP commands work; however it’s not al-

ways the case with other commands.

3.10 Paragraphs with jQL statements

Paragraphs are records in VOC that can be used to run many commands or selects.
First line of such record should be "PA".
(There are also jCL paragraphs that start with "PQ / PQN" but they are almost out
of scope of this book.)
Example: list @IDs of customers which were edited but the changes were not yet
authorised (we don’t need to include records that were never authorised yet). Cre-
ate a VOC record SEE.CHANGED:
PA
SELECT FBNK.CUSTOMER$NAU
SELECT FBNK.CUSTOMER
LIST ONLY FBNK.CUSTOMER

// Page 60
Run it:
 
SEE.CHANGED
 

8 Records selected

** Error [ 202 ] **
Record '190122' is not on file.
** Error [ 202 ] **
Record '190117' is not on file.
** Error [ 202 ] **
Record '190108' is not on file.
** Error [ 202 ] **
Record '190089' is not on file.
** Error [ 202 ] **
Record '190142' is not on file.
** Error [ 202 ] **
Record '190115' is not on file.

2 Records selected
LIST ONLY FBNK.CUSTOMER$NAU PAGE 1 19:25:58 12 JUN 2017

@ID.......

100273
100407

2 Records Listed

To suppress the message "Record ’190115’ is not on file" we can use "(R" flag:
PA
SELECT FBNK.CUSTOMER$NAU
SELECT FBNK.CUSTOMER (R
LIST ONLY FBNK.CUSTOMER

Result:
8 Records selected

2 Records selected
LIST ONLY FBNK.CUSTOMER$NAU PAGE 1 19:40:57 12 JUN 2017

@ID.......

100273
100407

2 Records Listed

// Page 61
What if we want to proceed other tables as well? Ask user:
PA
DISPLAY <<TABLE>>
SELECT <<TABLE>>$NAU
SELECT <<TABLE>> (R
LIST ONLY <<TABLE>>

 
SEE.CHANGED

TABLE=FBNK.ACCOUNT
 

FBNK.ACCOUNT

28 Records selected

1 Records selected
LIST ONLY FBNK.ACCOUNT$NAU PAGE 1 14:53:54 12 JUN 2017

@ID................

21067

1 Records Listed

More tables to test...


 
SEE.CHANGED

TABLE=FBNK.SECTOR
 

...
3503
4002
4601
5001
9999

48 Records Listed

Why so many? Scroll back, see what was selected in INAU file:
No Records selected

If we have no selection after first SELECT, the second one will - as it should -
select all records. To suppress this we can use REQUIRE.SELECT keyword:
PA
DISPLAY <<TABLE>>
SELECT <<TABLE>>$NAU
SELECT <<TABLE>> REQUIRE.SELECT (R
LIST ONLY <<TABLE>>

// Page 62
Now we have the following error message:
!!! Error message A Select list was required and not supplied.
not found !!!

Another method to process variable data is to use a parameter:


PA
SELECT <<C2,''>>$NAU
SELECT <<C2,''>> REQUIRE.SELECT (R
LIST ONLY <<C2,''>>

Run:
 
SEE.CHANGED FBNK.ACCOUNT
 
PQN paragraph can be used to present a long jQL query on several lines, e.g.:
 
PQN
HSELECT FBNK.RE.CONSOL.SPEC.ENTRY WITH OUR.REFERENCE LIKE 'LD...'
H AND TRANSACTION.CODE EQ 'ACC' 'CAP' BY OUR.REFERENCE
H BY BOOKING.DATE BY DATE.TIME
P
 

3.11 EXPLAIN keyword

Starting from R12 there’s an EXPLAIN keyword in jQL.


Example of select by @ID only:
 
EXPLAIN SELECT FBNK.ACCOUNT UNLIKE "3N"
 
1637 Records selected

Explain Plan
==============================================================================

Command: SELECT FBNK.ACCOUNT UNLIKE "3N"

file:
FBNK.ACCOUNT Type(20)
Scan all of the file, (jQLIDonlyFullFileSource)

Timings:

Full file ID only item source Processor


Total Taken: 0 (1...1)(ms)

End.

Select by field contents:


 
EXPLAIN SELECT FBNK.STMT.ENTRY WITH ACCOUNT.NUMBER LIKE "'1'..."
 

// Page 63
2377 Records selected

Explain Plan
==============================================================================

Command: SELECT FBNK.STMT.ENTRY WITH ACCOUNT.NUMBER LIKE "'1'..."

file:
FBNK.STMT.ENTRY Type(20)
Scan all of the file, (jQLFullFileItemSource)

Timings:

Full file item source Processor


Total Taken: 49312 (1...93)(ms)

End.

3.12 Get information from another table

Show customer name in ACCOUNT listing (we use so-called "T correlative"):
 
LIST FBNK.ACCOUNT UNLIKE "3A..." EVAL "OCONV(CUSTOMER,'TFBNK.CUSTOMER;V1;2;2')"
 

@ID................ OCONV(CUSTOMER,"TFBNK.CUSTOMER;V1;2;2")

76902 Cadbury
75067 Helicks
14095 Merrill Lynch
14087 Merrill Lynch
...

Another example - list security ratings with additional information (in this ex-
ample - only the first RATING value if available):
 
LIST F.SECURITY.MASTER WITH SUB.ASSET.TYPE GE 200 AND SUB.ASSET.TYPE LE 299
EVAL "EXTRACT(RATING,1,1);OCONV(@1,'TF.EB.RATING;V;1;1'):'/'
:OCONV(@1,'TF.EB.RATING;V;3;3'); IF @2 EQ '/' THEN 'No rating' ELSE @2"
COL.HDR 'Rating' FMT '25L'
 

@ID......... Rating...................

300400-000 No rating
800000-011 No rating
000423-000 AA+.S&P/GOOD
000400-033 No rating
400300-001 AA+.S&P/GOOD
800000-016 No rating
200111-000 AA.S&P/GOOD
300300-000 No rating

// Page 64
400301-000 AA+.S&P/GOOD
200118-000 AA+.S&P/GOOD
400400-000 AAA.S&P/STRONG
400500-000 AAA.S&P/STRONG
500200-000 BBB.S&P/SATISFACTORY
300301-000 No rating
400300-000 AA+.S&P/GOOD
400200-000 AA-.S&P/GOOD

16 Records Listed

3.13 Use other dictionary


 
COPY FROM F.SPF TO &TEMP& SYSTEM
 

1 records copied

 
LIST &TEMP& 'SYSTEM'
 

@ID

SYSTEM

1 Records Listed

 
LIST &TEMP& 'SYSTEM' USING DICT F.SPF
 

@ID.................. SYSTEM
@ID.................. SYSTEM
SYSTEM.SPEC.......... SYSTEM
RUN.DATE............. 20150420
SITE.NAME............ Model Bank R15-AMR
OP.MODE.............. O
OP.CONSOLE........... OFF
MAIN.ACCOUNT......... ..\bnk.data
BACKUP.CYCLE.1.......
....

 
LIST &TEMP& 'SYSTEM' USING DICT F.ABBREVIATION
 

@ID............... SYSTEM
@ID............... SYSTEM
ABBREVIATION.CODE. SYSTEM
ORIGINAL.TEXT..... 20150420
RECORD.STATUS..... Model Bank R15-AMR
CURR.NO........... O
INPUTTER.......... OFF
DATE.TIME......... ..\bnk.data

// Page 65
AUTHORISER........
CO.CODE...........
DEPT.CODE......... R15
AUDITOR.CODE...... 1
AUDIT.DATE.TIME...

1 Records Listed

3.14 User exits

User exits are built-in codes starting from "U" that can be used in OCONV(). How-
ever, most of them can be easily replaced with EVAL.
Some examples:
Port number, user name:
 
LIST . SAMPLE 1 EVAL "OCONV('', 'U50BB')"
 

1 modelbank

Call stack:
 
LIST . SAMPLE 1 EVAL "OCONV('', 'U0016')" FMT '35L'
 

JQL_LISTCOLUMNAR LIST

Remove non-printable characters:


 
LIST . SAMPLE 1 EVAL
"DQUOTE(OCONV('ABCDE' : @FM: CHAR(10) : 'FGHIJ', 'U02E7'))"
 

"ABCDEFGHIJ"

Return command line options:


 
LIST . SAMPLE 1 EVAL "OCONV('', 'U20E0')" FMT '35L'
 

.
SAMPLE
1
EVAL
"OCONV('', 'U20E0')"
FMT
'35L'

Encrypt a string:
 
LIST . SAMPLE 1 EVAL "OCONV('This Is How Globus Works', 'U3060')"
 

// Page 66
Ygh\{4$wmZ2}x)v]NSh29bB

Remove spaces:
 
LIST . SAMPLE 1 EVAL "OCONV('This Is How Globus Works', 'U01A9')"
 

ThisIsHowGlobusWorks

4 Some more examples

4.1 See if there’s a discrepancy between F.TSA.STATUS and running


tSA agents
 
SELECT F.TSA.STATUS WITH @ID UNLIKE "'OLTP'..."
AND AGENT.STATUS EQ "RUNNING"
AND WITH EVAL "ABS(TIME()-ICONV(LAST.CONTACT,'MTS'))/60" GT 2.5
 

4.2 See the time of STMT.ENTRY records creation up to a second


 
LIST FBNK.STMT.ENTRY SAMPLE 5 DATE.TIME EVAL "@ID[11,5]" CONV 'MTS' ID-SUPP
 

1504292128 21:28:16
1504291837 18:37:16
1504292051 20:51:00
1504292204 22:04:30
1504292237 22:37:14

4.3 See how many fields are populated in a table


 
SELECT FBNK.STMT.ENTRY SAVING UNIQUE EVAL "DCOUNT(@RECORD,@FM)"
 

8 Records selected

 
>SAVE.LIST SE-CNT
 

8 record(s) saved to list 'SE-CNT'

 
CT &SAVEDLISTS& SE-CNT
 

// Page 67
SE-CNT
001 104
002 106
003 100
004 52
005 107
006 91
007 2
008 101

4.4 How to display only the last value of a field

E.g. MSG.DISPOSITION in DE.O.HEADER:


 
LIST F.DE.O.HEADER EVAL "DCOUNT(MSG.DISPOSITION,@VM) ;
MSG.DISPOSITION<1,@1>" COL.HDR 'Last MSG.DISPOSITION'
 

@ID...................... Last MSG.DISPOSITION.

D20150429267757645902 FORMATTED
D20150429469107521504 REPAIR
D20150430183750057912 FORMATTED
D20150429033096262402 FORMATTED
D20150429791836992805 FORMATTED
D20150429263236143001 FORMATTED
D20150504147773239909
D20150504147773239921 ACK
...

4.5 See on which work day an FT was created (based on its @ID)
 
LIST FBNK.FUNDS.TRANSFER$HIS
EVAL "OCONV(ICONV('20':@ID[3,2]:@ID[5,3],'DJ'),'D')"
COL.HDR 'CREATED' FMT '11L'
 

@ID...................... CREATED....

FT150838302S;1 24 MAR 2015


FT15093FD0P2;1 03 APR 2015
FT15104QXHTD;1 14 APR 2015
FT15089GRGKH;1 30 MAR 2015
FT15093BML3J;1 03 APR 2015
FT15083M5SSN;1 24 MAR 2015
FT150837LQQR;1 24 MAR 2015
FT150836PKCL;1 24 MAR 2015
FT1509014MCW;1 31 MAR 2015
...

// Page 68
4.6 Get account balance history

Note that sorting affects the resulting data layout:


 
SELECT FBNK.ACCT.ACTIVITY WITH @ID LIKE "10995..."
SAVING EVAL "FIELD(@ID,'-',1):';':FIELD(@ID,'-',2):';':DAY.NO:';':BALANCE"
 

21 Records selected

 
>SAVE.LIST ACT
 

21 record(s) saved to list 'ACT'

 
SELECT FBNK.ACCT.ACTIVITY WITH @ID LIKE "10995..."
SAVING EVAL "FIELD(@ID,'-',1):';':FIELD(@ID,'-',2):';':DAY.NO:';':BALANCE"
BY @ID
 

2 Records selected

 
>SAVE.LIST ACT-SORTED
 

2 record(s) saved to list 'ACT'

 
CT &SAVEDLISTS& ACT ACT-SORTED
 

ACT
001 10995;201504;01;11453030.73
002 02;11458094.98
003 03;11365993.17
004 06;11363057.06
005 07;11346375.83
006 08;11600192.31
007 09;11845509.75
008 10;11845458.37
009 13;11843702.81
010 14;11831258.2
011 15;11826883.2
012 17;12025233.2
013 20;12022297.09
014 21;12010095.7
015 22;13986696.11
016 10995;201503;24;3182275.69
017 25;3181000.69
018 26;3180840.69
019 29;1514174.02
020 30;1512981.24
021 31;1500720.73

// Page 69
ACT-SORTED
001 10995;201503;24;3182275.69]25;3181000.69]26;3180840.69]29;1514174.02
]30;1512981.24]31;1500720.73
002 10995;201504;01;11453030.73]02;11458094.98]03;11365993.17]06;11363057.06
]07;11346375.83]08;11600192.31]09;11845509.75]10;11845458.37
]13;11843702.81]14;11831258.2]15;11826883.2]17;12025233.2]20;12022297.09
]21;12010095.7]22;13986696.11

4.7 See the longest batches in the last COB:


 
LIST F.JOB.TIMES WITH
EVAL "OCONV(FIELD(@ID,'-',1),'TF.BATCH;V1;1;1')" AS Stage NE ''
Stage EVAL "EXTRACT(ELAPSED.TIME,1,1)" AS Time BY.DSND Time BY Stage
 

@ID........................................... Stage..... Time...

BNK/AA.SOD.PROCESS-AA.CREATE.NAU.ACTIVITIES D250 28
BNK/RE.BUILD.SLC-RE.UPDT.STAT.LINE.CONT R001 26
EU1/RE.BUILD.SLC-RE.UPDT.STAT.LINE.CONT R001 17
SG1/RE.BUILD.SLC-RE.UPDT.STAT.LINE.CONT R001 16
BNK/AA.EOD.PROCESS-AA.DELETE.NAU.ACTIVITIES S022 15
BNK/AA.EOD.PROCESS-AA.SERVICE.PROCESS S022 14
MF1/RE.BUILD.SLC-RE.UPDT.STAT.LINE.CONT R001 12
BNK/REPORT.PRINT.REPORTING-EB.EOD.REPORT.PRINT R999 11
BNK/TECPACK-BUILD.TECPACK O997 9
BNK/SL.END.OF.DAY-SL.EOD.PERFORM.ACCRUALS A100 7
SGP/DX.END.OF.DAY-DX.COB.CLEAR.MKT.HIST A100 7
...

4.8 See active T24 users


 
LIST F.OS.TOKEN WITH EVAL "DATE()-TIME.2" EQ 0 USER.ID
EVAL "OCONV(TIME.1,'MTS')" COL.HDR 'Logged in at' ID-SUPP
 

USER.ID............................ Logged in at.......................

VKAZIMIRCHIK 14:07:51
INPUTTER 14:06:28

2 Records Listed

// Page 70
4.9 See all active sessions in detail

Step 1. Get the location of PROC file:


 
LIST . SAMPLE 1 EVAL "SYSTEM(1027)" FMT '40L' ID-SUPP HDR-SUPP
 

C:\home\kzm\t24env\r15\TAFC\dev\PROC

Step 2. See the contents:


 
CT C:\home\kzm\t24env\r15\TAFC\dev\PROC
 

1
001 1
002 2
003 1497878701
004 3128
005 modelbank
006 modelbank
007 vt220
008 vt220
009 default
010 CONIN$
011 en_US
012 1497878771
013 0
014 26263552
015 1
016 Normal
017 49747]100000
018 127
019 322
020 22
021 6
022 0
023 12
024 329
025
026 43
027 39
028 VKAZIMIRCHIK-0
029
030
031
032 1
033 0
034 3
035 0
036 0
037 13
038 1
039
040

// Page 71
041 jsh -]CT C:\home\kzm\t24env\r15\TAFC\dev\PROC
042 111]241
043 jsh.b]jutil.copycommand.b
044
045
046 Program performing EXECUTE/PERFORM]Program running normally
047 16]11
048 71.14]0.00
049 0.00]0.00
050 0.00]0.00
051 0.00]0.00
052 ]

See jBC documentation (system functions) for record layout.

That’s all folks!

// Page 72

You might also like