Tag: T-SQL

  • Managing Data in a FileTable with T-SQL

    I wrote a post about creating a Filetable, which just covered the basics of how to build one. How do you work with the data in this table? In this post I’ll look at a few things you can do from the T-SQL side.

    From the last post, I had my author drafts Filetable. I can see this in the Object Explorer.

    filetable_c

    I can use the same “select data” feature from Object Explorer on a Filetable, just like any other table.

    filetable_e

    I get the results, and as you see, I have a few rows in the table.

    filetable_f

    These are actually the files I see in the share.

    filetable_d

    Inserting Data

    One of the advantages of Filetable is that you can use Explorer (and any tools that use the same Explorer APIs) to move data in and out of a table. However that doesn’t preclude you from using T-SQL.

    I can use a script to insert data into the table, just as I might with Filestream.

    INSERT INTO AuthorDrafts(name, file_stream) Values ( 'circle.jpg' , 0xFFD8FFE000104A46494600010101006000600000FFE100684578696600004D4D002A000000080004011A0005000000010000003E011B0005000000010000004601280003000000010002000001310002000000120000004E00000000000000600000000100000060000000015061696E742E4E45542076332E352E313000FFDB0043000201010201010202020202020202030503030303030604040305070607070706070708090B0908080A0807070A0D0A0A0B0C0C0C0C07090E0F0D0C0E0B0C0C0CFFDB004301020202030303060303060C0807080C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0CFFC0001108000A000D03012200021101031101FFC4001F0000010501010101010100000000000000000102030405060708090A0BFFC400B5100002010303020403050504040000017D01020300041105122131410613516107227114328191A1082342B1C11552D1F02433627282090A161718191A25262728292A3435363738393A434445464748494A535455565758595A636465666768696A737475767778797A838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE1E2E3E4E5E6E7E8E9EAF1F2F3F4F5F6F7F8F9FAFFC4001F0100030101010101010101010000000000000102030405060708090A0BFFC400B51100020102040403040705040400010277000102031104052131061241510761711322328108144291A1B1C109233352F0156272D10A162434E125F11718191A262728292A35363738393A434445464748494A535455565758595A636465666768696A737475767778797A82838485868788898A92939495969798999AA2A3A4A5A6A7A8A9AAB2B3B4B5B6B7B8B9BAC2C3C4C5C6C7C8C9CAD2D3D4D5D6D7D8D9DAE2E3E4E5E6E7E8E9EAF2F3F4F5F6F7F8F9FAFFDA000C03010002110311003F00E97FE0E87FF82CA7ED35FB04FED85E09F03FC2BD6A5F87BE1097408B5C4D523D2ADAF1BC41746795248CBDC4722F970848C18940399373E43478FD75FF00827CFC68F177ED17FB0FFC2AF1D78F3461A078C7C59E19B2D4F57B110B42B14F244199846DF346AFC384392A1C024E335E95E2EF87BE1FF880968BAF687A3EB6B612F9F6C2FECA3B916F27F7D3783B5BDC60D6C5007FFFD9 ); go

     

    As you can see, this command works fine:

    filetable_g

    If I then look at the share, I see my file:

    filetable_h

    Retrieving Data

    As shown above, I can use SELECT queries to return data from a Filetable in T-SQL. However, I have a share as well, and I can cut, copy, paste, and open files from the share just as I would any other file in the file system.

    filetable_j

     

    If I open the file in Paint, I see my image:

    filetable_i

    Summary

    Working with files in a file table is easy, and while many people will use Explorer functions, you can use T-SQL as well to insert, or retrieve the data as you choose.

  • CHOOSE in SQL Server 2012

    The CHOOSE command is new in the T-SQL as of SQL Server 2012. I hadn’t ever had the chance to work with it, but after seeing someone submit a piece recently, I decided to play with it a bit.

    This feature is essentially an indexing value from an array. Here’s a short example.

    SELECT CHOOSE(1, 'First', 'Second', 'Three');

    The first parameter to the CHOOSE() function is an integer, which is the position. The second (and subsequent) parameters are the array of values. Here’s a better example. Let’s say I have a lookup table of titles:

    CREATE TABLE titles
    ( titleid INT
    , title VARCHAR(20))
    ;
    INSERT titles 
     VALUES (1, 'Manager')
          , (2, 'Developer')
          , (3, 'DBA')
          , (4, 'Sysadmin')
          , (5, 'Storage Admin')
          , (6, 'Help Desk')
    ;

    I might potentially have a very large table. Imagine that I work at SalesForce.com or I have some type of EAV table here. If I am performing a join with employees, I could easily do this:

    SELECT 
       e.firstname
     , t.title
     FROM dbo.employees e
      INNER JOIN dbo.titles t
        ON    e.titleid = t.titleid

    However, suppose I have performance issues, or I’m joining to lots of tables. Perhaps I’d prefer not to actually join to another table for some reason. I could do this instead:

    SELECT 
       e.firstname
     , CHOOSE( e.titleid, 'Manager', 'Developer', 'DBA', 'Sysadmin', 'Storage Admin', 'Help Desk')
     FROM dbo.employees e

    Is this useful?

    I’m not sure. Most of the examples and places I can think of for using this are rather trivial, or inflexible. This seems like hard coding values into a procedure or function when a table join might be a better option.

    I haven’t found any blogs that present practical uses that make sense, but I’m sure some are out there. Let me know if you know of any.

    UPDATE: Rob Farley mentioned he uses this in the date dimension of data warehouses. I’m not sure if that’s the best solution, but Rob’s a smart guy, so I’ll take his word that this is a good use of the function.

  • How do you solve T-SQL problems?

    solvetsql

    Six scans, six logical reads. What could be the problem? There’s no problem if you’re always dealing with six rows of data. If you’re dealing with 6mm, however, this is likely to be a performance problem on your server. Many developers might write a query, check the statistics, and see something like that shown above, and think that it’s a good day’s work.

    Solving the problem is only half the job you should do. Solving things in an efficient way is the other half. When you tackle a new T-SQL challenge, what’s your methodology? Do you have one? I don’t need to know, though if you think you have a good one, post a note in the discussion, or perhaps write an article. If you aren’t sure how you begin, other than randomly trying ideas you vaguely understand or have seen others try, perhaps you want to start by reading Kathi Kellenberger’s Step by Step method.

    The image above comes from Kathi’s article, and is indeed the result of her first solution to a complex T-SQL problem. She lists out the basic steps she used to derive the solution, along with the business rules used. All too often I’ve found developers (including myself), start writing code without taking a few minutes to specifically state the business rules. Following that one step might eliminate lots of bugs in coding.

    Her solution worked, but with 6 scans occurring on her 11 rows of data, she knew this would be an issue. Moving forward she asked for help, which is perfectly acceptable way of working in your career. Try to solve it yourself, get a solution working, and then ask if it can be improved. Not only did she end up with a better performing solution, but she learned a bit more along the way. Something we all can do.

    Steve Jones


    The Voice of the DBA Podcasts

    We publish three versions of the podcast each day for you to enjoy.

  • Getting Information from a Database using Dynamic SQL

    I ran across someone that was building a restore script to automated their restores. This person wanted their script to work with any instance, and that means they’d need to find the path for the database files, if the database already existed.

    It was interesting to me, and I decided to give a solution a try, and I ended up using dynamic SQL, which I don’t love, but it worked. As I was digging through, I realized that all the database data is in sys.master_files. However I’d started this and it was an intriguing problem. I don’t love this solution, and I wouldn’t use it here, but there might be a place where you can use it.

    To find out if a database exists, you can easily use the sys.databases view to find it.

    USE master
    GO
    DECLARE @path VARCHAR(500)
       , @db VARCHAR(200)
    ;
    
    SELECT @db = 'AdventureWorks2008'
    
    IF EXISTS (SELECT name
             FROM sys.databases
     WHERE name = @db
     )

    This is a snippet, and you need more code for this to work, but it does work if you include the “then” and “else” blocks. If the database doesn’t exist, you can grab the default file paths from the registry if you want to build the restore script, but if it does, then what.

    You want to find the database files, but these aren’t stored in master. If you query sys.database_files, you’ll get this:

    dbfilepath

    I have 8 or 10 databases on this instance, but none appear. However if I query a specific database, I get the files.

    dbfilepath2

    How do I get this data, in a script, given that I can’t execute a “use” statement easily at runtime.

    There are probably a few ways, but for me, I decided dynamic SQL might make sense her. This is an administrative task, so it’s not likely to allow for SQL Injection as I wouldn’t expose this for users to run.

    The first step is to build my query. In this case, I want to execute this query:

     select physical_name
      from AdventureWorks2008.sys.database_files
       where file_id = 1

    This isn’t ideal, in that I could have many files for this database, but for now I’m concerned with just getting the primary data file.

    I can build this string dynamically like this. Note that I’ve assigned the result to a variable for now.

    DECLARE @sqlCommand nvarchar(1000)
    DECLARE @db varchar(75)
    DECLARE @file VARCHAR(500)
    SET @db = 'AdventureWorks2008'
    SET @sqlCommand = 'select @f = physical_name from ' + @db + '.sys.database_files where file_id = 1'
    
    SElect @sqlCommand

    However now I need to run this command and return a value. sp_executesql is a function that allows you to execute a string, pass in parameters, and assign them back. I can do this with this script.

    DECLARE @sqlCommand nvarchar(1000)
    DECLARE @db varchar(75)
    DECLARE @file VARCHAR(500)
    
    SET @db = 'AdventureWorks2008'
    SET @sqlCommand = 'select @f = physical_name from ' + @db + '.sys.database_files where file_id = 1'
    
    EXECUTE sp_executesql @sqlCommand, N'@f varchar(500) OUTPUT', @f=@file OUTPUT
    
    select @file

    If I run this, I’ll get the file path from the AdventureWorks2008 primary data file.

    That’s the first step in this process. If I wanted to complete it, I’d have to make sure I did this for each data file, probably using some temporary table instead of a variable, and storing all the physical paths and logical names, and using those to build a dynamic restore script.

    Or I could download this script: SQL 2005 Restore Script Generator