Tag: T-SQL

  • T-SQL Tuesday #17 – APPLYing Yourself to T-SQL

    TSQL2sDay150x150It’s T-SQL Tuesday again, and this month Matt Velic is the host. His topic this month is the APPLY operator, after a challenge from Adam Machanic that you are not that proficient in T-SQL if you don’t know how to use this operator. I agree with Adam, and I think APPLY was an amazing addition to the T-SQL language.

    If you’re not sure what T-SQL Tuesday is all about, check out Adam’s initial T-SQL idea and post on the monthly blog party. T-SQL Tuesday is the second Tuesday of every month and the host rotates.

    You can also follow T-SQL Tuesday on Twitter with the #tsql2sday hashtag.

    APPLY

    The APPLY operator is one that I wished had been available in SQL 7/2000. There were many times when you were trying to apply a result set to a function and there was no easy way to do this. Most of the time this resulted in some type of cursor/temp table solution to make things work.

    One classic example was in trying to determine the SQL that someone had executed when they were blocking another user. The old sp_who2 gave limited information and often we were query a blocking tree and then start sending SPIDs through dbcc inputbuffer to get an idea of what SQL queries were being run.

    APPLY doesn’t help with DBCC, but it does help in other ways. In a modern twist to this problem, you can take a plan handle and run it through sys.dm_exec_sql_text to get the SQL that was executed

    If I did that for one of the connections I have locally, I could get something like this:

    SELECT *
     FROM sys.dm_exec_sql_text(0x010005003E60AD1C901E7D81000000000000000000000000)

    Which will give you this:

    tsqltues_code2

    Now, if you have a whole list of data, say perhaps a list of everyone connected from sys.dm_exec_connections, you can combine these two together.

    SELECT a.session_id
        , a.num_reads
        , a.num_writes
        , b.text
     FROM sys.dm_exec_connections a
       CROSS APPLY sys.dm_exec_sql_text(a.most_recent_sql_handle) b

    From this, you’ll get some result similar to this one:

    tsqltues_code1

    Note that you can’t join these two items together because this doesn’t work:

    SELECT *
     FROM sys.dm_exec_sql_text

    It returns an error:

    Msg 216, Level 16, State 1, Line 3

    Parameters were not supplied for the function ‘sys.dm_exec_sql_text’.

    You have to pass in a parameter, which means that either you create some cursor or loop to do this, or use the power of APPLY.

  • Am I a sysadmin? (or other SQL Server role)

    How do you check if you are a sysadmin? It’s fairly easy to do in Management Studio. You can go to Security \ Server Roles \ Sysadmin, as shown here:

    sysadmin1

    You right click sysadmin and click properties to get a list of sysadmins. You can do this for any role, and that’s the easy way if you want to verify permissions.

    sysadmin2

    What if you have an open connection to the server, say in a Query window or Powershell session and want to verify your role. There’s a function to help you: Is_SrvrRoleMember().

    If you execute something like this:

    SELECT IS_SRVROLEMEMBER('sysadmin');

    You’ll get a one back if you are a member of that role, and a 0 otherwise. That will allow you to easily determine your current permissions, or check permissions programatically and continue on with your work depending on the results.

  • How Many Bytes Are In My Column? – T-SQL Functions

    One of the things you want to be aware of when writing T-SQL is using the proper function for a particular problem. Someone posted a question asking about why they were getting a 0 for this code:

    SELECT Mychar
        , '''' + mychar + ''''
       FROM dbo.MyTable

    That gave me these results

    mytable1

    I used the quotes in order to show that one of my columns has spaces trailing in one of the columns. I noticed that the poster was wondering why they had these results?

    SELECT Mychar
        , LEN(mychar)
       FROM dbo.MyTable

    mytable2

    In the table, clearly there are 4 characters for the row with “4D” and 5 characters for the next row. However the length is being returned as 0. If you were planning on testing for blank strings, or using some substring function, this could be an issue.

    The reason is simple. LEN, as noted in Books Online, ignores trailing spaces. The description of the function is: Returns the number of characters of the specified string expression, excluding trailing blanks.

    So if you have a space at the end of your string, or just a string of spaces, you don’t get the correct length. What should you use?

    Datalength – This function is designed to show the number of bytes used by the string, not the characters. Code shown below:

    SELECT 
       MyID
     , '''' + mychar + ''''
     , LEN(mychar)
     , DATALENGTH(mychar)
       FROM dbo.MyTable

    mytable3

     

    A good thing to be aware of if you are writing string test routines. LEN is the function I know most people use, but it is somewhat flawed, IMHO, in T-SQL

  • Implicit and Explicit Conversions

    Don't trust implicit conversions

    In a talk recently with some people I had someone note that the always chose to use explicit conversions on data types to prevent any unforeseen issues. That’s what I’d recommend as well. I have seen code in production function for years using implicit conversions, only to start failing when someone finally entered an invalid character in a row.

    How does that happen? Usually when someone is using character data types to store data that can be represented as character data,  even though the data must be dealt with in it’s native format. An example of this is storing a date as a varchar(10) or sticking numerical quantities in a character field to preserve formatting notations like dollar signs, or commas.

    That kind of code can work , pass a QA process, and live for years in a production system. However sooner or later someone will enter data that will break a query and return an error. Depending on your error handling system, this can be problematic to track down because it’s very data dependent. The code might work for some data sets but not for others.

    The best advice I can give is to store data in the proper data types whenever possible, and use explicit conversions when comparing data that might be of disparate types. Don’t always expect ’09/01/2001′ to compare to getdate(), and don’t expect ‘1’ to equal 1 in your code. At some point bad data will get into the system and those comparisons will error out.

    Steve Jones


    The Voice of the DBA Podcasts