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.
10 Comments
It seems odd to me that SAS Metadata Server allows what it seems to deem must be a unique key to have duplicates in the first place. If it matters to the extent that specific error generation occurs, then it suggests to me that there should be a uniqueness constraint. This is a legacy of SAS origins in a time when every SAS user had a separate SAS process. If you used the libref "MYLIB" and I used the libref "MYLIB" our separate sessions kept us safe. Leonid, it is nice of you to help us with little tools that we can use, but this is really a design issue that SAS should resolve.
You nailed it, Michael! (Or can I say "Neiled it"? 🙂 ) If you attempt to assign an existing Library Name to a new Library in SAS Management Console, it will display an Error pop-up window stating "A library named 'SomeName' is already assigned to the server 'SASApp'." preventing the new library creation. I agree that something similar could be done with the librefs too.
Thanks Leonid! One quick note: if you click the "Show Details" button on the "duplicate librefs detected" window, it usually lists the duplicated libraries. The admin still has to take action to fix the issue, though.
Thank you, Kevin, for this great catch. I corrected and clarified this in the blog. Still, programmatic libraries inventory and libref test for availability (to prevent the duplicates) are very useful tools for SAS admins.
Agreed, the programmatic tools make it much simpler to deal with this issue site-wide. Thanks for the great post!
You are welcome, Kevin! 👍
This is so important - the 8 character libref is foundational. It's also necessary for customers looking to get the most out of Data Controller for SAS® (https://datacontroller.io) as this uses librefs in URLs. We'll be sure to share this article, thanks!
For info, a number of macros for dealing with libraries in metadata can also be found here: https://core.sasjs.io/dir_0d92069d5a23b1d3125c326d74f1a07c.html
Thank you, Allan, for your input and sharing additional SAS administration utilities.
Great post Leonid! Could also be a pro-active approach for SAS admins to take to avoid SAS users getting the "Duplicate librefs detected" pop-up window. 😉
I saw that you mentioned Metacoda Plug-ins in the additional resources - thanks for that. If a SAS administrator is not a programmer and has access to the Metacoda Library Reviewer, they can click on the LIBREF column heading and see the list of LIBREFs sorted alphabetically to identify the duplicates. https://platformadmin.com/blogs/paul/2022/03/metacoda-plug-ins-library-reviewer/
Cheers,
Michelle
Thank you, Michelle!
Metacoda is a great SAS administrator's tool. The programmatic approach to the metadata data libraries inventorization described in this post should empower all SAS admins (even those who do not yet have Metacoda 🙂 ).