Object-oriented access to SAS data in a custom task

Most custom tasks need to access SAS data in some way. Since custom tasks are built using Microsoft .NET, and the .NET Framework is object-oriented, it would be convenient if we had an object-oriented method for navigating SAS data sources.

That was the thinking behind the "SasData"-namespace classes within the SAS Tasks Toolkit. The SAS Tasks Toolkit is a library of .NET classes (included in SAS.Tasks.Toolit.dll) that simplify the implementation of custom tasks by handling most of the "plumbing" for you, so that you can concentrate on the purpose and content of your task. (The SAS Tasks Toolkit is discussed in greater detail in my forthcoming book, Creating Custom Tasks for SAS Enterprise Guide using Microsoft .NET.)

These classes in the toolkit can help with navigating and inspecting the properties of data-related objects in SAS:

  • SAS.Tasks.Toolkit.SasServer (object for SAS workspace)
  • SAS.Tasks.Toolkit.SasData.SasLibrary (object for SAS data library)
  • SAS.Tasks.Toolkit.SasData.SasData (object for SAS data set or view)
  • SAS.Tasks.Toolkit.SasData.SasColumn (object for a variable in a data set)
  • SAS.Tasks.Toolkit.Helpers.TaskDataHelpers (methods for retrieving data values)

I built a simple example so that you can see this in action. Here's a preview of the user interface:


You can get the source code for this example on my SasDataExample github repository. There is a ready-to-use DLL that you can "install" into your SAS Enterprise Guide 4.3 or 5.1 to see it in action. And if you want to dabble with the C# source, you can use Microsoft Visual C# Express or Visual Studio (2010 or 2012 editions).

(Note: you don't have to be a github user to try the example. You can download the ZIP archive with a single click.)

What's remarkable about this example is that it contains very little code. Aside from the "designer" code in the Windows form, there are really only about 100 lines of code in the "form" class (excepting comments and spaces).

As I described in a previous post, I'm using data binding to populate the UI controls with the content of the SAS data object.

For example, once you select a SAS server (using the drop-down list in the upper left corner), these few lines of code will populate the list of SAS libraries:

// use the SasServer.GetSasLibraries method 
// to get a collection of defined SAS libraries
// on the active server
SasServer s = cmbServer.SelectedItem as SasServer;
IList<SasLibrary> libs = s.GetSasLibraries();
lbLibraries.Items.Clear();
lbLibraries.Items.AddRange(new List<SasLibrary>(libs).ToArray());

This example illustrates a cool function within the SAS.Tasks.Toolkit.Helpers.TaskDataHelpers namespace: GetDistinctValues. You supply it a data reference and the name of a column, and it returns a list of the distinct values within the data for that column. So it's like a SELECT DISTINCT operation, but it's got one additional cool feature: you can optionally supply a SAS format to apply.

So if you have a SAS date column with daily measures (for example) and you want a list of just the distinct year values in the data, you can simply apply the YEAR4. format in the GetDistinctValues function. The following screen image from the example task shows what kind of difference that can make:


If you have questions or thoughts about the example, its code, or the idea of placing such examples on github, please post back in the comments.

tags: .net, SAS custom tasks, SAS task toolkit, SasData

8 Comments

  1. Posted November 19, 2012 at 3:11 pm | Permalink

    Great stuff Chris. Thanks for taking the time to do this plumbing for us.

  2. Ramana Potluri
    Posted March 16, 2013 at 6:38 am | Permalink

    Hi Chris,
    Is it possible to build a custom task by modifying the existing query builder task?
    If yes could you please give me some tips and steps to follow to build the new custom task.

    Regards

    Ramana

    • Chris Hemedinger Chris Hemedinger
      Posted March 16, 2013 at 9:07 am | Permalink

      Ramana, no, you cannot modify an existing task to create your own custom task. But you can reuse some pieces of the task framework, such as the *simple* filter selection, in your own tasks. An example is described in Chapter 11 of my book, with the source project available here.

  3. Posted October 23, 2013 at 5:12 pm | Permalink

    Excellent, Chris!

    Keep up the good work!

    Kirk

  4. Slash
    Posted March 26, 2014 at 3:49 am | Permalink

    Thanks again, Chris! Another question, is there a method that I can use to get the data's size?

    • Chris Hemedinger Chris Hemedinger
      Posted March 26, 2014 at 6:49 am | Permalink

      That information is in SASHELP.VTABLE. The SasData classes don't provide a direct method to read it, but you can use the SAS OLE DB provider and a simple query to access the relevant fields. Check out my Data Set->DATA Step example for code samples that use the OLE DB provider.

      • Slash
        Posted March 28, 2014 at 11:06 pm | Permalink

        Yeah, I notice that too. So I use the OleDbDataAdapter to get the data into a DataSet, then use the Select method get the specified information. Just like this:

        System.Data.OleDb.OleDbDataAdapter obAdapter =
          new System.Data.OleDb.OleDbDataAdapter(
             "select memname,nobs,filesize from sashelp.vtable where libname=\"DATA\"", 
             "provider=sas.iomprovider.1; SAS Workspace ID=" + 
             remote_server.GetWorkspaceIdentifier());
        
        DataSet obDS = new DataSet();
        obAdapter.Fill(obDS, "Infor");
        
        String query = "memname='" + data_name + "'";
        /*Get the Data Obs*/
        String temp = obDS.Tables["Infor"].Select(query)[0][1].ToString();
        ........
        

        But I have a little question about the "provider=sas.iomprovider.1". The number 1 will change or not?

        • Chris Hemedinger Chris Hemedinger
          Posted March 31, 2014 at 7:22 am | Permalink

          Slash, that "prog ID" with the "1" has been like that for many years, and works even with the latest versions. I think it's safe to use. I think you could leave the ".1" off and it would still work, as there is an entry in the registry for it.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <p> <pre lang="" line="" escaped=""> <q cite=""> <strike> <strong>