SQL Server Version Detection

Every now and then, you need to figure out which version of SQL Server you’re using without knowing in advance. This might happen in a script (like sp_BlitzCache) or you might be using it in a migration.

Getting the SQL Server Version with @@VERSION

THe first thing that comes to mind is @@VERSION. On my SQL Server 2014 RTM installation, this returns an ugly string. Unless you like parsing multiline strings in T-SQL, you’re going to be left using LIKE on a hideous string like this one:

Imagine if you needed to get the build number of SQL Server out of there to validate against a list of builds to see if you had the current version of SQL Server installed. Pulling the build out of the major.minor.build.revision string isn’t easy when you first have to pull that string out of a bigger string.

There’s a better way than mucking around in @@VERSION.

Getting the SQL Server Version with SERVERPROPERTY

The SERVERPROPERTY built-in function has a lot of great functionality. We’re only going to concern ourselves with the ProductVersion portion of SERVERPROPERTY. How do we use it?

That should return nothing but the major.minor.build.revision for the current version of SQL Server. In my case, this returns: 12.0.2000.8.

Rather than parse the values myself, I created a temporary table with computed columns:

The common_version column will display the version of SQL Server as a floating point number – 12.0 for SQL Server 2014 or, in the case of SQL Server 2008R2, 10.5. When you’re targeting scripts for specific families of SQL Server, knowing the high level version can make scripting a lot easier.

What’s the final output look like for me?

version common_version major minor build revision
12.0.2000.8 12.0 12 0 2000 8

There you have it

That’s really all there is to finding and parsing the SQL Server version. Just a simple insert into a temporary table and a few computed columns and you’re ready to go.

Free, 3× a week

Get my new posts by email

Three posts a week, plus a Monday roundup of the best database news from around the web.

22 comments

  1. Any reason for the CONVERT(VARCHAR(32), version)? The best I can come up with is to support SQL Server 6.5 (which should be a varchar(30) according to BOL), but I don’t think SERVERPROPERTY existed back then (can’t find any docs on this).

  2. Why not just use a CTE and avoid creating and dropping a temp table?
    ; WITH cte as
    (
    SELECT CAST(SERVERPROPERTY(‘ProductVersion’) AS NVARCHAR(128)) AS Version
    )
    SELECT SUBSTRING(version, 1, CHARINDEX(‘.’, version) + 1 ) AS common_version,
    PARSENAME(CONVERT(VARCHAR(32), version), 4) AS major,
    PARSENAME(CONVERT(VARCHAR(32), version), 3) AS minor,
    PARSENAME(CONVERT(varchar(32), version), 2) AS build,
    PARSENAME(CONVERT(VARCHAR(32), version), 1) AS revision
    FROM cte;

    Of course the common_version parse would not work quite right if the common version were like 14.10….

  3. You’ll probably beat me to death for posting this, but… it doesn’t work with SQL 2000 🙂
    8.00.2066 gives
    common_version = 8.0, major = NULL, minor = 8, build = 00, revision = 2066

  4. PowerShell has a nice alternative method:

    dir SQLSERVER:\SQL\server_1 | select version, VersionMajor, VersionMinor, Buildnumber

    …which you can, if you want, put in a ‘for’ loop

    foreach ($ServerName in (“server_1”, “server_2”, “server_3”)) { dir SQLSERVER:\SQL\$ServerName | select version, VersionMajor, VersionMinor, Buildnumber }

    I can’t see how to retrieve the Revision Number though

  5. Hi Jeremiah
    All of your work is OUTSTANDING…the mark of a true professional….as far as executing powershell from sql server I have included the following in the hope it sheds light on how I accomplish it….this is used multiple times during the day to check free space on my drives….enjoy and keep up the outstanding work
    declare @sql varchar(8000)
    set @sql = ‘powershell.exe -c “Get-WmiObject Win32_Volume”‘
    insert into #wmi_drive_info (all_data)
    EXEC xp_cmdshell @sql

    1. I only just saw the comment above. Rather than using Powershell, this will provide you the same data:

      insert into #wmi_drive_info exec master..xp_fixeddrives

      It also saves you from having xp_cmdshell enabled (if that’s all you use it for).

  6. Hi Jeremiah,

    Related question…from what we are seeing, it looks like when Microsoft pushes a security hotfix, the CU that is installed is masked. That is, if you install the July QFE hotfix for SQL Server 2012, version 11.00.5613, you really have no idea if it is running CU1, CU2, … CU6. They all return 11.00.5613. CU7 came out later, so if you just install it (11.00.5623), you are ok, but if you were using a lower CU, you can’t programmatically know which one. Is that what you’ve found? thanks in advance for any insight.

      1. Hi Jeremiah. Just a follow up. We talked to our account rep and found, buried in the fine print of the security fix, that if you apply it, they bump you to CU6 (in this particular case of 2012, SP2). So the security fix actually incorporates CU6 as well. Unexpected, but at least it helps answer what version we’re running.

  7. Compare:

    CONVERT(HIERARCHYID, N’/’ + CONVERT(NVARCHAR, SERVERPROPERTY(‘ProductVersion’)) + ‘/’) < CONVERT(HIERARCHYID, N'/10.50.4000/')

  8. I found it easier this way to code for service pack features for multiple SQL versions.

    For example, say I want all the new performance counters and know they were released on a particular service pack on multiple SQL versions. So if I code for greater than SQL Server 12 SP3, or greater than SQL 2014 SP2, OR SQL 2016 + CU9 or better I could do this.

    DECLARE @sql_version INT = CONVERT(INT,LEFT(REPLACE(CAST(SERVERPROPERTY(‘ProductVersion’) AS CHAR(15)),’.’,”),7))
    SELECT
    CASE
    WHEN
    (@sql_version BETWEEN 1106020 AND 1200000) OR
    (@sql_version BETWEEN 1205000 AND 1300000) OR
    @sql_version >= 1301601
    THEN
    ‘Execute code block’
    ELSE
    ‘Execute code block’
    END

Leave a comment

Your email address will not be published. Required fields are marked *

Email me about new comments: