BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
richard_naff
Calcite | Level 5

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

1 ACCEPTED SOLUTION

Accepted Solutions
Astounding
PROC Star

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.

View solution in original post

6 REPLIES 6
Astounding
PROC Star

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.

RichardinOz
Quartz | Level 8

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

art297
Opal | Level 21

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.

richard_naff
Calcite | Level 5

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

richard_naff
Calcite | Level 5

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

RichardinOz
Quartz | Level 8

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():

  1. PUT() always outputs a character expression.  If the input value is numeric, you need a numeric format, and vice versa
  2. INPUTN() always requires a character expression input.  If the required output is numeric, you need a numeric informat etc.
  3. If you "break" these rules SAS does type conversion either by trying to substitute a format of the correct type, or by doing a type conversion of the input for INPUT().

Richard in Oz

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 6 replies
  • 1335 views
  • 6 likes
  • 4 in conversation