Skip to content
April 5, 2011 / sqlexpertise

Identifying nullable index columns and nullable foreign keys.

 Identifying nullable index columns and nullable foreign keys

 While there are no limitations to prevent the use of a nullable column within an index or as a foreign key, there are several situations where nulls may cause problems. One example where a nullable column may cause a problem is in the creation of a unique index or unique constraint. Simply stated, you cannot create a unique index or a unique constraint if there is more than one row with a value of “null” in the given column. The information below is from the SQL Server 2008 R2documentation and can be viewed here: http://msdn.microsoft.com/en-us/library/ms175132.aspx

 ”Handling NULL Values”

“For indexing purposes, NULL values compare as equal. Therefore, you cannot create a unique index, or UNIQUE constraint, if the key values are NULL in more than one row. Select columns that are defined as NOT NULL when you choose columns for a unique index or unique constraint.”

Additionally, the results show columns used as foreign keys that have been defined as nullable. While it is possible to create foreign keys on nullable columns, it creates a condition that violates the foreign key itself because the null value cannot be equated to any given value during the foreign key lookup. In effect, a null value bypasses the foreign key constraint resulting in data corruption type scenarios.

 The following T-SQL script lists all columns that have been defined to allow nulls. The script can also be used to identify columns used as indexed columns and / or foreign keys that have been defined to allow nulls.

select b.name as 'Table Name'
      ,a.name as 'Column Name'
      ,isnull(d.name,'N/A') as 'Index Name'
      ,isnull(f.name,'N/A') as 'Foreign Key Constraint Name'
  from sys.columns a
  join sys.objects b
    on b.object_id = a.object_id
  left join sys.index_columns c
    on c.column_id = a.column_id
   and c.object_id = a.object_id
  left join sys.indexes d
    on d.index_id = c.index_id
   and d.object_id = c.object_id
  left join sys.foreign_key_columns e
    on e.parent_object_id = a.object_id
   and e.parent_column_id = a.column_id
  left join sys.foreign_keys f
    on f.object_id = e.constraint_object_id
 where a.is_nullable = 1
   and b.type = 'U'
   and objectproperty(b.object_id,'IsMSShipped') = 0

Sample results shown below:

Hopefully you find this script useful.
Please let me know if there are any questions. All feedback is appreciated.
Thanks,
Greg Moss

March 29, 2011 / sqlexpertise

Reducing confusion through T-SQL CASE expressions

Ever looked at data returned from a catalog view in order to achieve clarity about a specific question, only to end up being further confused by the catalog data returned?

A good example of this is when looking at the size of your database files in the sys.database_files catalog view. The data returned for the “size” column is shown in 8k pages instead of actual size in KB.  This is confusing enough, but with larger databases this can be even more confounding. 

One solution to resolving this confusion is with T-SQL “CASE” expressions.

In using T-SQL code to access data within a SQL Server database, we often find opportunities based upon conditional situations where we need the flexibility of replacing column values, calculations, or even conditionally altering the order results are sorted. Most often, these situations can be addressed with the T-SQL “CASE” expression.

There are two types of case statements including the first example, which is the “simple” type. The “simple” case statement evaluates a value (or expression) and compares it in an equality check against a set of values (or expressions).

In its simplest form the T-SQL “CASE” expression can enrich database results while providing descriptive results for non-obvious data values.

In this example, the information is clearer than just a simple “code” being returned:

  select    name  as ‘Object Name’
                 ,(case type
                                          when ‘U’  then  ‘User Defined Table’
                                          when ‘V’  then  ‘User Defined View’
                     end) as ‘Object Type’
     from  sys.objects
  where type in (‘U’,'V’)
   order by name

This example produces the following results:
Object Name              Object Type
Collection                   User Defined Table
CollectionGroup         User Defined Table
HourlyLoad                 User Defined View
HourlyData                 User Defined View
Hours                          User Defined Table
DataValues                User Defined View
Property                     User Defined Table

In the example above the object is “labeled” for clarity based upon its object type.

The second type of case expression is the “searched” case expression. In this type of expression, one or more Boolean expressions are evaluated until a match occurs. For example:

 select (convert(varchar(50),getdate(), 108) + ‘ ‘ + 
        convert(varchar(50),datename(weekday,getdate())) +
        convert(varchar(50),(case                                 
                                 when datepart(hh,getdate()) between 0 and 5
                                      then ‘ Early Morning’
                                 when datepart(hh,getdate()) between 6 and 11
                                      then ‘ Morning’
                                 when datepart(hh,getdate()) between 12 and 17
                                      then ‘ Afternoon’
                                 when datepart(hh,getdate()) between 18 and 23
                                      then ‘ Evening’
                                 else ‘Unknown Time’
                              end)))                         as ‘When did problem occur?’

 This example produces the following results:
When did problem occur?
10:06:52 Monday Morning

In the example above a text string is created with standardized information in order to facilitate clarity in communications between groups.

In some situations, the use of a case expression can be used to address complex conditional computations. For example, in order to provide the size of a database file in the appropriate measurement (in this case we provide size information in Gigabytes, Megabytes, Kilobytes, and Bytes depending on the actual size of the file) we create a nested case expression as follows:

 –*****  Define Variables  *****
declare @GB    float
declare @MB    float
declare @KB    float
declare @B     float

–*****  Assign Variable Values  *****
set @GB   =  (cast(8192 as float) / cast(1073741824 as float))
set @MB   =  (cast(8192 as float) / cast(1048576 as float))
set @KB   =  (cast(8192 as float) / cast(1024 as float))
set @B    =  (cast(8192 as float))

–*****  Get Database File Information  ******
select  name                                                              as ‘File Name’
        ,file_id                                                          as ‘File ID’
        ,(case 
              when (cast(size as float) * @GB) > (cast(1 as float))
                   then (convert(varchar(16),(cast(size as float) * @GB)) +  ‘ GB’)
              else (case
                        when (cast(size as float) * @MB) > (cast(1 as float))
                             then  (convert(varchar(16),(cast(size as float) * @MB)) + ‘ MB’)
                        else (case
                                   when (cast(size as float) * @KB) > (cast(1 as float))
                                        then (convert(varchar(16),(cast(size as float) * @KB)) + ‘ KB’)
                                   else ((convert(varchar(16),(cast(size as float) * @B))) + ‘ Bytes’)
                              end)
                    end)
          end)                                                            as ‘File Size’
  from  sys.database_files
 order  by type, file_id

This example provides the following results and was created to demonstrate complex CASE expression nesting:
File Name                 File ID        File Size
MyDatabase_Data     1               11.7197 GB
MyDatabase_Log       2               1.95313 GB

NOTE: This example can be reduced to a simple case statement but was purposefully coded to show nesting of case expressions. This example accurately calculates useable file space and does not necessarily match the SQL Server Management Studio file size displayed!
The example above calculates size in differing measurements based upon measurement boundries.

In the final example, we use a T-SQL “CASE” expression to conditionally order a result set. In this particular scenario, we order all results other than system table data by object type and object name. All results that are system table data are sorted by type and object_id:

select   name        as ‘Object Name’
        ,type        as ‘Object Type’
        ,object_id   as ‘Object ID’
  from  sys.objects a
 order  by type
           ,(case type
                  when ‘S’ then ‘Object ID’
                  else a.name
             end) asc

This example provides the following results:
Object Name                                                       Object Type               Object ID
CK_master_server_MustBe_1                               C                               309576141
sysmail_OutMailSensitivityMustBeValid                C                              155147598
default_current_date                                             D                               2121058592
DF__sysutilit__volum__049AA3C2                        D                               77243330
FK__backupfil__backu__14E61A24                       F                               350624292
FK_sysutility_mi_smo_properties                          F                               1293247662
agent_datetime                                                    FN                             1973582069
ConvertToInt                                                        FN                              891150220
syspolicy_fn_get_type_name                                FN                              1504724413
sp_add_alert                                                       P                                1906105831
sysmail_verify_profile_sp                                      P                                939150391
PK__backupfi__57D1800A17C286CF                    PK                              414624520
SYSMAIL_SERVERTYPE_TypeMustBeUnique      PK                              1822629536
sysrscols                                                            S                                3
sysallocunits                                                       S                                7
sysfiles1                                                             S                               8
syspriorities                                                         S                               17
sysowners                                                          S                                27
sysbinobjs                                                          S                                58
sysaudacts                                                         S                                59
sysobjvalues                                                       S                                60
sysclsobjs                                                          S                                64
sysrowsetrefs                                                      S                                65
sysremsvcbinds                                                   S                                 67
sysxmitqueue                                                      S                                 68
sysrts                                                                 S                                 69
sysconvgroup                                                      S                                 71
sysdesend                                                          S                                 72
sysdercv                                                             S                                 73
syssingleobjrefs                                                   S                                 74
sysmultiobjrefs                                                     S                                 75
sysguidrefs                                                          S                                  78
syscompfragments                                               S                                  82
syn_sysutility_ucp_volumes                                  SN                              189243729
fn_sysutility_ucp_get_policy_violations                   TF                               2077250455
backupfile                                                            U                                 366624349
backupfilegroup                                                    U                                 286624064
backupmediafamily                                               U                                 110623437
backupmediaset                                                   U                                 46623209
backupset                                                            U                                 206623779
sysproxylogin                                                       U                                 69575286
sysutility_ucp_volumes_stub                                 U                                  2000726180
NOTE: Results truncated for clarity!

In the example above a “CASE” expression is used to conditionally order data within the result set that would not be possible otherwise.

In conclusion, we can see that the “CASE” expression can be used in efforts to clarify results, conditionally apply calculations and conditionally order result sets. The ability to use a “CASE” expression effectively can provide additional functionality and flexibility in T-SQL coding scenarios unobtainable otherwise.

Note: All examples created using SQL Server 2008 R2.

Note: I am also including the original word document that perserves formating for reading ease!

REDUCING CONFUSION THROUGH T-SQL CASE EXPRESSIONS

March 29, 2011 / sqlexpertise

T-SQL Script to list database files and file sizes

 As is always the case with a limited amount of space, I often find myself trying to manage space on the physical storage I have available. This process is like trying to hit a moving target as I will frequently create and drop databases for testing purposes or load / attach databases sent to me by customers.

Usually if a database is not in use, I archive it or remove it completely as I only need space for the active databases I am working with. In order to know how much space I am currently consuming I run the following script to enumerate all databases currently in use and the files associated with each of these databases.

 –***** Define Variables *****
declare @GB    float
declare @MB    float
declare @KB    float
declare @B     float

–***** Assign Variable Values *****
set @GB   =  (cast(8192 as float) / cast(1073741824 as float))
set @MB   =  (cast(8192 as float) / cast(1048576 as float))
set @KB   =  (cast(8192 as float) / cast(1024 as float))
set @B    =  (cast(8192 as float))

select db_name(database_id) as ‘Database Name’,      
       database_id as ‘Database ID’,
      (case type
            when 0 then ‘Data File’
            when 1 then ‘Log File’
            when 2 then ‘Filestream File’
            when 3 then ‘Other – N/A’
            when 4 then ‘Full Text Catalog File’
            else ”
       end) as ‘FIle Type’,
       name as ‘Logical File Name’,
       physical_name as ‘Physical File Name and Location’,
     ((convert(float,size) * CONVERT(float,8)) / CONVERT(float,1024)) as ‘Declared Size in MB’,
      (case when (cast(size as float) * @GB) > (cast(1 as float))
            then (convert(varchar(16),(cast(size as float) * @GB)) +  ‘ GB’)
            else (case when (cast(size as float) * @MB) > (cast(1 as float))
                       then (convert(varchar(16),(cast(size as float) * @MB)) + ‘ MB’)
                       else (case when (cast(size as float) * @KB) > (cast(1 as float))
                                  then (convert(varchar(16),(cast(size as float) * @KB)) + ‘ KB’)
                                  else ((convert(varchar(16),(cast(size as float) * @B))) + ‘ Bytes’)
                             end)                 
                  end)        
       end) as ‘Actual Size’,       
      (case when is_percent_growth = 0                  
            then (case when (cast(growth as float) * @GB) > (cast(1 as float))
                       then (convert(varchar(16),(cast(growth as float) * @GB)) +  ‘ GB’)
                       else (case when (cast(growth as float) * @MB) > (cast(1 as float))
                                  then  (convert(varchar(16),(cast(growth as float) * @MB)) + ‘ MB’)
                                  else (case when (cast(growth as float) * @KB) > (cast(1 as float))
                                             then (convert(varchar(16),(cast(growth as float) * @KB)) + ‘ KB’)
                                             else ((convert(varchar(16),(cast(growth as float) * @B))) + ‘ Bytes’)
                                        end)
                             end)
                  end)
            when is_percent_growth = 1
            then (case growth
                       when 0 then ‘N/A’
                       else (convert(varchar(16),(cast(growth as float))) + ‘ %’)
                  end)
            else ”
       end) as ‘Growth Method’
 from  master.sys.master_files
 order by database_id, type, size desc

Hopefully you find this script useful.
Please let me know if there are any questions. All feedback is appreciated.
Thanks,
Greg Moss

Follow

Get every new post delivered to your Inbox.