SAS Viya Studio version: V.03.05
My understanding is that in CAS, a persisted .sashdat format file should be usable directly as a format without needing to recreate the original SAS PROC FORMAT definitions.
I suspect that the issue on my end may be due to administrative restrictions or configuration settings imposed by our SAS administrator.
Assuming no such restrictions are in place, I’m seeking guidance on what the expected process or solution should be to enable the use of persisted .sashdat format files as formats in CAS as intended.
I have studied and broken down (or attempted to) these various resources.
SAS Help Center: SAS Cloud Analytic Services 3.5: User-Defined Formats
SAS Help Center: Migrate User-Defined Formats from SAS to CAS
SAS Help Center: User-Defined Format Basics
SAS Viya CAS Format library persistence
Importing User-defined Formats to CAS in the SAS Viya Platform
https://www.youtube.com/watch?v=uC-Z5moTX9k
I’ve outlined my inquiry in 9 steps to provide full context. While steps 1–4 are foundational, they help set the stage for the more substantive points that follow.
Step 5 demonstrates empirically that SAS formats can be used within CAS.
Steps 6–7 result in the creation of a persisted .sashdat format file.
Steps 8–9, after initiating a new CAS session, attempt to use that persisted .sashdat file as a format within CAS.
I realize the explanation may seem verbose, but I wanted to ensure the context is clear. I appreciate any guidance or suggestions from those familiar with this process.
Please see full code with all relevant annotations.
/* connect to CAS + set-up libref for caslib */
cas CASauto sessopts=(caslib='CASuser');
libname CASuser cas caslib=CASuser;
/* 1) list and delete SAS formats <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> */
/* a) list all Custom formats */
proc catalog catalog=work.formats ;
contents out=format_catalog;
quit;
proc print data=format_catalog noobs; run;
/* b) delete all Custom formats from work.formats catalog*/
proc datasets library=work nolist;
delete formats / memtype=catalog;
quit;
/* 2) list and delete CAS formats <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> */
/* a) list all formats in all CAS libraries */
cas casauto listformats MEMBERS;
/* b) list all formats in the CAS library CASFormats */
cas casauto listformats fmtlibname=CASFormats SCOPE=BOTH /*GLOBAL|SESSION|BOTH*/ MEMBERS;
/* c) drop all formats in the CAS library CASFormats */
cas casauto dropfmtlib fmtlibname=CASFormats fmtsearchremove;
/* >>> using CAS action */
proc cas;
sessionProp.dropFmtLib /
fmtLibName='CASFormats'
fmtSearchRemove = TRUE;
quit;
/* 3) list and delete CAS .sashdat files <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> */
/* a) check for .sashdat files in CASuser*/
proc cas;
table.fileinfo
caslib='CASuser';
quit;
/* b) delete all files from CASuser (assuming some are persisted .sashdat format files) */
proc cas;
table.fileinfo result=r
caslib='CASuser';
do i = 1 to dim(r.fileInfo);
File_Name = r.fileinfo[i].Name;
table.deleteSource
caslib='CASuser'
source=File_Name;
end;
quit;
/* 4) create simple SAS data set + simple SAS format + apply SAS format <><><><><><><><><><><><><><><><><><><><><><>
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> */
/* a) raw data */
data raw;
infile datalines;
input var1 var2;
datalines;
1 10
2 10
;
/* b) create SAS only format */
proc format; /* <<< lib=work.formats is implicit*/
value frmt
1 = 'abc';
run;
/* ########## re-run 1a) to validate format exists in SAS
Result: LIBNAME: Work MEMNAME: FORMATS NAME: FRMT */
/* c) apply SAS only format to SAS Data Set */
data raw_frmt;
set raw;
format var1 frmt.;
run;
proc print data=raw_frmt noobs; run;
/* 5) load raw data set to CAS + apply SAS only format to CAS table <><><><><><><><><><><><><><><><><><><><><><><><>
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> */
/* a) load raw to CAS */
proc casutil;
load
data=raw
outcaslib='CASuser' /* << always implicit via sessopts=(caslib='CASuser')*/
casout='raw_cas' replace;
quit;
/* ########## re-run 2a) to validate format does NOT exist in CAS
Result: NOTE: No format libraries were found */
/* ########## re-run 3a) to validate no .sashdat files exist at all
Result: none */
/* b) apply SAS format to a CAS table in a CAS DATA Step */
data CASuser.raw_cas_frmt;
set CASuser.raw_cas;
format var1 frmt.;
run;
proc print data=CASuser.raw_cas_frmt noobs; run;
/* c) apply SAS format to a CAS table in CASutil load */
proc casutil;
format var1 frmt.;
load
data=raw
outcaslib='CASuser'
casout='raw_cas_frmt' replace;
quit;
proc print data=CASuser.raw_cas_frmt noobs; run;
/* d) apply SAS format to a CAS table in a CAS fetch action */
proc cas;
table.fetch
table={caslib='CASuser' name='raw_cas'}
fetchvars={{name='var1' format='frmt.'} {name='var2'}}
index=false;
quit;
/* 6) create the same format but add casfmtlib="CASformats" + save the format as a .sashdat file <><><><><><><><><><><><>
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> */
/* a) now create the same format:
in SAS: the format already exists
... NOTE: Format FRMT is already on the library WORK.FORMATS.
in CAS: the format Library CASformats is added
... NOTE: Format library CASFORMATS added. Format search update using parameter APPEND completed */
proc format casfmtlib="CASformats"; /* <<< lib=work.formats is implicit*/
value frmt
1 = 'abc';
run;
/* ########## re-run 2a) to validate that the CAS format library + format exists
Result: NOTE: Fmtlib = CASFORMATS
Scope = Session
Fmtsearch = YES
Format = frmt */
/* ########## re-run 3a) to validate that - still - no .sashdat files exist
Result: none */
/* b) now save our new CAS format library + format to CAS as a .sashdat file
NOTE: Cloud Analytic Services saved the file frmt.sashdat in caslib CASUSER */
cas casauto savefmtlib caslib=CASuser fmtlibname=CASformats table=frmt replace;
/* ########## re-run 3a) to validate .sashdat file DOES now exist
Result: frmt.sashdat */
/* 7) now how do we know that the frmt.sashdat file actually 'contains' a format ...
.. and specifically contains the format 'frmt' that we just created ?? <><><><><><><><><><><><><><><><><><><><>
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> */
/* NOTE: we know that a 'format' .sashdat file is different than a 'table' .sashdat file
In this section we load a 'format' .sashdat file to CAS + see the info. for that table
We know that trying to print that 'format' table will give us:
ERROR: Invalid characters were present in the data
Yes, an execercise in futility, BUT ...
We want to know the difference between our frmt.sashdat file and a random .sashdat file that is NOT 'tied to' any actual format */
/* a) load the frmt.sashdat file to a CAS table */
proc cas;
table.loadTable
caslib='CASuser'
path="frmt.sashdat"
importoptions={filetype="hdat"}
casout={caslib='CASuser' name="frmt_table" replace=true} ;
run;
/* b) 'see' the info. for that table */
proc cas;
table.tableinfo /
caslib='CASuser' name='frmt_table';
quit;
/* Source Name: frmt.sashdat
Source Caslib: CASUSER */
/* c) but we can create any random .sashdat format file that is NOT 'tied to' any actual format */
cas casauto savefmtlib caslib=CASuser fmtlibname=CASformats table=frmt_test replace;
/* NOTE: Cloud Analytic Services saved the file frmt_test.sashdat in caslib CASUSER.
However, frmt_test.sashdat is not 'tied to' any actual format */
/* >> load the file to a CAS table */
proc cas;
table.loadTable
caslib='CASuser'
path="frmt_test.sashdat"
importoptions={filetype="hdat"}
casout={caslib='CASuser' name="frmt_test_table" replace=true} ;
run;
/* >> see the info. for that table */
proc cas;
table.tableinfo /
caslib='CASuser' name='frmt_test_table';
quit;
/* Source Name: frmt_test.sashdat
Source Caslib: CASUSER */
/* ########## re-run 3a) to see both .sashdat files
Result: frmt.sashdat
frmt_test.sashdat */
/* So what is - and how do we know - the difference between frmt.sashdat and frmt_test.sashdat ? */
/* 8) we have now started a new CAS session <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><> */
cas CASauto sessopts=(caslib='CASuser');
libname CASuser cas caslib=CASuser;
/* a) we would obviously have no session format libraries (and we did nothing to promote global format libraries ) */
cas casauto listformats fmtlibname=CASFormats SCOPE=BOTH /*GLOBAL|SESSION|BOTH*/ MEMBERS;
/* ERROR: Scope=Both was specified. Format library CASFORMATS is not found in Session or Global scope. */
/* b) but we know that the frmt.sasdhat files persist */
proc cas;
table.fileinfo
caslib='CASuser';
quit;
/* frmt.sashdat + frmt_test.sashdat*/
/* c) we 'transform' the frmt.sashdat file into the CASFORMATS library which contains the format named 'frmt' */
cas casauto addfmtlib caslib=casuser fmtlibname=CASformats table=frmt;
/* NOTE: Format library CASFORMATS added. Format search update using parameter APPEND complete */
/* d) we confirm that the CASFORMATS library + format 'frmt' exist */
cas casauto listformats fmtlibname=CASFormats SCOPE=BOTH /*GLOBAL|SESSION|BOTH*/ MEMBERS;
/* NOTE: Fmtlib = CASFORMATS
Scope = Session
Fmtsearch = YES
Format = frmt */
/* e) re-run our raw data */
data raw;
infile datalines;
input var1 var2;
datalines;
1 10
2 10
;
/* f) load raw to CAS */
proc casutil;
load
data=raw
outcaslib='CASuser' /* << always implicit via sessopts=(caslib='CASuser')*/
casout='raw_cas' replace;
quit;
/* 9) So what do we need to do to use frmt.sashdat as a format in CAS ??? <><><><><><><><><><><><><><><><><><><><><>
<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
NOTE: offering a solution wherein we 'restate' the entire proc format seems to entirely disregard the idea of using a
persisted .sashdat 'format' file to apply a format in CAS
.. and would bring us back to 'argument' 5b/c/d)
... wherein we can "apply the SAS format to a CAS table" */
/* a) this provides a 'promising' note but does not seem to have an impact */
proc format casfmtlib='CASformats';
/* NOTE: Both CAS based formats and catalog-based formats will be written.
The CAS based formats will be written to the session CASAUTO. */
/* b) I don't believe that - for this excercise- we're concerned with promoting the format library to global scope */
cas casauto promotefmtlib fmtlibname=CASformats replace;
/* NOTE: Request to PROMOTEFMTLIB CASFORMATS completed for session CASAUTO.*/
/* c) note sure what this really does .. essentially the same as 7a) */
proc casutil;
load incaslib="CASuser" casdata="frmt.sashdat" outcaslib='CASuser' casout="frmt_table" replace;
quit;
/* NOTE: Cloud Analytic Services made the file frmt.sashdat available as table FRMT_TABLE in caslib CASUSER. */
/* But none of these result in our ability to use that persisted frmt.sashdat as a format in CAS */
/* >>> apply CAS format to a CAS table in a CAS DATA Step */
data CASuser.raw_cas_frmt;
set CASuser.raw_cas;
format var1 frmt.;
run;
proc print data=CASuser.raw_cas_frmt noobs; run;
/* NOTE .... Format FRMT was not found or could not be loaded. */
/* >>> apply SAS format to a CAS table in CASutil load */
proc casutil;
format var1 frmt.;
load
data=raw
outcaslib='CASuser'
casout='raw_cas_frmt' replace;
quit;
proc print data=CASuser.raw_cas_frmt noobs; run;
/* >>> apply SAS format to a CAS table in a CAS fetch action */
proc cas;
table.fetch
table={caslib='CASuser' name='raw_cas'}
fetchvars={{name='var1' format='frmt.'} {name='var2'}}
index=false;
quit;
Many thanks Tom!
These were the triggers I needed: (paraphrasing your insight):
I applied this in context as follows:
SECTION 1
6) export our user-defined formats:
FROM: the work.formats catalog
TO: a control data set (here, a CAS table)
7) save the CAS table 'control data set' as a .sashdat file
### disconnect from CAS ####
SECTION 2
4) load our formats.sashdat file to a CAS table
5) import our CAS table 'control data set' "back into" work.formats
Full code with annotations inserted
This is mostly so that any others trying to understand ‘CAS formats’ (of which I assess that there really isn’t such a thing in this context) might not do as I did and start chopping down trees in the CAS formats forest and then realize it was the wrong forest.
The actual solution is fairly straight forward.
(here 'SAS' generally means Viya Compute Server)
/* SECTION 1: CREATE INITIAL FORMAT AND SAVE AS A .SASHDAT FILE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
/* 1) connect to CAS*/
cas CASauto sessopts=(caslib='CASuser');
libname CASuser cas caslib='CASuser';
/* 2) create SAS raw data */
data raw;
infile datalines;
input var1 var2;
datalines;
1 10
2 10
;
/* 3) load raw to CAS */
proc casutil;
load
data=raw
outcaslib='CASuser'
casout='raw_cas' replace;
quit;
/* 4) create "SAS only" format
NOTE: for this excercise, we're going to 'assess' that:
>> there are indeed just "SAS only" formats created using SAS proc format
>> there are effectively no "CAS only" formats */
proc format; /* <<< lib=work.formats is implicit*/
value frmt
1 = 'abc';
run;
/* 5) apply format to CAS table
<<< business as usual here (applying our 'SAS format' to a CAS table)*/
data CASuser.raw_cas_frmt;
set CASuser.raw_cas;
format var1 frmt.;
run;
proc print data=CASuser.raw_cas_frmt noobs; run;
/* 6) export our user-defined formats:
FROM: the work.formats catalog
TO: a control data set (here, a CAS table) */
proc format lib=work.formats cntlout=CASuser.formats noprint; run;
/* print our CAS table 'control data set' */
proc print data=CASuser.formats noobs; run;
/* 7) save the CAS table 'control data set' as a .sashdat file */
proc cas;
table.save
table={caslib='CASuser' name='formats'}
caslib='CASuser'
name='formats' replace=true;
quit;
/* 8) list files (to see our formats.sashdat file) */
proc cas;
table.fileinfo
caslib='CASuser';
quit;
/* #################### disconnect from CAS ########################## */
/* SECTION 2: LOAD .SASHDAT FILE (that contains our format) INTO CAS THEN INTO SAS TO REUSE THE FORMAT >>>>>>>>>>>>>>>>>>>>>> */
/* 1) reconnect to CAS */
cas CASauto sessopts=(caslib='CASuser');
libname CASuser cas caslib='CASuser';
/* 2) recreate SAS raw data */
data raw;
infile datalines;
input var1 var2;
datalines;
1 10
2 10
;
/* 3) reload raw to CAS */
proc casutil;
load
data=raw
outcaslib='CASuser'
casout='raw_cas' replace;
quit;
/* 4) load our formats.sashdat file to a CAS table */
proc cas;
table.loadtable
caslib='CASuser'
path='formats.sashdat'
casout={caslib='CASuser' name='formats' replace=true};
quit;
/* >>> verify that work.formats does not yet exist */
proc format lib=work fmtlib; run;
/* 5) import our CAS table 'control data set' "back into" work.format
(our user-defined format will reside in work.format for the current session) */
proc format cntlin=CASuser.formats lib=work.formats noprint;
run;
/* >>> note that we have not utilized proc format 'values' to create a format */
/* 7) apply our format in CAS */
data CASuser.raw_cas_frmt;
set CASuser.raw_cas;
format var1 frmt.;
run;
proc print data=CASuser.raw_cas_frmt noobs; run;
Step 1 makes no sense. If you just started a new SAS session there is no WORK.FORMATS catalog yet.
Step 2 make no sense to me since you never defined any libref name CASFORMATS. (Perhaps I don't understand VIYA? Are CAS library names allowed to be more than 8 bytes long?
Where are you telling CAS that you want a library named CASFormats? I can see where you defined the library named CASuser in your first two statements, but do not see anything similar that might have defined CASFormats.
Thanks for the feedback. I should have clarified.
The initial steps (1–3) are designed to ensure that all SAS format catalogs, CAS format libraries, and CAS .sashdat files are deleted, regardless of the current state of the session. These steps may fail in a new CAS session, which is expected and acceptable since error handling is not relevant for this inquiry.
Assuming a clean slate (i.e., no persisted formats or files), step 4 becomes the logical starting point.
The inquiry centers around two key questions:
Can a SAS-only format be used directly in a CAS table?
Once a new CAS session is started, can a persisted .sashdat format file be used directly as a format—without needing to recreate the original PROC FORMAT definitions?
I hope that the code annotations reasonably illustrate and support my inquiry into format behavior within CAS.
FYI: To avoid this discussion from turning into an extensive deep dive on caslibs etc., I decided it was more appropriate to address the subject of caslibs, librefs, and format libraries in a dedicated post.
See here:
caslib vs CAS libref (+ CAS format library)
Kind of looks to me like the articles you linked are talking about converting the FORMAT catalog into a DATASET and storing that.
So basically use PROC FORMAT to convert your format(s) into a control datasets.
proc format lib=work.formats cntlout=caslib.formats noprint;
run;
So if you can figure out how to convert caslib in-memory dataset into disk files that persist and then load them back into memory then the only additional step you need to do in the new session is convert the dataset back into a format catalog.
proc format lib=work.formats cntlin=caslib.formats noprint;
run;
I suspect that the need to have the formats in CAS formats is for things like Dashboards that might not use the compute server to run code.
Some of the other articles are talking about how the system admin can configure the system so that some particular format catalogs are automatically loaded when you start a new session.
Many thanks Tom!
These were the triggers I needed: (paraphrasing your insight):
I applied this in context as follows:
SECTION 1
6) export our user-defined formats:
FROM: the work.formats catalog
TO: a control data set (here, a CAS table)
7) save the CAS table 'control data set' as a .sashdat file
### disconnect from CAS ####
SECTION 2
4) load our formats.sashdat file to a CAS table
5) import our CAS table 'control data set' "back into" work.formats
Full code with annotations inserted
This is mostly so that any others trying to understand ‘CAS formats’ (of which I assess that there really isn’t such a thing in this context) might not do as I did and start chopping down trees in the CAS formats forest and then realize it was the wrong forest.
The actual solution is fairly straight forward.
(here 'SAS' generally means Viya Compute Server)
/* SECTION 1: CREATE INITIAL FORMAT AND SAVE AS A .SASHDAT FILE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
/* 1) connect to CAS*/
cas CASauto sessopts=(caslib='CASuser');
libname CASuser cas caslib='CASuser';
/* 2) create SAS raw data */
data raw;
infile datalines;
input var1 var2;
datalines;
1 10
2 10
;
/* 3) load raw to CAS */
proc casutil;
load
data=raw
outcaslib='CASuser'
casout='raw_cas' replace;
quit;
/* 4) create "SAS only" format
NOTE: for this excercise, we're going to 'assess' that:
>> there are indeed just "SAS only" formats created using SAS proc format
>> there are effectively no "CAS only" formats */
proc format; /* <<< lib=work.formats is implicit*/
value frmt
1 = 'abc';
run;
/* 5) apply format to CAS table
<<< business as usual here (applying our 'SAS format' to a CAS table)*/
data CASuser.raw_cas_frmt;
set CASuser.raw_cas;
format var1 frmt.;
run;
proc print data=CASuser.raw_cas_frmt noobs; run;
/* 6) export our user-defined formats:
FROM: the work.formats catalog
TO: a control data set (here, a CAS table) */
proc format lib=work.formats cntlout=CASuser.formats noprint; run;
/* print our CAS table 'control data set' */
proc print data=CASuser.formats noobs; run;
/* 7) save the CAS table 'control data set' as a .sashdat file */
proc cas;
table.save
table={caslib='CASuser' name='formats'}
caslib='CASuser'
name='formats' replace=true;
quit;
/* 8) list files (to see our formats.sashdat file) */
proc cas;
table.fileinfo
caslib='CASuser';
quit;
/* #################### disconnect from CAS ########################## */
/* SECTION 2: LOAD .SASHDAT FILE (that contains our format) INTO CAS THEN INTO SAS TO REUSE THE FORMAT >>>>>>>>>>>>>>>>>>>>>> */
/* 1) reconnect to CAS */
cas CASauto sessopts=(caslib='CASuser');
libname CASuser cas caslib='CASuser';
/* 2) recreate SAS raw data */
data raw;
infile datalines;
input var1 var2;
datalines;
1 10
2 10
;
/* 3) reload raw to CAS */
proc casutil;
load
data=raw
outcaslib='CASuser'
casout='raw_cas' replace;
quit;
/* 4) load our formats.sashdat file to a CAS table */
proc cas;
table.loadtable
caslib='CASuser'
path='formats.sashdat'
casout={caslib='CASuser' name='formats' replace=true};
quit;
/* >>> verify that work.formats does not yet exist */
proc format lib=work fmtlib; run;
/* 5) import our CAS table 'control data set' "back into" work.format
(our user-defined format will reside in work.format for the current session) */
proc format cntlin=CASuser.formats lib=work.formats noprint;
run;
/* >>> note that we have not utilized proc format 'values' to create a format */
/* 7) apply our format in CAS */
data CASuser.raw_cas_frmt;
set CASuser.raw_cas;
format var1 frmt.;
run;
proc print data=CASuser.raw_cas_frmt noobs; run;
April 27 – 30 | Gaylord Texan | Grapevine, Texas
Walk in ready to learn. Walk out ready to deliver. This is the data and AI conference you can't afford to miss.
Register now and lock in 2025 pricing—just $495!
Still thinking about your presentation idea? The submission deadline has been extended to Friday, Nov. 14, at 11:59 p.m. ET.
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.