Building an ISPF table is done by the TBCREATE service. The table may or may not have a key or keys. The table may or may not have one or more name (data) fields. It will almost certainly have at least one of either, but 'almost' is not 'absolutely'. In fact, an ISPF table may be TBCREATED with no specifically-named fields at all... but you had better know what in Hell you are doing in that case. Very likely, before doing so, you would very definitely know what you had in mind. The uses for an 'extension-variables-only' table are breathtakingly esoteric.
"TBCREATE" table_name "KEYS(" key_field_names ")", "NAMES(" data_field_names ")" other_table_qualities "TBCREATE TEMP [ KEYS() NAMES() ] WRITE REPLACE"
To populate a new table row, each of the named fields, whether KEYS or NAMES, is assigned a value (or not — more later) and the TBADD service is called. The row is created with all KEYS and NAMES fields, whether populated or not, plus all extension variables referenced by the SAVE parameter. Extension variables are potentially unique to each row, and are only loaded to the table if specifically requested in the TBADD/TBMOD service call.
"TBCREATE ZORK KEYS(INDEX OFFSET) NAMES(PLACE TYPE VALUE)" index = index + 1 /* OFFSET not populated */ place = left type = normal value = total oper = userid() time = Date("S") Time("N") "TBADD ZORK SAVE(OPER TIME)"
This added one row to table ZORK. All fields except OFFSET have values, and there are two extension variables, OPER and TIME, which are not part of the canonical definition. There is a field for OFFSET, but it is null, and here null has a different meaning than it does in REXX. Here, it means: doesn't exist.
That's it. That's all there is to populating a table. Updates to the table thereafter can be done via TBADD (for new rows) or TBMOD (for replacement rows — or new rows if the key does not presently exist).