Tag: T-SQL

  • T-SQL Tuesday #69–Encryption

    TSQL2sDay150x150This is a good T-SQL Tuesday topic for me. This month Ken Wilson asks everyone to write on encryption, which is a topic I’ve presented on quite a few times.

    You can participate, too. Take a few hours, learn something, and tell us what you learned. Let everyone know how you view this topic and grow your blog with a little new knowledge.

    T-SQL Tuesday is a great chance to force you to write a post on a specific topic. Your post needs to publish on the second Tuesday of the month, Aug 11 this month, to be included in the roundup from the host. However feel free to write about this topic anytime, and even include the T-SQL Tuesday title.

    CASTing Results

    A short post this month, as I’m a bit buried in a few things, but this is one of those encryption notes that I didn’t see well documented when I started working with the subject, and I’m hoping I can save you a few minutes of frustration.

    If you encrypt your data, it will be stored as a binary type. This is because encrypted data is supposed to be random, and not easily decrypted.

    Let’s imagine I have some simple setup like the code below. I’ll create a key, open it, and use it to encrypt some data that I’ll insert into a table.

    CREATE TABLE MyEncryptionTest( intsource INT, charsource VARCHAR(50), intencrypt VARBINARY(max), charencrypt VARBINARY(max));
    CREATE SYMMETRIC KEY Mykey WITH    ALGORITHM = AES_128 ENCRYPTION BY PASSWORD = 'M$test78';
    GO
    OPEN SYMMETRIC KEY MyKey DECRYPTION BY PASSWORD = 'M$test78';
    
    INSERT dbo.MyEncryptionTest
            ( intsource ,
              charsource ,
              intencrypt ,
              charencrypt
            )
    VALUES  ( 7, 
              'Spike' , 
              ENCRYPTBYKEY(KEY_GUID('MyKey'), CAST(7 AS VARCHAR(10))) ,
              ENCRYPTBYKEY(KEY_GUID('MyKey'), 'Spike')
            );
    
    SELECT top 20
     * FROM dbo.MyEncryptionTest;
    
    

    The results of this are that I get binary data:

    2015-08-04 22_10_22-SQLQuery1.sql - ARISTOTLE.sandbox (ARISTOTLE_Steve (76))_ - Microsoft SQL Server

    Now, the decryption routine for T-SQL doesn’t need to specify the key. That means instead of a *, I can use the DECRYPTBYKEY function and pass in the column.

    SELECT TOP 20
            intdecrypt = DECRYPTBYKEY(intencrypt),
            chardecrypt = DECRYPTBYKEY(charencrypt) ,
            intencrypt ,
            charencrypt
    FROM    dbo.MyEncryptionTest;
    
    

    This gives me this:

    2015-08-04 22_12_22-SQLQuery1.sql - ARISTOTLE.sandbox (ARISTOTLE_Steve (76))_ - Microsoft SQL Server

    Not quite what I want. What if I cast this back to an integer? After all, the output of the function is listed as an nvarchar.

    SELECT TOP 20
            intdecrypt = CAST(DECRYPTBYKEY(intencrypt) AS INT),
            chardecrypt = DECRYPTBYKEY(charencrypt) ,
            intencrypt ,
            charencrypt
    FROM    dbo.MyEncryptionTest;
    
    

    I see:

    2015-08-04 22_18_10-SQLQuery1.sql - ARISTOTLE.sandbox (ARISTOTLE_Steve (76))_ - Microsoft SQL Server

    Again, not what I wanted. However, since I know something about conversions, I realize the output is close to what I want. In fact, what I need to do is perform a different CAST before I perform my final one. Here I’ll decrypt the results as NVARCHAR first, then as an INT.

    SELECT TOP 20
            intdecrypt = CAST(CAST(DECRYPTBYKEY(intencrypt) AS NVARCHAR(30)) AS INT),
            chardecrypt = DECRYPTBYKEY(charencrypt) ,
            intencrypt ,
            charencrypt
    FROM    dbo.MyEncryptionTest;
    
    
    

    Now I see:

    2015-08-04 22_15_29-SQLQuery1.sql - ARISTOTLE.sandbox (ARISTOTLE_Steve (76))_ - Microsoft SQL Server

    If I do the same for the character column:

    SELECT TOP 20
            intdecrypt = CAST(CAST(DECRYPTBYKEY(intencrypt) AS NVARCHAR(30)) AS INT),
            chardecrypt = CAST( DECRYPTBYKEY(charencrypt) AS VARCHAR(50)) ,
            intencrypt ,
            charencrypt
    FROM    dbo.MyEncryptionTest;
    
    

    I’ll get the correct results.

    2015-08-04 22_17_11-SQLQuery1.sql - ARISTOTLE.sandbox (ARISTOTLE_Steve (76))_ - Microsoft SQL Server

    Note that if I take the character column and cast to nvarchar, I’ll get something different. Try it and see.

    And don’t forget to close your key.

    CLOSE SYMMETRIC KEY mykey;
    
    
  • Loading XML Data–CONVERT Option 2

    I was playing around with some XML lately, and had to load a file that looked like this::

    2015-07-22 14_40_59-mathis.xml - Notepad

    I ran a simple query, one that used the OPENROWSET and a CONVERT to load the data.

    WITH XmlFile (Contents) AS (
    SELECT CONVERT (XML, BulkColumn) 
    FROM OPENROWSET (BULK 'C:\mathis.xml', SINGLE_BLOB) AS XmlData
    )
    SELECT *
    FROM   XmlFile
    GO
    

    However, that didn’t work. I received this message in SSMS.

    Msg 6359, Level 16, State 1, Line 1

    Parsing XML with internal subset DTDs not allowed. Use CONVERT with style option 2 to enable limited internal subset DTD support.

    Hmmm. That seems to make sense. Let’s add an option to CONVERT of 2. I’ve assumed the last parameter is the one mentioned, as with date conversions, and added that. I can hover with SQL Prompt and see that.

    2015-07-22 14_43_13-SQLQuery1.sql - ARISTOTLE.sandbox (ARISTOTLE_Steve (71))_ - Microsoft SQL Server

    Let’s change the code:

    WITH XmlFile (Contents) AS (
    SELECT CONVERT (XML, BulkColumn,2) 
    FROM OPENROWSET (BULK 'C:\mathis.xml', SINGLE_BLOB) AS XmlData
    )
    SELECT *
    FROM   XmlFile
    GO
    

    That works.

    Why?

    If you go to the BOL page for CAST and CONVERT, you will find an XML styles section. There are possible values of 0 (default), 1, 2, and 3. In this case, the 2 enables an internal DTD processing, which basically uses a default document of sorts for parsing the XML. No external DTD is needed and this is treated as a standalone document.

    I am not an XML expert, but I’m guessing here that I’ve included a document that doesn’t conform to some specification and the additional style parameter allows SQL Server to ignore some of what’s there.

    If anyone knows more, I would like to better understand how this works.

  • Presenting Data

    Many of us that develop or manage database systems are concerned with the actual bits and bytes that compromise data. However our clients and customers are more interested in the information, in gaining knowledge from the numbers, strings, and dates that are kept in our database tables.

    I really think that one of those things that can truly allow a developer or DBA to show their employer they are valuable to the organization. Employees prove this when they can retrieve information in a way that clients find valuable. Not that we, as the technical people value, but in the ways that clients find valuable.

    This doesn’t mean you need to learn PowerBI or PowerPivot or any other Power tools, but that you learn how to present the data you work with in the best way you can. Whether that’s in an SSRS report, an Excel worksheet you email around, or a complex visualization, all of these formats have one thing in common: a query. One of the best things you can do as a developer or DBA is ensure you can write efficient queries that assemble data from a variety of tables in different formats. Queries that retrieve data that can answer a question or reveal a pattern.

    Learning how to build a fancy visualization is great, but be flexible. If you get the opportunity, work with a new technology and develop some comfort, take it. However make sure that above everything else you can get the data sets to the end user. Clients can always use their own tools, but the efficiency and performance they experience will often come down to your query writing skills.

    Make sure you are constantly improving those skills.

    Steve Jones

    The Voice of the DBA Podcast

    Listen to the MP3 Audio ( 2.0MB) podcast or subscribe to the feed at iTunes and LibSyn.

  • Get a comma separated list

    I’m writing this post as a way to help motivate the #SQLNewBloggers out there. Read the bottom for a few notes on structuring a post.

    I was working on a test of sorts and wanted to return multiple values as the output, but as a single variable. In other words, I couldn’t return a result set, I needed to return a string.

    I knew this was easy, and decided this would make a nice simple blog. Here we go.

    Let’s start with a simple table. Here’s one that has a few rows in it.

    CREATE TABLE MyTest
    ( id int);
    GO
    INSERT mytest values (1), (2), (3);
    go

    I want to return the values “1, 2, 3” as a string, in any order. Here’s how it works:

    DECLARE @i VARCHAR(MAX);
    SELECT @i = COALESCE(@i + ‘, ‘,”) + CAST( Id AS VARCHAR)
    FROM MyTest;
    SELECT @i;

    The COALESCE is important as the first time this runs, we have a NULL for the variable. In this case, we return an empty string. This is almost like the inverse of the operation that ends recursion. We add in the first row, and we end up with ‘1’ as the string.

    Note: it could be 2 or 3 in the string as I don’t have an ORDER BY. DO NOT depend on the order of insertion in the table. If you care about ordering, always include an ORDER BY.

    The next execution has a blank string (NOT NULL), so that is returned. In this case, we have ‘1’ + ‘, ‘ for the first part. The second part adds in the next row.

    This continues, and I get a nice set of output.

    2015-06-10 17_20_39-SQLQuery4.sql - ARISTOTLE.sandbox (ARISTOTLE_Steve (62))_ - Microsoft SQL Server

    SQLNewBlogger

    This one was short. It took me almost as much time to write the code and find a reference as it did to write the post. Five minutes.

    References

    This is basic T-SQL, but here’s another look at this.