Category: Blog

  • T-SQL Tricks – Trigger Your Memory

    I was scanning Twitter the other day and saw a note from someone that they had written a query using an obscure T-SQL command and were glad it had worked. I exchanged a note with the person and they mentioned that they had to look up the command and syntax periodically when they had to write a similar query.

    I mentioned templates.

    If  you haven’t used these, you should, and I wrote a basic post about how to access them and one on customizing these for yourself. These templates are like Snippets in SQL Prompt (Which are way more useful to me), and they are a tool every DBA should use.

    Here’s one way I think they’re really helpful:

    Suppose I need to write a PIVOT query. I rarely do this, and it’s not too hard, but I write this query:

    select
        *
      from
        ( select
              runner
            , miles
            , mins
            from
              results
        ) as rawdata pivot ( avg(mins) for [miles] in ( [3], [5], [10] ) ) as pivotresults
    ;
    GO

    That’s easy enough, but it’s specific for my tables. However when I glance at it, I can see that there’s an aggregate columns, and I know the PIVOT requires that I list the values that are to be used in the columns.

    What if I change the query? I can do this:

    select
        *
      from
        ( select
              runner
            , <pivotcol, varchar, miles>
            , <aggcol, varchar, mins>
            from
              results
        ) as rawdata pivot ( avg(<aggcol, varchar, mins>) for [<pivotcol, varchar, miles>] in ( [3], [5], [10] ) ) as pivotresults
    ;
    GO

    Now if I make this a template:

    templates7

    I can drag this into a new query window. When I see it, I can CTRL+Shift+M and get this:

    templates8

    Now I change a few values and I have a pivot.

    templates10

    Of course, I need to actually enter the values I want, but this gets my PIVOTs done quickly without the need to decode BOL or swing by SQLServerCentral. Once I do that, I have a query I can use.

    templates11

    I’d encourage you to use templates. They’re very, very handy for quick sections of code that you use often, or want to remember in the future.

  • Converting Dates

    I ran across a post recently where someone had dates stored as characters (never good), but also in this format: CYYMMDD. I’d never seen that, and thought it was strange. The person was asking for a way to convert this to YYYY-MM-DD, which I think it fairly easy.

    Let’s set up some data:

    CREATE TABLE RandomDates
    (
        myid INT
        , mydate VARCHAR(7)
    );
    GO
    INSERT dbo.RandomDates
            ( myid
            , mydate
            )
        VALUES
            ( 1, '0600102' )
           , ( 2, '1121004' )
           , ( 3, '0920415' )
           , ( 4, '1040611' )
            ;
    GO

    The format for the data is 7 characters denoted as century, year, month, day. The century is encoded, with the single value representing:

    • 0 = 1900
    • 1 = 2000

    That’s pretty straightforward and it means that we have two dates in the 1900s and 2 in the 2000s. The dates are:

    • January 2, 1960
    • April 15, 1992
    • June 11, 2004
    • October 4, 2012

    Querying these dates and converting them is straightforward, but there are a couple ways to do this. If we are just looking to convert these to characters, I saw this solution from ZZartin.

     SELECT CONVERT(DATETIME, CASE 
                                WHEN LEFT(mydate, 1) = '1' 
                                    THEN '20' 
                                    ELSE '19' 
                                END 
                                + RIGHT(rd.mydate, 6)
                    , 112)
      FROM dbo.RandomDates AS rd;

    That’s fairly straightforward, and overall I like it. It uses simple functions and puts things together.

    I had another idea, mostly because I initially favored keeping the items separate as parts of the date in case I needed them. I thought about DATEFROMPARTS, which is a SQL Server 2012+ function. My thought was to calculate each of the parts and send them into the function like this:

    SELECT DATEFROMPARTS(
                        CASE WHEN LEFT(mydate, 1) = '0'
                            THEN 1900
                            ELSE 2000
                            END + SUBSTRING( rd.mydate, 2, 2)
                        , SUBSTRING( rd.mydate, 4, 2)
                        , SUBSTRING( rd.mydate, 6, 2)
                        )
     FROM dbo.RandomDates AS rd
     ;

    My idea has more function calls, and I’d think it would take longer to build, but I’m not sure. Let’s test.

    I’ll use Data Generator to insert a few million rows into this table. Then let’s run both pieces of code.

    The first code, from ZZartin, required about 19,000 logical reads and this execution plan when I ran it a few times. The CPU execution was in the 40k ms, and about 9 sec of real time.

    dates1

    The second code, mine, had about 30,000 logical reads, with only 8k CPU ms, but about 40sec of real time. The execution plan:

    dates2

    That’s interesting, and it matches what I’d expect. The first code is much simpler, intuitively, and it’s easy to read. With the format of the date essentially in order, it doesn’t make sense to try and "assemble" the date from parts. It’s easier to convert the first character to two (with the CASE) and then just cast this as a date.

  • T-SQL Tuesday #61 – Giving Back

    tsqltuesdayIt’s that time of month again, the time when we have a day where everyone writes on the same topic.

    This month Wayne Sheffield is the host and has chosen Giving Back as his theme. It’s a good one with the holidays and it’s one that really inspired SQLServerCentral. We built a business, but one that was founded on helping others and giving back to the community. The same could be said for SQL Saturday as well.

    Volunteering

    First the soap box. Everyone should give back to the world at some point in their lives. Perhaps it’s when you’re younger, perhaps when you retire, maybe it’s this weekend, but you should volunteer to make the world a better place.

    Now for my plans for giving back.

    They won’t change a lot from the past few years. I look to speak at various SQL Saturdays and User Groups in 2015. While Red Gate funds my travel and sometimes asks me attend events, I choose many on my own. I also donate my time as I don’t get a shorter week when I’m delivering a talk or two on Saturday. I still have the same responsibilities and deadlines to manage during the week.

    In 2015, I’m going to try and get to 8 SQL Saturdays. I did 11 in 2014, but I’m not sure I’ll end up with the same number. We’re still planning out 2015, and I don’t have any SQL Saturdays in the first quarter, but I’m hoping to make up a few later in the year.

    I also plan to get to each of the Denver area user groups in 2015. I managed to speak in Boulder, Denver, and Colorado Springs in 2014 and I hope to do the same in 2015.

  • SQL Server Disk Space Emergencies

    One of the things I’ll see happen often with SQL Server instances is that the system will run out of space on a drive. This could be for a variety of reasons, some of which can be prevented, and some cannot. You might have:

    • Don’t delete old backup files
    • Data growth fills the disk over time, usually years
    • tempdb rapid growth that uses all space
    • old import files not deleted over time

    There are other reasons, but I’ve often found that some process will cause an emergency and the SQL Server stops working, or stops backing up database, and administrators are in a panic to free space so the server can continue to function.

    Here’s what I suggest to smooth the way with a series of placeholders and a job.

    Create Placeholders

    First, create a folder on your SQL Server (or really every server) called Placeholder. I’d put it in the root to make it easy to find and standardize on it.

    placeholders3

    In the folder, place a series of files to save space. If you don’t know how to do this, I can show you an easy way. I have 4GB reserved here.

    placeholders4

    Now create a SQL Server Agent job. I might standardize this on every server I have with the same name and path.

    placeholders5

    The job has one step, which is designed to delete one file, each time it’s run.

    Note that I had a slight bug in what I shot above. I had the contig.exe utility in the folder and the first execution of the job deleted that file. Not a big deal in an emergency, because I can run the job again, but I’d make sure that only the place holder files are in this folder on machines.

    Here’s the job. It’s a PoSh type of step.

    placeholders6

    The actual PoSh code is here:

    $fileEntries = [IO.Directory]::GetFiles(“d:\placeholder”);
    $delete = 1;
    foreach($fileName in $fileEntries)
    {
    if ($delete -eq 1)
    {
    Remove-Item $fileName
    $delete = 0;
    }
    }

    When I run this, each time I run it, it’s just a single click or sp_start_job call.

    placeholders7

    After it runs, I have 1GB more free space. If I need more, run it again.

    placeholders8

    However, once you clear your low space condition, I’d be sure I put the placeholders back.

    For the next emergency.