You are on page 1of 7

Deleting Duplicate Records From A TableIf you have SQL, this is possible in a few steps as long

as you have fields you can use to determine what is a duplicate. These fields would be the fields
you want to be unique in your file.

Assuming your file is named MyFile, start by creating a grouping view that includes just the key
fields and a field for COUNT(*); use a HAVING clause such as HAVING COUNT(*) > 1. Name the
view MyFileGV. This view now shows every set of keys that are duplicated (or triplicated or more).

Next, create an inner join view over MyFile and MyFileGV. Include the key fields from MyFile and
a field for RRN(MyFile). Name the new field RRNfld. Since the original table is joined to the table
of duplicate keys, you now have a view that shows all the record numbers for each duplicate.
Name this view MyFileJV.

Next, create a grouping view over MyFileJV that includes the key fields and a field for
MAX(RRNfld). This view will provide you with the highest RRN() for any of the duplicates.

So far, all you've done is create three new views. The last view tells you exactly which record
numbers to delete. A DELETE statement with a WHERE clause can then be based on this last
view to delete specific record numbers. The first time you run through the DELETE, the highest
record numbers for each duplicate will be deleted and the temporary views will all readjust
automatically. The second time you run through it, records that were originally triplicated will be
deleted. And so forth for higher multiples.

When there are no more records to delete, the temporary views will be empty.data queues and
how to useCan anyone that actually know, explain to me what are data queues, what the benefit
of using them are, and how to use them. An IBM book number would greatly be appreciated?

I am considering using them in a system we are writing at work to get our AS400 to dial out on an
asynchronous line to Transunion for credit checks. This program will be accessed by a number of
Service Reps. and I am hoping that a Data Queue Guru will shed some light on the in's and out's.

Data Queues are a cross between data areas, and message queues. They are a method for
asynchronous communication between programs. A typical use for a data queue is to have a job
sitting in a batch subsystem waiting for a data queue entry to be created, and multiple programs
dropping entries into the data queue. The ERP system my company uses has a single process to
print invoices which is triggered by entries from multiple order entry staff to the data queue.

It sounds like your application fits the bill for using data queues. There are API programs to read
and write to data queues, and they are quite straight-forward to use. If memory serves, they are
QSNDDTAQ and QRCVDTAQ, and they are well documented in the book, although I don't know
the number. If you like I can send you examples.

Benefits:
- performance can be dramatically improved over individual submits if the job is complex
- record locking conflicts are eliminated if only one job is updating.
- they can facilitate clean modular design

Drawbacks
- they are hard to document well - the next programmer will have to think to figure them out
- they can't really be audited, backed up, or for that matter conveniently examined.
- the contents are almost invisible, although smart programmers have written program to read the
queue, print the entry, and re-write it.
- Once the entry is read it is gone; if the program halts the entry is lost. This can be gotten around
with an audit file; write a record when the entry is written, nad have the receiver program update a
status field when done.

Also, data queues don't support data definition, so you do need to use data structures if you
intend to pass more than a single data element. In the example above, the data queue holds the
order to be invoiced as well as the output queue to place the spooled file and the user to notify
when it is printed.

Explaining them to a 'data queue beginner' is maybe easiest by comparing them to other objects
to see similarities and differences. Then you can get into purpose and useability.

A data queue is similar to a database file that has records written to it. One program (or many
programs) can send entries to the queue. Each entry is similar to a record. Another program (or
many programs) can read entries back from the queue, similar to reading records.

Differences to begin with are in formats (record descriptions), reading the same entries more than
once and speed.

An entry on a data queue has no external description; it's just a string of bytes. If you want
something like "fields", you'll have to do all the concatenating and sub-stringing yourself.

Normally, an entry is read only once. When the entry is read off the queue, it is gone. The first
program to read the entry gets it and then it's gone. (It's possible to get around this, but there's
seldom a reason to.)

Data queues are designed to provide fast communication between programs. You might have a
dozen programs feeding entries onto a queue and a single program receiving those entries. The
entries might represent transactions that you want performed against your database and you
don't want those dozen programs all doing it individually. You centralize the process in the
receiver program. The time it takes for an entry to be sent from one program and be received by
another is minimal, less than if you used a file to hold records.

Alternatively, you might have one program feeding entries as fast as it can onto a queue and
have a dozen programs receiving entries. By having the transactions processed by a dozen
programs, you can multiply the work being done. And since each entry is removed from the
queue when it's received, you don't have to worry about another program getting the same entry.

The speed is partially achieved by eliminating any overhead done by the system. An example is
the way the system handles the space used by a data queue as entries are added and removed.
If you start a program up to add entries to the queue but there's no program started to receive the
entries, the allocated space gets bigger. When the entries are later received and removed from
the queue, the space allocated does _not_ get smaller. You must delete and recreate the data
queue to recover excess space if want it back. This means you must know the original
parameters used to create the *DTAQ object so you can recreate one to match. (There's an API
to get this info that you can get into later.)

If you prefer, you can think of a *dtaq as being similar to a message queue. You can send
messages from one program and another can receive them from the *msgq. If you do a
RCVMSG RMV(*YES), the message is gone from the *msgq, similar to how an entry is removed
from a *dtaq. And a *dtaq entry has a format similar to a message; i.e., there's no format except
what you create yourself. (Note that MSGDTA() can be used to provide some general formatting
with a message.)

Entries are generally sent by calling the QSNDDTAQ API and received by calling the QRCVDTAQ
API. One handy use for me is in CL programs where you're limited to a single file declaration. If
you use these APIs, you can use any number of *dtaqs to simulate physical files, either for
passing info from one part of a program to another or for passing to a different program(s).

Perhaps start by creating a *dtaq with CRTDTAQ and writing a program to send some entries to
it. Then do a DMPOBJ and examine the output. Then write a second program to receive the
entries and do a second DMPOBJ. Testing it out can be done with some pretty small CLPs.

Data queue APIs are technically described for Version 4 in the OS/400 Object APIs manual on the
Systems Programming Support Bookshelf.

The data queue is a very simple concept. In your application you would have a single job that
handles credit checks. When a credit check is needed, the program talking to the service rep
sends a message to the data queue for the credit check job. This "wakes up" the waiting credit
check job and it proceeds to dial and do the credit check. When it's done it sends a message
back to a data queue for the requesting job, waking that job back up and giving it the results of
the check.

You can do various things, like have the credit check job check the incoming data queue for new
messages needing processing before hanging up the line after completing a credit check. Just
use a "dequeue but don't wait" operation in this case, vs the usual "dequeue with wait" operation.

For some reason queues are rarely used (or provided as primitives) in computer systems, even
though they are one of the most efficient and easiest to manage mechanisms for synchronizing
multi-threaded applications. Retrieving SMTP NameI want to create a cgi][ program (in RPG IV)
to create a dynamic page of all users' e-mail addresses. I haven't been able to find an API (or
command that output to a file) to retrieve SMTP names. I can use WRKNAMSMTP to display
them on screen and DSPDIRE to and outfile to retrieve proper name information, but no SMTP
name. Anyone point me in a direction?Since you put up an ILE RPG example, I thought a CLP
would be nice to compare against. Having more or less the same thing in two radically different
languages using differing techniques might make the API easier to figure out. It isn't one of the
nicer APIs to make work on your own. The CLP can be found at: http://zap.to/tl400 under
Files/View my files. The CLP accepts a system distribution directory user ID and address and
returns the associated SMTP address. It does not include any handling of the API's error code;
it's just a program I put together for my own use.
You can find all defined SMTP names in QUSRSYS/QATMSMTPA.RPGLE example for Dynamic
Screen Manager APIThere is an ILE C example for the Dynamic Screen Manager API in the book
but we need one in ILE RPG - If someone has done this yet or knows where to find on - please let
me know.I once got this sample from someone, it's definitely a good start. * * Bind with
*SRVPGM QSNAPI *D F3 c x'33'D sa_norm c x'20'D txt
s 128 inz('Press Enter to Roll, F3.')D txtlen s 9b 0 inz(32)D err s
8 inz(x'0000000000000000')D aid s 1D lines s 9b 0 inz(1)D wf1
s 1D wrtn s 9b 0D ClrScr PR 9b 0 extproc('QsnClrScr')D
mode 1 options(*nopass) constD cmdbuf 9b 0 options(*nopass)
constD env 9b 0 options(*nopass) constD error 8
options(*nopass)D WrtDta PR 9b 0 extproc('QsnWrtDta')D data 128D
datalen 9b 0D fldid 9b 0 options(*nopass) constD row
9b 0 options(*nopass) constD col 9b 0 options(*nopass) constD strmatr
1 options(*nopass) constD endmatr 1 options(*nopass) constD strcatr
1 options(*nopass) constD endcatr 1 options(*nopass) constD cmdbuf
9b 0 options(*nopass) constD env 9b 0 options(*nopass) constD error
8 options(*nopass)D GetAID PR 1 extproc('QsnGetAID')D aid 1
options(*nopass)D env 9b 0 options(*nopass) constD error 8
options(*nopass)D RollUp PR 9b 0 extproc('QsnRollUp')D lines 9b 0
constD top 9b 0 constD bottom 9b 0 constD
cmdbuf 9b 0 options(*nopass) constD env 9b 0 options(*nopass)
constD error 8 options(*nopass)C Eval wrtn = ClrScr('0' : 0 : 0 :
err)C DoW wrtn = 0C Eval wrtn = WrtDta (txt : txtlen : 0 : 23 : 2 :C
sa_norm : sa_norm : sa_norm : sa_norm :C 0 : 0 : err)C Eval wf1
= GetAID (aid : 0 : err)C If aid = F3C LeaveC EndIfC
Eval wrtn = RollUp (lines : 1 : 24 : 0 : 0: err)C EndDoC SetOn
LrC ReturnCalling APIs from CL - with
examples!/*-------------------------------------------------------------------*//* LSTMBRC - List processing for
file members - Example Pgm *//* *//* By Craig
Rutledge, 1/14/95, Version 1.0 *//* *//*
This program was done as an example of working with APIs in *//* a CL program.
*//*
*//*-------------------------------------------------------------------*//* Program Summary:
*//* *//* Initialize binary values
*//* Create user space (API CALL) *//* Load user space with member
names (API CALL) *//* Extract entries from user space (API CALL)
*//* Loop until all entries have been processed *//*
*//*-------------------------------------------------------------------*//* API (application program interfaces)
used: *//* *//* QUSCRTUS create user
space *//* QUSLMBR list file members *//*
QUSRTVUS retrieve user space *//* See SYSTEM PROGRAMMER'S
INTERFACE REFERENCE for API detail. *//*
*//*-------------------------------------------------------------------*/
PGM/*-------------------------------------------------------------------*//* $POSIT - binary fields to control
calls to APIs. *//* #START - get initial offset, # of elements, length of element.
*//*-------------------------------------------------------------------*/ DCL &$START *CHAR 4 /*
$POSIT */ DCL &$LENGT *CHAR 4 /* $POSIT */ DCL &#START *CHAR 16 DCL
&#OFSET *DEC (7 0) DCL &#ELEMS *DEC (7 0) DCL &#LENGT *DEC (7
0)/*-------------------------------------------------------------------*//* Error return code parameter for the
APIs *//*-------------------------------------------------------------------*/ DCL &$DSERR
*CHAR 256 DCL &$BYTPV *CHAR 4 DCL &$BYTAV *CHAR 4 DCL &$MSGID *CHAR
7 DCL &$RESVD *CHAR 1 DCL &$EXDTA *CHAR
240/*-------------------------------------------------------------------*//* Define the fields used by the create
user space API. *//*-------------------------------------------------------------------*/ DCL
&$SPACE *CHAR 20 ('LSTOBJR QTEMP ') DCL &$EXTEN *CHAR 10 ('TEST')
DCL &$INIT *CHAR 1 (X'00') DCL &$AUTHT *CHAR 10 ('*ALL') DCL &$APITX
*CHAR 50 DCL &$REPLA *CHAR 10
('*NO')/*-------------------------------------------------------------------*//* various other fields
*//*-------------------------------------------------------------------*/ DCL &$FORNM *CHAR 8
('MBRL0200') /* QUSLMBR */ DCL &$FIELD *CHAR 30 /* QUSRTVUS */
DCL &$MEMBR *CHAR 10 DCL &$FILLB *CHAR 20 ('QDDSSRC JCRCMDS ') DCL
&$MBRNM *CHAR 10 ('*ALL ') DCL &$MTYPE *CHAR 10 DCL &COUNT *DEC (5
0)/*-------------------------------------------------------------------*//* Initialize Binary fields and build error
return code variable *//*-------------------------------------------------------------------*/ CHGVAR
%BIN(&$START) 0 CHGVAR %BIN(&$LENGT) 50000 CHGVAR %BIN(&$BYTPV) 8
CHGVAR %BIN(&$BYTAV) 0 CHGVAR &$DSERR + ( &$BYTPV || &$BYTAV || &$MSGID ||
&$RESVD || &$EXDTA)/*-- Create user space. ---------------------------------------------*/ CALL
PGM(QUSCRTUS) PARM(&$SPACE &$EXTEN &$INIT + &$LENGT &$AUTHT &$APITX
&$REPLA &$DSERR)/*-------------------------------------------------------------------*//* Call API to load the
member names to the user space. *//*-------------------------------------------------------------------
*/ A: CALL PGM(QUSLMBR) PARM(&$SPACE &$FORNM &$FILLB + &$MBRNM '0'
&$DSERR) CHGVAR %BIN(&$START) 125 CHGVAR %BIN(&$LENGT)
16/*-------------------------------------------------------------------*//* Call API to return the starting position
of the first block, the *//* length of each data block, and the number of blocks are returned.
*//*-------------------------------------------------------------------*/ CALL PGM(QUSRTVUS)
PARM(&$SPACE &$START &$LENGT + &#START &$DSERR) CHGVAR &#ELEMS
%BIN(&#START 9 4) /* # OF ENTRIES */ IF (&#ELEMS = 0) GOTO C /* NO OBJECTS
*/ CHGVAR &#OFSET %BIN(&#START 1 4) /* TO 1ST OFFSET */ CHGVAR &#LENGT
%BIN(&#START 13 4) /* LEN OF ENTRIES */ CHGVAR %BIN(&$START) (&#OFSET + 1)
CHGVAR %BIN(&$LENGT) &#LENGT/*-------------------------------------------------------------------*//*
Call API to retrieve the data from the user space. &#ELEMS *//* is the number of data blocks
to retrieve. Each block contains a *//* the name of a member.
*//*-------------------------------------------------------------------*/ CHGVAR &COUNT 0 B: CHGVAR
&COUNT (&COUNT + 1) IF (&COUNT *LE &#ELEMS) DO CALL PGM(QUSRTVUS)
PARM(&$SPACE &$START &$LENGT + &$FIELD &$DSERR) CHGVAR &$MTYPE
%SST(&$FIELD 11 10) /* MEMBER TYPE */ CHGVAR &$MBRNM %SST(&$FIELD 1 10)
/* EXTRACT MEMBER NAME */ IF (&$MTYPE = 'PRTF ') DO /* ANZPRTFF
PRTF(&$MBRNM) SRCFILE(JCRCMDS/QDDSSRC) */ ENDDO CHGVAR &#OFSET
%BIN(&$START) CHGVAR %BIN(&$START) (&#OFSET + &#LENGT) GOTO B ENDDO
C: ENDPGM /*-------------------------------------------------------------------*//* LSTOBJC - List processing
for OBJECTS - Example Pgm *//* *//* By
Craig Rutledge, 1/03/94, Version 1.0 *//*
*//* This program was done as an example of working with APIs in *//* a CL program.
*//*
*//*-------------------------------------------------------------------*//* Program Summary:
*//* *//* Initialize binary values
*//* Create user space (API CALL) *//* Load user space with object names
(API CALL) *//* Extract entries from user space (API CALL) *//* Loop
until all entries have been processed *//*
*//*-------------------------------------------------------------------*//* API (application program interfaces)
used: *//* *//* QUSCRTUS create user
space *//* QUSLOBJ list objects *//*
QUSRTVUS retrieve user space *//* See SYSTEM PROGRAMMER'S
INTERFACE REFERENCE for API detail. *//*
*//*-------------------------------------------------------------------*/
PGM/*-------------------------------------------------------------------*//* $POSIT - binary fields to control
calls to APIs. *//* #START - get initial offset, # of elements, length of element.
*//*-------------------------------------------------------------------*/ DCL &$START *CHAR 4 /*
$POSIT */ DCL &$LENGT *CHAR 4 /* $POSIT */ DCL &#START *CHAR 16 DCL
&#OFSET *DEC (5 0) DCL &#ELEMS *DEC (5 0) DCL &#LENGT *DEC (5
0)/*-------------------------------------------------------------------*//* Error return code parameter for the
APIs *//*-------------------------------------------------------------------*/ DCL &$DSERR
*CHAR 256 DCL &$BYTPV *CHAR 4 DCL &$BYTAV *CHAR 4 DCL &$MSGID *CHAR
7 DCL &$RESVD *CHAR 1 DCL &$EXDTA *CHAR
240/*-------------------------------------------------------------------*//* Define the fields used by the create
user space API. *//*-------------------------------------------------------------------*/ DCL
&$SPACE *CHAR 20 ('LSTOBJR QTEMP ') DCL &$EXTEN *CHAR 10 ('TEST')
DCL &$INIT *CHAR 1 (X'00') DCL &$AUTHT *CHAR 10 ('*ALL') DCL &$APITX
*CHAR 50 DCL &$REPLA *CHAR 10
('*NO')/*-------------------------------------------------------------------*//* various other fields
*//*-------------------------------------------------------------------*/ DCL &$FORNM *CHAR 8
('OBJL0100') /* QUSLOBJ */ DCL &$FIELD *CHAR 30 /* QUSRTVUS */
DCL &$DEVNM *CHAR 10 /* RMT002P */ DCL &$OBJLB *CHAR 20 ('*ALL
QSYS ') DCL &$OBJTY *CHAR 10 ('*LIB ') DCL &COUNT *DEC (5
0)/*-------------------------------------------------------------------*//* Initialize Binary fields and build error
return code variable *//*-------------------------------------------------------------------*/ CHGVAR
%BIN(&$START) 0 CHGVAR %BIN(&$LENGT) 5000 CHGVAR %BIN(&$BYTPV) 8
CHGVAR %BIN(&$BYTAV) 0 CHGVAR &$DSERR + ( &$BYTPV || &$BYTAV || &$MSGID ||
&$RESVD || &$EXDTA)/*-- Create user space. ---------------------------------------------*/ CALL
PGM(QUSCRTUS) PARM(&$SPACE &$EXTEN &$INIT + &$LENGT &$AUTHT &$APITX
&$REPLA &$DSERR)/*-------------------------------------------------------------------*//* Call API to load the
object names to the user space. *//*-------------------------------------------------------------------*/
A: CALL PGM(QUSLOBJ) PARM(&$SPACE &$FORNM &$OBJLB + &$OBJTY &$DSERR)
CHGVAR %BIN(&$START) 125 CHGVAR %BIN(&$LENGT)
16/*-------------------------------------------------------------------*//* Call API to return the starting position
of the first block, the *//* length of each data block, and the number of blocks are returned.
*//*-------------------------------------------------------------------*/ CALL PGM(QUSRTVUS)
PARM(&$SPACE &$START &$LENGT + &#START &$DSERR) CHGVAR &#ELEMS
%BIN(&#START 9 4) /* # OF ENTRIES */ IF (&#ELEMS = 0) GOTO C /* NO OBJECTS
*/ CHGVAR &#OFSET %BIN(&#START 1 4) /* TO 1ST OFFSET */ CHGVAR &#LENGT
%BIN(&#START 13 4) /* LEN OF ENTRIES */ CHGVAR %BIN(&$START) (&#OFSET + 1)
CHGVAR %BIN(&$LENGT) &#LENGT/*-------------------------------------------------------------------*//*
Call API to retrieve the data from the user space. &#ELEMS *//* is the number of data blocks
to retrieve. Each block contains a *//* the name of a object and information about that object.
*//*-------------------------------------------------------------------*/ CHGVAR &COUNT 0 B: CHGVAR
&COUNT (&COUNT + 1) IF (&COUNT *LE &#ELEMS) DO CALL PGM(QUSRTVUS)
PARM(&$SPACE &$START &$LENGT + &$FIELD &$DSERR) CHGVAR &$DEVNM
%SST(&$FIELD 1 10) /* EXTRACT DEVICE NAME */ /* INSERT CODE HERE */ CHGVAR
&#OFSET %BIN(&$START) CHGVAR %BIN(&$START) (&#OFSET + &#LENGT) GOTO B
ENDDO C: ENDPGM/ Compare two strings in RPG character by characterNow I want to
compare two strings letter by letter using RPG.Example:

'America' and 'American'

Who knows any function I can implement this(except %scan)? Answer(s):I'm not sure what you
want to achieve, but to compare two fields character-by-character you could use the following
code: (sample definitions)D FIELD1 S 999D FIELD2 S 999D LENGTH
S 3 0 INZ(%SIZE(FIELD1))D INDEX S + 2 LIKE(LENGTH)C 1
DO LENGTH INDEXC IF %SUBST(FIELD1:INDEX:1) =C
%SUBST(FIELD2:INDEX:1)...(your code - you might want to leave the loop using the LEAVE op-
code)...C ENDIFC ENDDO Why can't you just compare them?

IF Field1=Field2? If Field1 is 7 char long and Field2 is 8 char long, RPG will test with the greatest
length padded with blanks so you will test : "America " (with a blank) = "American" and that's
false.

See http://publib.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/QB3AGZ00/4.3.6. How about If


Trim(Field1) = Substr(Field2,Len(Field1)) Then Shouldn't it be If Trim(Field1) =
Substr(Field2,Len(trim(Field1))) ??
But they don't match... with or without the blank...so I don't see the point.

Unless you want If Str1 = %SubSt(Str2:1:%Len(%Trim(Str1))


you could use the c function strcmp D strcmp PR 10I 0 ExtProc('strncmp')D
s1 1000 ValueD s2 1000 Value

To use this you would have to terminate the string with nulls C Eval rc =
strcmp(s1+x'00':s2+x'00) But using strcmp gives the exact same answer as comparing the strings
in RPG, only in a slower and more complicated way.

By the way, Mike, your prototype for strcmp won't work. > D strcmp PR 10I 0 ExtProc('strncmp') >
D s1 1000 Value > D s2 1000 Value

It should be one of these (two ways to fix the parameters + two different functions (strcmp takes 2
parms, strncmp takes 3) D strcmp PR 10I 0 ExtProc('strcmp') D s1
1000 Const D s2 1000 Const D strcmp PR 10I 0
ExtProc('strcmp') D s1 * Value options(*string) D s2
* Value options(*string)OPTIONS(*STRING) isn't strictly necessary. D strcmp PR
10I 0 ExtProc('strncmp') D s1 1000 Const D s2 1000
Const D len 10u 0 Value D strcmp PR 10I 0
ExtProc('strncmp') D s1 * Value options(*string) D s2
* Value options(*string) D len 10u 0 ValueHow to search all pgms in
QCLSRC for a keywordI have to change TAP03 to TAP01 in every CL. To avoid forgetting one,
I'm looking for a tool to search all members of QCLSRC and list where it occurs. Anybody knows
one?Use option 25 against the file in PDM. This gives you the find string screen. You can set the
option in this screen to 2 to bring up any matched source in edit mode. I cant remember, but I
think that if you set up your replace options before using this, you can just do replace once the
source is displayed. You can sbmjob the following command:
FNDSTRPDM STRING(TAP03) FILE(Your_source_lib/QCLSRC)
MBR(*ALL) OPTION(*NONE)PRTMBRLIST(*YES) And before doing this, create a data area to
store the device name in. Then when you locate every occurrence in every CL, change the CLs to
get the device from the data area rather than hard-coding it into the programs. Next time you
have to change the device name, just change the data area.Using Multiformat Logical To Join 2
Identical FileI have two identical files except for their object names. One is a current production
file, the other is a history file with last years data. Of course, I need a program that use these two
files as one. But, I can't seem to get a Join Logical to compile. Keeps running into duplicate field
and key field names.

Is there anyway to do this?Answer(s):

Don't try to use Join Logical file, use Multiple Record Logical files.

The funny thing is, this is a vendor file that used to be multiple formats for each year but in their
Y2K version they changed it. Why? Beats me!

Any ways, sorry if I am a little dense here. Could you give me an example of two identical files
using the same logical with mulitple records?

Here an example of a multiformat logical file : A R FORMAT1 PFILE(FILE1)A


FIELD1A FIELD2....A K FIELD1A*A R FORMAT2 PFILE(FILE2)A
FIELD1A FIELD2....A K FIELD1
In the program, you can chain with the file name and you'll get records from both physical files, or
the format name and you'll get records only from the specifc PFILE. If you want to update or write
a record with this logical file, you must use the format name.
Classification: GE Public

You might also like