SQLServerCentral Article

Customized Output Labels

,

Last month I had an interesting task to deal with. It had to do with the way our business views the data. In many cases my company is using MS Access as the way to access the data from tables and then save user filtered, ordered, or grouped reports in various formats. I am not saying it is good or bad. It is as it is. In many cases we are using stored procedures to get data out to Access. Stored procedures are linked in ICT Access files. Sometime views are created and linked to Access ICT file as well.

The request originated by the external users. In many cases clients would like to see a report output with their own header labels instead of our column names. Our internal business clients have the same request but with our internal labels. They would like to see a label instead of a column name. But the label should be a company specific label. We have about 200 databases and 5-6 new databases created per month. Each database should satisfy with such request. Remember that we are talking about direct stored procedure outputs and not about full reports developed by a specific reporting tool such as Crystal Reports.

Let illustrate a general idea of how it can be done. Let’s create a user table, a column dictionary table and populate the data dictionary with some data.

Create table customer (
Cust_cd char(4) not null primary key,
   Cust_lnm varchar(50),
   Cust_fnm varchar(50) )
INSERT INTO customer ( Cust_cd ,Cust_lnm ,Cust_fnm) 
   VALUES ('AAAA','LNM_TEST1','FNM_TEST1')
INSERT INTO customer ( Cust_cd,Cust_lnm ,Cust_fnm)
   VALUES ('BBBB','LNM_TEST2','FNM_TEST2')
CREATE TABLE COL_DICTIONARY (
   COL_DICTIONARY_ID int IDENTITY(1,1) NOT NULL PRIMARY KEY,
   COLUMN_NM varchar (50) NOT NULL , 
INTERNAL_ELEMENT_LABEL VARCHAR (50) NOT NULL ,
   CLIENT_ELEMENT_LABEL varchar (50) NULL )
Insert into COL_DICTIONARY ( COLUMN_NM, INTERNAL_ELEMENT_LABEL, CLIENT_ELEMENT_LABEL )
  Values ( 'cust_cd', '"Customer Code"', 'Code')
Insert into COL_DICTIONARY ( COLUMN_NM, INTERNAL_ELEMENT_LABEL, CLIENT_ELEMENT_LABEL )
  Values ( 'cust_lnm', '"Customer Last Name"', '"Last Name"')
Insert into COL_DICTIONARY ( COLUMN_NM, INTERNAL_ELEMENT_LABEL, CLIENT_ELEMENT_LABEL )
  Values ( 'cust_fnm', '"Customer First Name"', '"First Name"')

This table allows you save every data element for all tables as well as client and company internal labels for the columns. Next step is to prepare the procedure that will allow label manipulation.

CREATE PROC REPORT1
@USERLABEL CHAR(1) = 'N'
AS
BEGIN
SET NOCOUNT ON
declare @cmd nvarchar(4000)
create table #tmp 
( Cust_cd char(4) not null primary key
  , Cust_lnm varchar(50)
  , Cust_fnm varchar(50)
)
INSERT INTO #TMP (cust_cd, cust_lnm, cust_fnm)
 SELECT cust_cd, cust_lnm, cust_fnm
  FROM customer
select @cmd = 'select cust_cd as cust_cd, cust_lnm as cust_lnm, cust_fnm as cust_fnm FROM #tmp' 
declare @minid int, @maxid int
select @minid = min(COL_DICTIONARY_ID) , @maxid = max(COL_DICTIONARY_ID)
  from COL_DICTIONARY
WHILE (@MINID <= @MAXID)
 BEGIN
  IF (@USERLABEL = 'N')
   BEGIN
     select @CMD = replace (@cmd, 'AS ' + COLUMN_NM , 'AS ' + INTERNAL_ELEMENT_LABEL)
      from COL_DICTIONARY
      WHERE COL_DICTIONARY_ID = @MINID
   END
  ELSE
   BEGIN
    select @CMD = replace (@cmd, 'AS ' + COLUMN_NM , 'AS ' + CLIENT_ELEMENT_LABEL)
     from COL_DICTIONARY
     WHERE COL_DICTIONARY_ID = @MINID
   END
   SELECT @MINID = @MINID + 1
 END
exec (@cmd)
SET NOCOUNT OFF
END

Flag @USERLABEL allows a business person to specify the label output: internal or customer specific.

The next two outputs illustrate the point.

EXEC REPORT1@USERLABEL = 'N'
Customer Code Customer Last Name                                 Customer First Name
------------- -------------------------------------------------- ------------------------- 
AAAA          LNM_TEST1                                          FNM_TEST1
BBBB          LNM_TEST2                                          FNM_TEST2
EXEC REPORT1@USERLABEL = 'Y'
Code Last Name                    First Name
---- ---------------------------- ----------------- 
AAAA LNM_TEST1                    FNM_TEST1
BBBB LNM_TEST2                    FNM_TEST2

Obviously, there are some restrictions:– columns with the same name will end up having the same label.

It can be avoided if the label for each column will be unique in the SQL statement:

select cust_cd as cust_cd, cust_lnm as cust lnm, cust_fnm as cust_fnm
 FROM #tmp

Table COL_DICTIONARY may have an additional column COL_LABEL. And one row will be created for every column in the database to support uniqueness of the label even if the column names are the same.

CREATE TABLE COL_DICTIONARY (
  COL_DICTIONARY_ID int IDENTITY(1,1) NOT NULL PRIMARY KEY,
  COLUMN_NM varchar (50) NOT NULL ,
  INTERNAL_ELEMENT_LABEL VARCHAR (50) NOT NULL ,
  CLIENT_ELEMENT_LABEL varchar(50) NULL ,
  COL_LABELvarchar(50)
)
Insert into COL_DICTIONARY ( COLUMN_NM, INTERNAL_ELEMENT_LABEL, CLIENT_ELEMENT_LABEL, COL_LABEL )
 Values ( 'cust_cd', '"Customer Code"', '"Code"', 'cust_cd_1')
Insert into COL_DICTIONARY ( COLUMN_NM, INTERNAL_ELEMENT_LABEL, CLIENT_ELEMENT_LABEL, COL_LABEL )
 Values ('cust_lnm', '"Customer Last Name"', '"Last Name"', 'last_nm_1')
Insert into COL_DICTIONARY ( COLUMN_NM, INTERNAL_ELEMENT_LABEL, CLIENT_ELEMENT_LABEL, COL_LABEL )
 Values ('cust_fnm', '"Customer First Name"', '"First Name"', 'first_nm_1')

The procedure will now look like:

CREATE PROC REPORT1
  @USERLABEL CHAR(1) = 'N'
AS
BEGIN
SET NOCOUNT ON
declare @cmd nvarchar(4000)
create table #tmp 
( Cust_cd char(4) not null primary key, Cust_lnm varchar(50), Cust_fnm varchar(50))
INSERT INTO #TMP (cust_cd, cust_lnm, cust_fnm)
 SELECT cust_cd, cust_lnm, cust_fnm 
  FROM customer
select @cmd =  'select cust_cd as cust_cd_1, cust_lnm as last_nm_1, cust_fnm as first_nm_1
                 FROM #tmp' 
declare @minid int, @maxid int
select @minid = min(COL_DICTIONARY_ID) , @maxid = max(COL_DICTIONARY_ID)
 from COL_DICTIONARY
WHILE (@MINID <= @MAXID)
 BEGIN
  IF (@USERLABEL = 'N')
   BEGIN
    select @CMD = replace (@cmd, 'AS ' + COL_LABEL , 'AS ' + INTERNAL_ELEMENT_LABEL)
     from COL_DICTIONARY
     WHERE COL_DICTIONARY_ID = @MINID
   END
  ELSE
   BEGIN
    select @CMD = replace (@cmd, 'AS ' + COL_LABEL , 'AS ' + CLIENT_ELEMENT_LABEL)
     from COL_DICTIONARY
     WHERE COL_DICTIONARY_ID = @MINID
   END
  SELECT @MINID = @MINID + 1
 END
exec (@cmd)
SET NOCOUNT OFF
END
EXEC REPORT1@USERLABEL = 'N'
Customer Code Customer Last Name                                 Customer First Name
------------- -------------------------------------------------- ------------------------------ 
AAAA          LNM_TEST1                                          FNM_TEST1
BBBB          LNM_TEST2                                          FNM_TEST2
EXEC REPORT1@USERLABEL = 'Y'
Code Last Name                      First Name
---- ------------------------------ ------------------------- 
AAAA LNM_TEST1                      FNM_TEST1
BBBB LNM_TEST2                      FNM_TEST2

The parameter passed to the procedure can be made table driven as well.. However, it may prove to be a bit tricky in a multi-user environment.

Conclusion

This is a simple way to change output labels returned by a stored procedure. Despite it’s many restriction, it is quite fitting for simple kind of output.

Rate

You rated this post out of 5. Change rating

Share

Share

Rate

You rated this post out of 5. Change rating