If you operate in SAS® Enterprise Business Intelligence environment, you must realize that many of your data and user access functionalities and scopes are defined in and handled by the SAS metadata. Therefore, SAS metadata health is a paramount for successful SAS operations in your organization.
As a SAS user, have you ever been annoyed by a pop-up window in SAS Enterprise Guide? It reads “Duplicate librefs detected. Multiple libraries were detected in metadata that use the same libref for server SASApp. This is not a supported configuration and may cause problems. Please contact your SAS administrator.” Here’s how it looks:
Of course, the suggested solution to “contact your SAS administrator” is easy, but what if the SAS administrator is YOU?
First, you need to find out what these “multiple libraries” are. If you click on the Show Details arrow in the lower left corner, this pop-up window will expand showing the duplicated libref and listing the perpetrator libraries by their names.
After that, you need to modify these library definitions to use unique librefs. However, when assigning a new libref, how do you know whether it is unique and not used in another library? After all, you don’t want to go the painful route of trial and error when you assign a new libref and keep your fingers crossed so the “Duplicate librefs detected” window does not pop-up.
Here, we present programmatic solutions to create SAS metadata libraries inventory, identify existing libref duplicates, and check if a given word (character string) can be used as a new library libref without fear of being a duplicate.
Creating metadata libraries inventory and identifying duplicate LIBREF
Fortunately, there is an assortment of SAS DATA step functions for reading and writing metadata. These metadata functions enable SAS administrators to programmatically retrieve (or set) various attributes, associations and properties of the metadata objects.
SAS program to list all metadata libraries and identify duplicate librefs
The following little program will 1) create a SAS data table listing all the metadata libraries; 2) create another data table specifically listing only libraries with duplicate librefs.
/* Connect to the SAS metadata server */ options metaserver = 'your_metadata_server' metaport = 8561 metarepository = Foundation metauser = 'sasadm@saspw' metapass = '{SAS002}encrypted_password' ; /* Create metadata libraries listing/inventory */ data META_LIBS (drop=i rc ouri); length NAME $256 LIBREF $8 ouri $35; call missing(of _char_); do i=1 by 1 while(metadata_getnobj("omsobj:SASLibrary?@Id contains '.'", i, ouri) > 0); rc = metadata_getattr(ouri, 'Name', NAME); rc = metadata_getattr(ouri, 'Libref', LIBREF); LIBREF = upcase(LIBREF); output; end; run; /* Output metadata libraries with duplicate librefs */ proc sort data=META_LIBS nouniquekey out=DUP_LIBREFS; by LIBREF; run; |
Code highlights
- Connection OPTIONS statement makes sure you connect to the metadata server of your interest.
- CALL MISSING makes sure that all character variables are initialized to blanks – to eliminate NOTES in the SAS log that variables are
- DO-loop iterates through all the libraries in the metadata. Note, that we specify only a start-value (i=1), increment value (by 1) and WHILE-condition of entering into the DO-loop (metadata_getnobj(“omsobj:SASLibrary?@Id contains ‘.'”, i, ouri) > 0).
Here we use METADATA_GETNOBJ function which produces the output URI (ouri) of the i-th object that matches the specified input URI (“omsobj:SASLibrary?@Id contains ‘.'”). Besides returning the output URI, the function’s return value represents the number of objects matching the specified input URI (that is why we have while-condition as “> 0“). When negative value -4 is returned, it means that all SAS library objects are exhausted and DO-loop stops its iterations. - METADATA_GETATTR function is used twice and it assigns values of ‘Name’ and ‘Libref’ attributes of the metadata library object identified by the ouri
- Since librefs are case insensitive, in order to eliminate case sensitivity in the captured values of libref we simply convert all its characters to upper case using the UPCASE function.
- Finally, we use PROC SORT with NOUNIQUEKEY option to extract all non-unique LIBREF values and output observations with found duplicates to the DUP_LIBREFS data table. (NOUNIQUEKEY checks for and eliminates observations from the output data set that have a unique sort key.)
Duplicate librefs output
Here is an example of the produced data table that lists library names and duplicated librefs:
In case of no duplicate librefs, you will get the following NOTE in the SAS log:
NOTE: The data set WORK.DUP_LIBREFS has 0 observations and 2 variables.
Remediation of the duplicate librefs
Now, when you know the culprit(s), you can easily modify your metadata library definition to change the duplicate librefs to unique names. That is how you fix already existing problem.
However, such a fix would not preclude you from falling into the same trap again. How do you know that your new libref is unique and not repeating some other libref? Here is how to assuredly prevent this from happening.
Prevention from assigning duplicate LIBREF
The above method allows you to catch those accidentally (or not) assigned duplicate librefs. In this section, we will show how to prevent creating that mess in the first place! Here is how we can check (validate) if a libref that we are about to assign to a new metadata library is unique and not being used in one of the libraries that have already been defined in the metadata.
Solution 1: Querying metadata libraries listing
One simple solution is to use the data table META_LIBS created in the previous section. In essence, this data table is a listing (inventory) of all the data libraries defined in the SAS metadata. You can visually browse it or you can query it. For example, the following code will validate your new libref for exclusivity:
/* Libref to check for uniqueness */ %let NEW_LIBREF=Abc; /* Libref available or taken */ data _null_; set META_LIBS end=eof; if LIBREF=upcase("&NEW_LIBREF") then taken + 1; if eof and taken then put "***Libref &NEW_LIBREF already taken."; if eof and not taken then put "***Libref &NEW_LIBREF available."; run; |
It will produce either of the following two “verdicts” in the SAS log:
***Libref Abc available.
or
***Libref Abc already taken.
Solution 2: Using METADATA_RESOLVE function
Another, even simpler, single step solution uses the METADATA_RESOLVE function, which allows querying SAS metadata directly:
/* Libref to check for uniqueness */ %let NEW_LIBREF=Abc; /* Check if requested Libref available or taken */ data _null_; length type id $20; call missing (of _character_); select(metadata_resolve("omsobj:SASLibrary?@Libref="&NEW_LIBREF"", type, id)); when(0) put "***Libref &NEW_LIBREF available."; when(-1) put "***Unable to connect to the metadata server."; otherwise put "***Libref &NEW_LIBREF already taken."; end; run; |
METADATA_RESOLVE function resolves a URI specified in its first argument into an object’s type and id on the metadata server. In addition, and that what is important for our purpose, its return value represents the number of objects that match the specified URI. That is the return value of
- 0 means no matches were found and our &NEW_LIBREF libref is available for use in the new library
- -1 means that function was unable to connect to the metadata server
- 1+ means that there is one (or more) libref &NEW_LIBREF already existing in the metadata and this libref is not available for the new library.
Questions? Thoughts? Comments?
Do you find this blog post useful? How do you prevent and handle duplicate librefs in the metadata? Do you have questions, concerns, suggestions, or comments? Please share with us below in the Comments section.