Overview of the IMS DATA Step Interface |
Introduction to the DL/I INPUT Statement |
If you are unfamiliar with the INPUT statement, refer to SAS Language Reference: Dictionary for more information.
An INPUT statement reads from the file that is specified by the most recently executed INFILE statement. If the INFILE statement is a DL/I INFILE statement, the INPUT statement issues a DL/I get call and retrieves a segment or segments.
There are no special options for the DL/I INPUT statement as there are for the DL/I INFILE statement. The form of the DL/I INPUT statement is the same as that of the standard INPUT statement:
input variable optional-specifications;
For example, suppose you are issuing a qualified get call for the CUSTOMER segment. The DL/I INPUT statement might be coded like this:
input @1 soc_sec_number $char11. @12 customer_name $char40. @52 addr_line_1 $char30. @82 addr_line_2 $char30. @112 city $char28. @140 state $char2. @142 country $char20. @162 zip_code $char10. @172 home_phone $char12. @184 office_phone $char12.;
When this DL/I INPUT statement executes, DL/I retrieves a CUSTOMER segment and places it in the input buffer. Data for the variables specified in the DL/I INPUT statement is then moved from the input buffer to SAS variables in the program data vector by SAS.
Different forms of the INPUT statement can have different results:
When an INPUT statement specifies variable names (as in the previous example), the segment is usually retrieved and placed in the input buffer and the values are moved immediately to SAS variables in the program data vector unless this form of the INPUT statement is preceded by an INPUT statement with a trailing @ sign, for example, input@ . The INPUT statement with a trailing @ sign is described below.
If the INPUT statement does not specify any variable names or options, as in this example:
input;
a segment or segments are retrieved by the call and placed in the input buffer but no data is mapped to the program data vector. Or, if the previous INPUT statement was input@ , this clears the hold.
If the INPUT statement does not specify variable names but does have a trailing @:
input @;
a call is issued and one or more segments are retrieved and placed in the input buffer. The trailing @ tells SAS to use the data just placed in the input buffer when the next DL/I INPUT statement in that execution of the DATA step is executed. In other words, the trailing @ tells SAS not to issue another call the next time a DL/I INPUT statement is executed. Instead, SAS uses the data that is already in the input buffer. This form of the INPUT statement is very useful in IMS DATA step programs. Refer to Using the DL/I INPUT Statement for more information.
You can combine the form that names variables with the form that uses a trailing @. In this example, a call is issued, a segment is retrieved and placed in the input buffer, and values for the named variables are moved to SAS variables in the program data vector:
input soc_sec_number $char11. @;
Because of the trailing @, SAS holds the segment in the input buffer for the next INPUT statement.
Although the syntax of the DL/I INPUT statement and the standard INPUT statement are the same, your use of the DL/I INPUT statement is often different. Suggested uses of the DL/I INPUT statement are discussed in Using the DL/I INPUT Statement.
Example 1: A Get Call |
The following DATA step illustrates how to issue get calls using the DL/I INFILE and DL/I INPUT statements:
data custchck; retain ssa1 'CUSTOMER*D ' ssa2 'CHCKACCT '; infile acctsam dli ssa=(ssa1,ssa2) status=st pcbno=3; input @1 soc_sec_number $char11. @12 customer_name $char40. @52 addr_line_1 $char30. @82 addr_line_2 $char30. @112 city $char28. @140 state $char2. @142 country $char20. @162 zip_code $char10. @172 home_phone $char12. @184 office_phone $char12. @226 check_account_number $char12. @238 check_amount pd5.2 @243 check_date mmddyy6. @251 check_balance pd5.2; if st ¬= ' ' then do; file log; put _all_; abort; end; run; proc print data=custchck; title2 'Customer Checking Accounts'; run;
This DATA step creates a SAS data set, CUSTCHCK, with one observation for each checking account in the ACCTDBD database. To build the data set, the program issues qualified get-next path calls using unqualified SSAs for the CUSTOMER and CHCKACCT segments. The path call is indicated by the *D command code in the CUSTOMER SSA, SSA1. The PCBNO= option specifies the first eligible PCB that permits path calls for the CUSTOMER segment of the ACCTDBD database.
The DL/I INFILE statement points to the ACCTSAM PSB and specifies two SSA variables, SSA1 and SSA2. The SSA variables have already been assigned values and lengths by the preceding RETAIN statement. Since these SSAs are not qualified, the program access is sequential. In this get call, the status code is checked and the third PCB is specified. Defaults are in effect for the other DL/I INFILE options: only get-next calls are issued, the input buffer length is 1000 bytes, and segment names and PCB mask data are not returned.
When the DL/I INPUT statement executes and status = ' ' , the qualified GN call is issued, the concatenated CUSTOMER and CHCKACCT segments are placed in the input buffer, and data from both segments are moved to SAS variables in the program data vector.
The following output shows the results of this example.
The SAS System Customer Checking Accounts soc_sec_ addr_ OBS number customer_name line_1 addr_line_2 city state 1 667-73-8275 WALLS, HOOPER J. 4525 CLARENDON RD RAPIDAN VA 2 667-73-8275 WALLS, HOOPER J. 4525 CLARENDON RD RAPIDAN VA 3 434-62-1234 SUMMERS, MARY T. 4322 LEON ST. GORDONSVILLE VA 4 436-42-6394 BOOKER, APRIL M. 9712 WALLINGFORD PL. GORDONSVILLE VA 5 434-62-1224 SMITH, JAMES MARTIN 133 TOWNSEND ST. GORDONSVILLE VA 6 434-62-1224 SMITH, JAMES MARTIN 133 TOWNSEND ST. GORDONSVILLE VA 7 178-42-6534 PATTILLO, RODRIGUES 9712 COOK RD. ORANGE VA 8 156-45-5672 O'CONNOR, JOSEPH 235 MAIN ST. ORANGE VA 9 657-34-3245 BARNHARDT, PAMELA S. RT 2 BOX 324 CHARLOTTESVILLE VA 10 667-82-8275 COHEN, ABRAHAM 2345 DUKE ST. CHARLOTTESVILLE VA 11 456-45-3462 LITTLE, NANCY M. 4543 ELGIN AVE. RICHMOND VA 12 234-74-4612 WIKOWSKI, JONATHAN S. 4356 CAMPUS DRIVE RICHMOND VA check_ account_ check_ check_ check_ OBS country zip_code home_phone office_phone number amount date balance 1 USA 22215-5600 803-657-3098 803-645-4418 345620145345 1702.19 12857 1266.34 2 USA 22215-5600 803-657-3098 803-645-4418 345620154633 1303.41 12870 1298.04 3 USA 26001-0670 803-657-1687 345620104732 826.05 12869 825.45 4 USA 26001-0670 803-657-1346 345620135872 220.11 12868 234.89 5 USA 26001-0670 803-657-3437 345620134564 2392.93 12858 2645.34 6 USA 26001-0670 803-657-3437 345620134663 0.00 12866 143.78 7 USA 26042-1650 803-657-1346 803-657-1345 745920057114 1404.90 12944 1502.78 8 USA 26042-1650 803-657-5656 803-623-4257 345620123456 353.65 12869 463.23 9 USA 25804-0997 803-345-4346 803-355-2543 345620131455 1243.25 12871 1243.25 10 USA 25804-0997 803-657-7435 803-645-4234 382957492811 7462.51 12876 7302.06 11 USA 26502-3317 803-657-3566 345620134522 608.24 12867 831.65 12 USA 26502-5317 803-467-4587 803-654-7238 345620113263 672.32 12870 13.28
Refer to Example 6: Issuing Path Calls later in this section for a detailed explanation of a sample IMS DATA step program that includes a similar DATA step.
Using the DL/I INPUT Statement |
A get call might or might not successfully retrieve the requested segments. For each call issued, DL/I returns a status code that indicates whether the call was successful. Since the success of a call can affect the remainder of the program, it is a good idea to check status codes, especially in programs that use random access. You can obtain the status code returned by DL/I with the STATUS= option or the PCBF= option of the DL/I INFILE statement. Refer to your IBM documentation for explanations of DL/I status codes.
In general, a call has been successful and the segment(s) has been obtained if the automatic SAS variable _ERROR_ has a value of zero. This corresponds to a blank DL/I return code, or codes of CC , GA , or GK . SAS sets _ERROR_ to 1 if any other DL/I status code is returned or if the special SAS status code SE is returned. (The SE code is generated when SAS cannot format a proper DL/I call from the options specified.) If _ERROR_ is set to 1, the contents of the input buffer and the program data vector are printed on the SAS log when another INPUT statement is executed or when control returns to the beginning of the DATA step, whichever comes first.
Some of the DL/I status codes that set _ERROR_ might not be errors to your SAS program. When this is the case, you should check the actual return code as well as the value of _ERROR_. For example, suppose you are writing a program that looks for a segment with a particular value for a sequence field. If the segment is found, a replace call (REPL) is issued to update the segment. If the segment is not found, _ERROR_ is set to 1, but you do not consider the status code to be an error. Instead, you issue an insert call (ISRT) to add a new segment.
If a status code sets _ERROR_ but you do not consider the status code to be an error, you should reset _ERROR_ to zero before executing another INPUT or PUT statement or returning to the beginning of the DATA step. Otherwise, the contents of the input buffer and program data vector are printed on the SAS log.
You can use different forms of the DL/I INPUT statement to perform these general functions:
move data from the input buffer to SAS variables in the program vector if variables are named in the INPUT statement.
In some programs, it is important to check the values of the _ERROR_ or STATUS= variables before moving data from the input buffer to SAS variables in the program data vector. For example, if a get call fails to retrieve the expected segment, the input buffer might still contain data from a previous get call or be filled with missing values. You might not want to move these values to SAS variables. By checking the STATUS= or _ERROR_ variable, you determine whether the call was successful and can decide whether to move the input buffer data to SAS variables.
Similarly, if you issue unqualified get calls with a PCB that is sensitive to more than one segment type, you might need to know what type of segment was retrieved in order to move data to the appropriate SAS variables.
When you want to issue a get call but you need to check _ERROR_ or STATUS= variable values before moving data to SAS variables, use a DL/I INPUT statement with a trailing @ to issue the call:
input @;
The trailing @ pointer control causes SAS to hold the current record (segment) in the input buffer for the next DL/I INPUT statement. The next DL/I INPUT statement to be executed does not issue another call and does not place a new segment in the input buffer. Instead, the second INPUT statement uses the data placed in the input buffer by the first INPUT statement.
If no variables are named in the first DL/I INPUT statement (as in the statement shown in the previous paragraph), data is not moved from the buffer to SAS variables until another DL/I INPUT statement specifying the variables is executed. Therefore, before executing a second INPUT statement, you can check the value of the STATUS= or PCBF= variable to determine whether the call was successful. You can also check the _ERROR_ automatic variable and the SEGMENT= variable. After checking these values, execute a second DL/I INPUT statement to move data to SAS variables, if appropriate.
This example demonstrates the use of the trailing @. This DATA step creates two SAS data sets, CHECKING and SAVINGS, from data in the CHCKACCT and SAVEACCT segments of the ACCTDBD database. The PCB that is used defines CUSTOMER, CHCKACCT, and SAVEACCT as sensitive segments. Since no CALL= or SSA= variables are specified, all calls are unqualified get-next calls, and access is sequential.
Each call is issued by a DL/I INPUT statement with a trailing @, so the retrieved segment is placed in the buffer and held there. Two variables are checked: ST and SEG (the SEGMENT= variable). If a call results in an error, the job terminates. If a call is successful, the program checks SEG to determine the type of the retrieved segment. Because this is a sequential access program, a GB (end-of-file) status code is not treated as an error by the program. Therefore, the program resets _ERROR_ to 0.
When SEG='CUSTOMER', execution returns to the beginning of the DATA step. When the SEG value is CHCKACCT or SAVEACCT, another DL/I INPUT statement moves the data to SAS variables in the program data vector, and the observation is written to the appropriate SAS data set.
data checking savings; infile acctsam dli segment=seg status=st pcbno=3; input @; if st ¬= ' ' and st ¬= 'CC' and st ¬= 'GA' and st ¬= 'GK' then do; file log; put _all_; abort; end; if seg = 'CUSTOMER' then return; else do; input @1 account_number $char12. @13 amount pd5.2 @18 date mmddyy6. @26 balance pd5.2; if seg = 'CHCKACCT' then output checking; else output savings; end; run; proc print data=checking; title2 'Checking Accounts'; run; proc print data=savings; title2 'Savings Accounts'; run;
The following output shows the results of this example:
Results of Using the Trailing @
The SAS System Checking Accounts account_ OBS number amount date balance 1 345620145345 1702.19 12857 1266.34 2 345620154633 1303.41 12870 1298.04 3 345620104732 826.05 12869 825.45 4 345620135872 220.11 12868 234.89 5 345620134564 2392.93 12858 2645.34 6 345620134663 0.00 12866 143.78 7 745920057114 1404.90 12944 1502.78 8 345620123456 353.65 12869 463.23 9 345620131455 1243.25 12871 1243.25 10 382957492811 7462.51 12876 7302.06 11 345620134522 608.24 12867 831.65 12 345620113263 672.32 12870 13.28 The SAS System Savings Accounts account_ OBS number amount date balance 1 459923888253 784.29 12870 672.63 2 345689404732 8406.00 12869 8364.24 3 144256844728 809.45 12863 1032.23 4 345689473762 130.64 12857 261.64 5 345689498217 9421.79 12858 9374.92 6 345689462413 950.96 12857 946.23 7 345689435776 136.40 12869 284.97 8 859993641223 845.35 12860 2553.45 9 884672297126 945.25 12868 793.25 10 345689463822 929.24 12867 924.62
Note: If the DL/I call is issued by a DL/I INPUT statement with a trailing @ and the status code sets _ERROR_, but you do not consider the status code to be an error and you want to issue another get call in the same execution of the DATA step, then you must first execute a blank DL/I statement: input;
The blank DL/I INPUT statement clears the input buffer. If the buffer is not cleared by issuing a blank INPUT statement, the next DL/I INPUT statement assumes that the data to be retrieved is already in the buffer and does not issue a DL/I call. See Example 8: Using the Blank INPUT Statement for an example that includes a blank INPUT statement.
Copyright © 2007 by SAS Institute Inc., Cary, NC, USA. All rights reserved.