I have a sequential dataset has the form of this
0000000520161103152815SHE0009 P1234561234567898765411112222 120AA
The last 2 bytes (position 71 and 72) are separate CH of either AA, AB, BA or blank. I'm trying to sort this input and create a report of sections AA, AB, BA and ignore the record that doesn't have AA, AB or BA. Each row of each section shows the teller name (SHE0009 above, position 23), and the payment (120 above, 11 bytes before AA, position 60). The final line of each section sum all the payments from that section.
Here's my code
//SHE0008 JOB
//SORTSTEP EXEC PGM=SORT
//SYSOUT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SORTIN DD DSN='SHECISC.ZEUSBANK.TXNOFFLD',DISP=SHR
//SORTOUT DD DSN=SHE0008.TESTT,
// DISP=(NEW,CATLG,DELETE),SPACE=(CYL,(10,5),RLSE)
//SYSIN DD *
SORT FIELDS=(71,1,CH,A,72,1,CH.A)
INREC BUILD=(71,1,72,1,23,8,60,11,BI,TO=ZD,LENGTH=11)
OUTFIL REMOVECC,
SECTIONS=(1,1,2,1
HEADER3=(1:C'PAYMENTS BY TELLER',/,X,/,
1:C'TRANSFER TYPE: ',1,1,2,1,/,X,/,
1:C'TELLER',10:C'PAYMENT',/,
1:C'------',10:C'-------'),
TRAILER3=(X,/,
1:C'BRANCH TOTAL: ',16:TOT=(11,11,BI,EDIT=(SIIIITTT),SIGNS=(,-)))),
TRAILER1=(X,/,1:C'GRAND TOTAL: ',TOT=(11,11,BI,
EDIT=(SIIIITTT),SIGNS=(,-))),
OUTREC=(1:7,4,CH,LENGTH=7,10:11,4,BI,EDIT=(SIIIITTT),
SIGNS=(,-))
/*
I'm getting error SORTIN - DATA SET SHECISC.ZEUSBANK.TXNOFFLD NOT FOUNDI
- STEP WAS NOT EXECUTED. Can anyone see why my dataset cannot be found and if possible is this the code that makes my desired result. Thanks.
The file name is SHECICS.ZEUSBANK.TXNOFFLD you wrote SHECISC.ZEUSBANK.TXNOFFLD.
You misspelt the first part "SHECICS" that could be the problem.
Try removing the quotes around the dataset name.
i.e. change
//SORTIN DD DSN='SHECISC.ZEUSBANK.TXNOFFLD',DISP=SHR
to
//SORTIN DD DSN=SHECISC.ZEUSBANK.TXNOFFLD,DISP=SHR
The reasoning being :-
If quotation marks delimit a data set name in a JCL DD statement, JCL
processing cannot perform syntax checking on the statement, and SMS
rejects the input based on its parsing of the data set name. SMS does
not allow the name to be catalogued because quoted data sets cannot be
SMS managed.
SMS being System Managed Storage, although I believe that the result would have been the same in pre-SMS times. If I recall correctly I also had the odd tape created with DSN=' ', (a number of spaces) which would fool quite a few people if they tried to read the tape i.e. quotes allowed you to use con-conformant dataset names.
The following my be of interest:-
Data Set Names
Character sets - Table 2. Special Characters Used in Syntax
Related
Earlier today, I changed a source-member in a PDSE in z/OS 2.2. I can see from Data Set List Utility that it was changed by me today.
Name Prompt Size Created Changed ID
MYPROGRM 50 2021/09/08 2022/07/26 11:44:03 MYUSRID
When browsing the source-member, I can see that some of the lines have a date on the far-right side of the screen, but they don't appear to be consistent. If I manually change a line, it doesn't always update that date.
RUNSTATS TABLESPACE XXXX.YYYYYY
TABLE(ALL) INDEX(ALL) 00011004
SHRLEVEL REFERENCE
Is there any way to tell what lines of my PDSE member where changed (for instance) today?
Thank you for your help!
Dave
You might be able to see what lines were changed or added but not deleted. If you have 'STATS ON' and sequence numbers on for the member you are editing, then the sequence numbers on the far right of the screen correspond to the MM values for the member:
VV.MM Version number and modification level. The version number is set
to 1 and the modification level is set to 0 when the member is
created. The modification level is the number of times this version
has been modified. For example, 02.15 means version 2, modification
15. If a member name is just an alternate name for another member, ALIAS appears in this field.
https://www.ibm.com/docs/en/zos/2.2.0?topic=statistics-member-list-display-panel-fields
The standard sequence field is the last 8 characters for fixed-length
records, or the first 8 characters for variable-length records,
regardless of the programming language. Use NUMBER ON STD to generate
sequence numbers in the standard sequence field. For members of
partitioned data sets, the format of standard sequence numbers depends
on whether statistics are being generated. If statistics are being
generated, standard sequence numbers are 6 digits followed by a
2-digit modification level number. The level number flag reflects the
modification level of the member when the line was created or last
changed. If, for example, a sequence number field contains 00040002,
the line was added or last changed at modification level 02. The
sequence number is 000400.
If STATS mode is off, or if you are editing a sequential data set,
standard sequence numbers are 8 digits, right-justified within the
field.
https://www.ibm.com/docs/en/zos/2.1.0?topic=numbers-sequence-number-format-modification-level
So if this is true for the member you are editing, and you want to know what was a changed in the last edit session, then check the Modification level of the member in question in the member display list (you may have to scroll left or right):
Name Prompt Size Init Mod VV MM ID
_________ TEST *Edited 8 7 2 01.02 JOCS065
**End**
aadn you can see the 00, 01, 02 etc. MM levels in columns 79-80
****** ***************************** Top of Data ******************************
000100 my data 00010000
000200 my data 00020000
000300 my data 00030000
000400 my data 00040000
000500 my data 00050000
000510 more data 00051001
000600 my changed data 00060002
000700 my data 00070000
****** **************************** Bottom of Data ****************************
so to see only what was last changed (useful in a large dataset), get the MM level (e.g. 45) end then, when editing, run the commands x all;f '45' 79 all
Those characters in positions 72 - 80 are not necessarily dates. They could be, but if they are it's because someone manually made that true. ISPF Edit does not enforce that.
It's more likely that at some point someone turned NUMBER ON on the member, or that some of the lines were copied from another member that at some point had NUMBER ON turned on.
To your question, it is common for HSM backups to be made of datasets when they are changed. You may be able to recover a recent backup of your PDSE to a different name and then use the compare ISPF Edit primary command to compare the two versions and determine what changed.
There is no way to tell which lines were changed by looking at the file. The number in far-right of the screen is likely a sequence number. If other lines in your file do not have similar numeric values it is likely that your profile is set to NUMEBR OFF.
To see your profile type prof command on the ISPF editor command line, it should display information similar to this:
> Command ===> prof Scroll ===> CSR
****** ***************************** Top of Data ******************************
=PROF> ....C (FIXED - 80)....RECOVERY ON....NUMBER ON STD......................
=PROF> ....CAPS OFF....HEX OFF....NULLS ON STD....TABS OFF.....................
=PROF> ....AUTOSAVE ON....AUTONUM ON....AUTOLIST OFF....STATS ON...............
=PROF> ....PROFILE UNLOCK....IMACRO NONE....PACK OFF....NOTE ON................
=PROF> ....HILITE C LOGIC PAREN CURSOR FIND MARGINS(1,72)......................
That will tell you if sequence numbers are ON or OFF. If you want to get rid of sequence numbers you can use do the following sequence of commands: num followed by unnum command, otherwse if you want sequence nymbers use just the num command.
I have 50 external EXCEL files. For each of these files, let's say #I, I import data as it follows in the SYNTAX of SPSS-statistics25:
GET DATA /TYPE=XLSX
/FILE='file#I.xlsx'
/SHEET=name 'Sheet2'
/CELLRANGE=full
/READNAMES=on
/ASSUMEDSTRWIDTH=32767.
EXECUTE.
DATASET NAME DataSet1 WINDOW=FRONT.
Then, I rank the variables included in #I file (WA CI) and I select one single case, at most, as it follows:
RANK VARIABLES= WA CI (D)
/RANK
/PRINT=YES
/TIES=LOW.
COUNT SVAR= RWA RCI (1).
SELECT IF( SVAR=2).
EXECUTE.
The task is the following:
I should print the sum of values of RWA looping on each EXCEL file #I. RWA can have value 1 or can be empty. If there are not selected cases (RWA is empty), the contribution to the sum of values should be 0. The final outcome should be the number of times RWA and RCI have the same TOP rank out of 50 Excel files.
How can I do this in a smart way?
Since I can't see the real data files, the following is a little in the dark, but I think it should be a viable strategy (you might as well try :)):
* first defining a macro to stack all the files together.
define stackFiles ()
GET DATA /TYPE=XLSX /FILE='file1.xlsx'
/SHEET=name 'Sheet2' /CELLRANGE=full /READNAMES=on /ASSUMEDSTRWIDTH=32767 /keep WA CI.
compute source=1.
exe.
dataset name gen.
!do !i=2 !to 40
GET DATA /TYPE=XLSX /FILE=!concat("'file", !i, ".xlsx'")
/SHEET=name 'Sheet2' /CELLRANGE=full /READNAMES=on /ASSUMEDSTRWIDTH=32767/keep WA CI.
compute source=!i.
exe.
add files /file=gen /file=*.
exe.
!doend.
!enddefine.
* now run the macro.
stackFiles .
* now for the rest of the analysis.
* first split the data by source file, then rank and select.
sort cases by source.
split file by source.
RANK VARIABLES= WA CI (D) /RANK /PRINT=YES /TIES=LOW.
COUNT SVAR= RWA RCI (1).
SELECT IF SVAR=2.
EXECUTE.
At this point you have up to 40 rows remaining - 0 or 1 from each original file. You can count or sum using descriptives RWA.
I am trying to add a Data step that creates the work.orders_fin_qtr_tot data set from the work.orders_fin_tot data set. This new data set should contain new variables for quarterly sales and profit. Use two arrays to create the new variables: QtrSales1-QtrSales4 and QtrProfit1-QtrProfit4. These represent total sales and total profit for the quarter (1-4). Use the quarter number of the year in which the order was placed to index into the correct variable to add either the TotalSales or TotalProfit to the new appropriate variable.
Add a Proc step that displays the first 10 observations of the work.orders_fin_qtr_tot data set.
My issue is that I can't seem to get the two diff arrays to meld with out spaces
proc sort data=work.orders_fin_tot_qtr;
by workqtr;
run;
data work.orders_fin_tot_qtr;
set work.orders_fin_tot_qtr;
array QtrSales{4} quarter1-quarter4 ;
do i = 1 by 1 until (last.order_id);
if workqtr=i then QtrSales{i}=totalsales;
end;
drop totalsales totalprofit _TYPE_ _FREQ_;
run;
proc print data=work.orders_fin_tot_qtr;
run;
The syntax last.order_id is only appropriate if there is a BY statement in the DATA Step -- if not present, the last. reference is always missing and the loop will never end; so you have coded an infinite loop!
The step has drop totalsales totalprofit _TYPE_ _FREQ_. Those underscored variables indicate the incoming data set was probably created with a Proc SUMMARY.
Your orders_fin_tot data set should have columns order_id quarter (valid values 1,2,3,4), and totalsales. If the data is multi-year, it should have another column named year.
The missing BY and present last.id indicate you are reshaping the data from acategorical vector going down a column to one that goes across a row -- this is known as a pivot or transpose. The do construct you show in the question is incorrect but similar to that of a technique known in SAS circles as a DOW loop -- the specialness of the technique is that the SET and BY are coded inside the loop.
Try adjusting your code to the following pattern
data want;
do _n_ = 1 by 1 until (last.order_id);
SET work.orders_fin_tot; * <--- presumed to have data 'down' a column for each quarter of an order_id;
BY order_id; * <--- ensures data is sorted and makes automatic flag variable LAST.ORDER_ID available for the until test;
array QtrSales quarter1-quarter4 ; * <--- define array for step and creates four variables in the program data vector (PDV);
* this is where the pivot magic happens;
* the (presumed) quarter value (1,2,3,4) from data going down the input column becomes an
* index into an array connected to variables going across the PDV (the output row);
QtrSales{quarter} = totalsales;
end;
run;
Notice there is no OUTPUT statement inside or outside the loop. When the loop completes it's iteration the code flow reaches the bottom of the data step and does an implicit OUTPUT (because there is no explicit OUTPUT elsewhere in the step).
Also, for any data set specified in code, you can use data set option OBS= to select which observation numbers are used.
proc print data=MyData(obs=10);
OBS is a tricky option name because it really means last observation number to use. FIRSTOBS is another data set option for specifying the row numbers to use, and when not present defaults to 1. So the above is equivalent to
proc print data=MyData(firstobs=1 obs=10);
OBS= should be thought of conceptually as LASTOBS=; there is no actual option name LASTOBS. The following would log an ERROR: because OBS < FIRSTOBS
proc print data=MyData(firstobs=10 obs=50);
I have a dataset that has patient data according to the site they visited our mobile clinic. I have now written up a series of commands such as freqs and crosstabs to produce the analyses I need, however I would like this to be done for patients at each site, rather than the dataset as whole.
If I had only one site, a mere filter command with the variable that specifies a patient's site would suffice, but alas I have 19 sites, so I would like to find a way to loop through my code to produce these outputs for each site. That is to say for i in 1 to 19:
1. Take the i th site
2. Compute a filter for this i th site
3. Run the tables using this filtered data of patients at ith site
Here is my first attempt using DO REPEA. I also tried using LOOP earler.
However it does not work I keep getting an error even though these are closed loops.
Is there a way to do this in SPSS syntax? Bear in mind I do not know Python well enough to do this using that plugin.
*LOOP #ind= 1 TO 19 BY 1.
DO REPEAT #ind= 1 TO 20.
****8888888888888888888888888888888888888888888888888888888 Select the Site here.
COMPUTE filter_site=(RCDSITE=#ind).
USE ALL.
FILTER BY filter_site.
**********************Step 3: Apply the necessary code for tables
*********Participation in the wellness screening, we actually do not care about those who did FP as we are not reporting it.
COUNT BIO= CheckB (1).
* COUNT FPS=CheckF(1).
* COUNT BnF= CheckB CheckF(1).
VAL LABEL BIO
1 ' Has the Wellness screening'
0 'Does not have the wellness screening'.
*VAL LABEL FPS
1 'Has the First patient survey'.
* VAL LABEL BnF
1 'Has either Wellness or FPS'
2 'Has both surveys done'.
FREQ BIO.
*************************Use simple math to calcuate those who only did the Wellness/First Patient survey FUB= F+B -FnB.
*******************************************************Executive Summary.
***********Blood Pressure.
FREQ BP.
*******************BMI.
FREQ BMI.
******************Waist Circumference.
FREQ OBESITY.
******************Glucose.
FREQ GLUCOSE.
*******************Cholesterol.
FREQ TC.
************************ Heamoglobin.
FREQ HAEMOGLOBIN.
*********************HIV.
FREQ HIV.
******************************************************************************I Lifestyle and General Health.
MISSING VALUES Gender GroupDep B8 to B13 ('').
******************Graphs 3.1
Is this just Frequencies you are producing? Try the SPLIT procedure by the variable RCDSITE. Should be enough.
SPLIT FILES allows you to partition your data by up to eight variables. Then each procedure will automatically iterate over each group.
If you need to group the results at a higher level than the procedure, that is, to run a bunch of procedures for each group before moving on to the next one so that all the output for a group will be together, you can use the SPSSINC SPLIT DATASET and SPSSINC PROCESS files extension commands to do this.
These commands require the Python Essentials. That and the commands can be downloaded from the SPSS Community website (www.ibm.com/developerworks/spssdevcentral) if you have at least version 18.
HTH,
Jon Peck
A simple but perhaps not very elegant way is to select from the menu: Data/Select Cases/If condition, there you enter the filter for site 1 and press Paste, not OK.
This will give the used filter as syntax code.
So with some copy/paste/replace/repeat you can get the freqs and all other results based on the different sites.
I have a date field which accepts system date in AS400
Display file contains a date field by *DATE
I have a physical file that has a date column.When i try saving the other fields of my screen onto this physical file,i would also like to save this system date.
But i am unable to add a field name to this inbuilt Date function.
How else can i have a date field in my display screen that will automatically accept system date and have format in DD/mm/yy format for input but internally in database it must save it as yy/mm/dd.
For the purpose of having this internal conversion in my database of date format,i have initialized a date field named "date" of length 6,Packed decimal,0 decimal position.
Please guide how to save system date from screen in this format into the physical file.
Reedited:
I have a PF of grade received date defines as follows.(Its DDS)
0004.00 A GRCVDT 6P 0
I refrain to use 'L' data type for date as i want to perform date conversion as i have above explained.
On a display file, *DATE is output-only. It cannot be read by a program.
It sounds like the database table has a decimal field called DATE; not a date field called DATE. Using a date data type will make date manipulation so much easier - see Dennis' answer for advice on that. If it is impossible to use a date data type, and you must use a decimal data type to hold the date value, look at the RPG TIME operation code. That will allow you to extract the current system date into a program variable. The exact format the date will be returned depends on your job date format setting. (WRKJOB to see that). You can use a data structure and a series of EVAL statements to rearrange the date elements if you need to.
EDIT Code sample to convert EUR to YYMMDD
d eur ds qualified
d ddmmyy 6s 0
d dd 2s 0 overlay(ddmmyy: 1)
d mm 2s 0 overlay(ddmmyy: 3)
d yy 2s 0 overlay(ddmmyy: 5)
d ymd ds qualified
d yymmdd 6s 0
d yy 2s 0 overlay(yymmdd: 1)
d mm 2s 0 overlay(yymmdd: 3)
d dd 2s 0 overlay(yymmdd: 5)
c/free
eur.ddmmyy = 020812;
ymd.yy = eur.yy;
ymd.mm = eur.mm;
ymd.dd = eur.dd;
dsply ymd.yymmdd;
*inlr = *on;
/end-free
Is this file created via DDS or SQL? If DDS, then please add the field of your choice to the DDS specs, and specify a Data Type of L:
A MYDATE L
Then use CHGPF, specifying the source file and member name; the system will add the new column.
CHGPF FILE(MYLIB/MYFILE)
SRCFILE(MYSRCLIB/MYSOURCE)
SRCMBR(MY_MBR)
Even if your file is DDS described, you could add the date column by using an SQL statement like:
alter table mytable add column mydate date not null default
(But of course, if you do that, you cannot recreate the file from DDS anymore without losing the new column)
Then in your program, just before the WRITE to the data, do:
mydate = %date
There are many assumptions here: you are using ILE, you know how to modify and recompile the program, you are using free form or can translate the "variable = value" syntax above, ...)
There are also other ways to get the system date into a file without your program having to do anything special; we actually need to know more about the application in order to help much beyond this high-level advice.