Last time I used SAS was when it was in version 5.x. My company's current version is 9.3 and since I'm the only one available with any SAS history, I'm suddenly the "expert". A lot has changed but I have the programmer's bookshelf and existing code for examples. My problem, for which I would be most grateful for a solution, is that I can't seem to "format" an INPUTted binary value into a CHAR value and assign it to a CHAR var, and make the CHAR var stay as a CHAR var. To wit:
DATA _NULL_;
INFILE SYSRECIN END=FILE_EOF;
INPUT @01 REC $CHAR3676.;
ORD_NO_BIN = INPUT(SUBSTR(REC,1,4),IB4.);
ORD_NO_TYP = SUBSTR(REC,5,1);
ORD_NO_CHK_DGT = SUBSTR(REC,6,1);
ORD_SEQ_NO = INPUT(SUBSTR(REC,7,2),IB2.);
ORD_TX_LEN = INPUT(SUBSTR(REC,9,2),IB2.);
ORD_TX = SUBSTR(REC,11,ORD_TX_LEN);
ORD_NO_7 = PUTC(ORD_NO_BIN,7.); [this and 2 dozen other ways to force ORD_NO_BIN to a CHAR value have failed]
ORD_NO_CURR = ORD_NO_TYP || ORD_NO_7|| ORD_NO_CHK_DGT;
FILE SASLIST;
PUT ORD_NO_CURR= ;
...
My output recs can be as much as 2000 or more characters long, when each row of output should be exactly 9 characters. An example DESIRED output line might look like:
C12345678
Where the C is ORN_NO_TYP and 8 is ORD_NO_CHK_DGT. 1234567 is the binary/integer numeric input, stored on the input file as 4 bytes, and limited to a maximum value of '0098967F'X (which is 9999999 in decimal).
What I'm actually getting, using the above ideal example of C12345678, is:
C[anything from 300 or so spaces up to a few thousand]8
I've tried PUT() and PUTC() with various combinations of $CHAR7, $7, $Z7, etc. I've tried converting the input to a combination of INPUT with PUT(SUBSTR()). Above, you see my latest attempt at using a completely new (and otherwise useless) variable in an attempt to force the numeric value in ORD_NO_BIN to a char value in a new char var, ORD_NO_7.
My goal is not the printing of ORD_NO_CURR. I'm printing to help debug the problem. My goal is to assemble all 3 parts of an Order Number into a single character variable that I can use later in the program. I have verified that if I actually PUT ORD_NO_CURR to a real output file, it shows up in the file the same way it shows up in print.
Please, can someone suggest how I can get the input 4-byte binary value of ORD_NO_BIN to become a 7-byte character variable (and STAY a char var) until I can concatenate it with the other 2 parts into a single Order Number variable, ORD_NO_CURR?
Thanks a lot! SAS has changed a whole lot since the last time I used and I just don't seem to be able to find my way around...
Richard
Richard,
A few issues off the top of my head ...
First, when SUBSTR creates a new variable, the length it assigns is the same as the length of the incoming string. Add this early in the DATA step:
length ord_no_typ $ 1;
Next, use PUT instead of PUTC. PUTC is only needed when the format being utilized (the second parameter, here it's 7.) is an expression rather than being hard-coded.
When you read with IB4., I would think you need 9 characters rather than 7 to hold the largest possible value. Unless you know that the values will not be that large, switch from 7. to 9. to convert.
You might be able to get around some of these issues by reading the data directly into your variables, such as:
input @1 REC $char3676.
@1 ORD_NO_BIN IB4.
@5 ORD_NO_TYPE $1.
@6 ORD_NO_CHK_DGT $1.
etc.
You might need ORD_NO_CHK_DGT as numeric, but not from the section of code that you posted here. If you concatenate numeric strings using the concatenation double bars, SAS has to convert it to character and adds leading blanks. There have also been concatenation functions added to the software since you last used it, that might come in handy here (CAT, CATS, CATX).
I imagine this gives you enough to get started. Good luck.
Richard,
A few issues off the top of my head ...
First, when SUBSTR creates a new variable, the length it assigns is the same as the length of the incoming string. Add this early in the DATA step:
length ord_no_typ $ 1;
Next, use PUT instead of PUTC. PUTC is only needed when the format being utilized (the second parameter, here it's 7.) is an expression rather than being hard-coded.
When you read with IB4., I would think you need 9 characters rather than 7 to hold the largest possible value. Unless you know that the values will not be that large, switch from 7. to 9. to convert.
You might be able to get around some of these issues by reading the data directly into your variables, such as:
input @1 REC $char3676.
@1 ORD_NO_BIN IB4.
@5 ORD_NO_TYPE $1.
@6 ORD_NO_CHK_DGT $1.
etc.
You might need ORD_NO_CHK_DGT as numeric, but not from the section of code that you posted here. If you concatenate numeric strings using the concatenation double bars, SAS has to convert it to character and adds leading blanks. There have also been concatenation functions added to the software since you last used it, that might come in handy here (CAT, CATS, CATX).
I imagine this gives you enough to get started. Good luck.
Can we see some relevant log output?
Insert the line Put _ALL_ ; in your code so all the variables are dumped.
To note: PUTC () requires a character input, and if ORD_NO_BIN is already numeric, SAS will do a default numeric to character conversion using BEST12. format. But the function will then fail because the next parameter should be the name of a character format.
The correct statement would be either
ORD_NO_7 = PUTN(ORD_NO_BIN,"Z7");
or
ORD_NO_7 = PUT(ORD_NO_BIN,Z7.);
If you have tried either of these, without success, then there is something wrong in your input data.
As I say, SHOW ME THE LOG!
Richard in Oz
Just one extra point to add to what has already been suggested: Since you are reading 3,676 characters, I think you will need to add an lrecl option to your infile statement.
Thanks Arthur. This is running on a Z/OS machine (MVS) so I'm thinking this is taken care of inside JES and the FCB information it assigns the file files. At least I'm not seeing any truncation problem, but I'll keep this in mind if I should notice a short record. So far, my test records are all under 1800 bytes, but they can go up to 3676 in production mode (that takes a huge amount of details on an order, which has been amended at least 4 times) We see this maybe once per year.
A customer wants 3 landline phones installed in 3 different houses, 6 cell phones, different data plans on each, different features on each, etc, and changes his mind 4 or 5 times over a week before saying, "Yes, that's what I want. Install it." It's rare to get this complex of a service order, and therefore rare to get somthing more than 1800 bytes.
But I'll create a test record at full length and see what happens. Thanks for the heads-up.
Richard
Astounding,
Thanks for the thump on the noggin'
Yeah, I changed all the INPUT() functions with SUBSTR() usage so they were part of the preceding INPUT statement. Also changed the PUTC() to PUT(). Ran like a champ and got my desired output with no other changes than what I presented here.
Though I've been away from SAS for 15-20 years, I should have known to simplify the initial values in my data segement this way. Less work and more accurate results to do things the right way! :smileyblush:
Yeah, I don't need ORD_NO_CHK_DGT to be numeric. I'm just trying to convert, from a scrambled mess of data on disc, to a consistant, purely character string Order Number. Lots of other things going on in the program, but I don't deal with the individual parts of an order number except what I showed above, and just to assmeble them into a char var for later use.
RichardinOz,
Thanks for showing me the PUTN() option. I would never have thought of enclosing the parm in quotes for this one. I'll remember this for the future. Looks like I'm going to be working with SAS again for the forseeable future. Probably ought to get certified (and get the education behind it).
Thanks to all!
Richard
Normally you would just use the PUT() function as a one size fits all solution - it handles both character and numeric inputs seamlessly.
PUTC() and PUTN() are really only necessary if you need to vary the format on the fly, which in my experience is extremely rare.
However, you do need to use them in Macro statements
eg
%Let number_formatted = %Sysfunc(PUTN(&numeric_expression, Z9)) ;
But that's for another day.
A couple of things to remember with PUT() and INPUT():
Richard in Oz
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.