Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Data Management

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

    Search

    XML Feeds

    Google Ads

    « SQL Advent 2012 Day 6: Standardized Naming And Other ConventionsDealing with the Column name 'TEXT()' contains an invalid XML identifier as required by FOR XML; '('(0x0028) is the first character at fault error »
    comments

    This is day five of the SQL Advent 2012 series of blog posts. Today we are going to look at why you need to be able to write your own DDL statements.

    Read the following two lines, have you ever answered that or has anyone every answered that when asked this question?

    Question: How do you add a primary key to a table?
    Answer: I click on the yellow key icon in SSMS!

    Technically, yes, that will create a primary key on the table but what will happen when you do that? Let's take a look at some examples.

    First create this very simple table

    1. CREATE TABLE TestInt(Col1 tinyint not null)

    Now they users changed their mind and want to insert values that go beyond what a tinyint can hold. If you try to insert 300, you will get an error

    1. INSERT TestInt VALUES(300)

    Msg 220, Level 16, State 2, Line 2
    Arithmetic overflow error for data type tinyint, value = 300.
    The statement has been terminated.

    No, problem, I will just change the data type

    1. ALTER TABLE TestInt ALTER COLUMN Col1 int NOT NULL

    But what if you use the SSMS designer by right clicking on the table, choosing design and then changing the data type from tinyint to int? Here is what SSMS will do behind the scenes for you

    1. /* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
    2. BEGIN TRANSACTION
    3. SET QUOTED_IDENTIFIER ON
    4. SET ARITHABORT ON
    5. SET NUMERIC_ROUNDABORT OFF
    6. SET CONCAT_NULL_YIELDS_NULL ON
    7. SET ANSI_NULLS ON
    8. SET ANSI_PADDING ON
    9. SET ANSI_WARNINGS ON
    10. COMMIT
    11. BEGIN TRANSACTION
    12. GO
    13. CREATE TABLE dbo.Tmp_TestInt
    14.     (
    15.     Col1 int NULL
    16.     )  ON [PRIMARY]
    17. GO
    18. ALTER TABLE dbo.Tmp_TestInt SET (LOCK_ESCALATION = TABLE)
    19. GO
    20. IF EXISTS(SELECT * FROM dbo.TestInt)
    21.      EXEC('INSERT INTO dbo.Tmp_TestInt (Col1)
    22.         SELECT CONVERT(int, Col1) FROM dbo.TestInt WITH (HOLDLOCK TABLOCKX)')
    23. GO
    24. DROP TABLE dbo.TestInt
    25. GO
    26. EXECUTE sp_rename N'dbo.Tmp_TestInt', N'TestInt', 'OBJECT'
    27. GO
    28. COMMIT

    That is right, it will create a new table, dump all the rows into this table, drop the original table and then rename the table that was just created to match the orginal table. This is overkill.

    What about adding some defaults to the table, if you use the SSMS table designer, it will just create those and you have no way to specify a name for the default.

    Here is how to create a default with T-SQL, now you can specify a name and make sure it matches your shop's naming convention

    1. ALTER TABLE dbo.TestInt ADD CONSTRAINT
    2.     DF_TestInt_Col1 DEFAULT 1 FOR Col1

    About that yellow key icon, let's add a primary key to our table, I can do the following with T-SQL, I can also make it non clustered if I want to

    1. ALTER TABLE dbo.TestInt ADD CONSTRAINT
    2.     PK_TestInt PRIMARY KEY CLUSTERED
    3.     (Col1)  ON [PRIMARY]

    Click that yellow key icon and here is what happens behind the scenes, I have not found a way to make it non clustered from the designer

    1. /* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
    2. BEGIN TRANSACTION
    3. SET QUOTED_IDENTIFIER ON
    4. SET ARITHABORT ON
    5. SET NUMERIC_ROUNDABORT OFF
    6. SET CONCAT_NULL_YIELDS_NULL ON
    7. SET ANSI_NULLS ON
    8. SET ANSI_PADDING ON
    9. SET ANSI_WARNINGS ON
    10. COMMIT
    11. BEGIN TRANSACTION
    12. GO
    13. ALTER TABLE dbo.TestInt
    14.     DROP CONSTRAINT DF_TestInt_Col1
    15. GO
    16. CREATE TABLE dbo.Tmp_TestInt
    17.     (
    18.     Col1 int NOT NULL
    19.     )  ON [PRIMARY]
    20. GO
    21. ALTER TABLE dbo.Tmp_TestInt SET (LOCK_ESCALATION = TABLE)
    22. GO
    23. ALTER TABLE dbo.Tmp_TestInt ADD CONSTRAINT
    24.     DF_TestInt_Col1 DEFAULT ((1)) FOR Col1
    25. GO
    26. IF EXISTS(SELECT * FROM dbo.TestInt)
    27.      EXEC('INSERT INTO dbo.Tmp_TestInt (Col1)
    28.         SELECT Col1 FROM dbo.TestInt WITH (HOLDLOCK TABLOCKX)')
    29. GO
    30. DROP TABLE dbo.TestInt
    31. GO
    32. EXECUTE sp_rename N'dbo.Tmp_TestInt', N'TestInt', 'OBJECT'
    33. GO
    34. ALTER TABLE dbo.TestInt ADD CONSTRAINT
    35.     PK_TestInt PRIMARY KEY CLUSTERED
    36.     (
    37.     Col1
    38.     ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    39.  
    40. GO
    41. COMMIT

    You might ask yourself why you should care, all the tables are small, this is not a big issue. This might be true now, what if you start a new job and now you have to supply alter, delete and create scripts? Now you are in trouble. I used to do the same when I started, I used the designers for everything, I didn't even know Query Analyzer existed when I started, I created and modified the stored procedures straight inside Enterprise Manager. Trying to modify a view that had a CASE statement in Enterprise Manager from the designer....yeah good luck with that one....you would get some error that it wasn't supported, I believe it also injected TOP 100 PERCENT ORDER BY in the view as well

    I don't miss those days at all. Get to learn T-SQL and get to love it, you might suffer when you start but you will become a better database developer.

    Aaron Bertrand also has a post that you should read about the designers: Bad habits to kick : using the visual designers



    That is all for day five of the SQL Advent 2012 series, come back tomorrow for the next one, you can also check out all the posts from last year here: SQL Advent 2011 Recap

    About the Author

    User bio imageDenis has been working with SQL Server since version 6.5. Although he worked as an ASP/JSP/ColdFusion developer before the dot com bust, he has been working exclusively as a database developer/architect since 2002. In addition to English, Denis is also fluent in Croatian and Dutch, but he can curse in many other languages and dialects (just ask the SQL optimizer) He lives in Princeton, NJ with his wife and three kids.
    Social SitingsTwitterFacebookLinkedInHomePageFlickrLTD RSS Feed
    2865 views
    InstapaperVote on HN

    7 comments

    Comment from: sqlsister [Member] Email
    sqlsister Also, changes to the database struture should be treated like all code and put under source control so they can easily be deployed. Writing a script to put into your source control system is one of the best ways to do this.
    12/05/12 @ 08:19
    Comment from: SQLDenis [Member] Email
    SQLDenis sqlsister, I agree, this also makes it much easier to recreate the DB from scratch as well
    12/05/12 @ 08:21
    Comment from: Paul Hunter [Visitor]
    Paul Hunter One thing I notice is that non-SQL folk can use T-SQL to create defaults and checks, but not give them names...

    ALTER TABLE my_table ADD new_column INT NOT NULL DEFAULT (0) WITH VALUES;

    SQL Server will then assign a random name as it does with the designer.

    I like having properly defined names for default, check and foriegn key constraints -- well all SQL objects. Everyone should create and publish a standards document that specifies how to properly name objects and a whole lot of other stuff. You'll end up with a lot less confusion for everyone concerned.
    12/05/12 @ 08:39
    Comment from: SQLDenis [Member] Email
    SQLDenis Paul, you are correct that you can create randomly named constraints in T-SQL as well, see this post here: How To Name Default Constraints And How To Drop Default Constraint Without A Name In SQL Server, it explains how you can find these 'unnamed' constraints
    12/05/12 @ 08:45
    Comment from: Paul Hunter [Visitor]
    Paul Hunter Interesting post for finding "unnamed" constraints.

    For SQL 2005+ you can use the system catalogs. For example:

    select * from sys.default_constraints
    where is_system_named = 1

    There are views for: foreign_keys, check_constraints, and key_constraints.




    12/05/12 @ 16:02
    Comment from: ta.speot.is [Visitor] · http://ta.speot.is
    ta.speot.is Unless I'm mistaken, you can't make changes through the designer that involve dropping and recreating a table unless you opt into doing so. Out of the box, SSMS will not allow you to do it.

    The "Prevent saving changes that require table re-creation" option is enabled by default and the limitations and risks of turning it off are pretty well documented:

    http://support.microsoft.com/kb/956176
    12/08/12 @ 22:15
    Comment from: SQLDenis [Member] Email
    SQLDenis You know how many times I have answered how to turn that behavior off? Take a look at Stackoverflow how many times this question has been asked: http://stackoverflow.com/search?q=Prevent+saving+changes+that+require+table+re-creation&submit=search

    I don't think these people once they turn it off realize what happens next time they do a change where SSMS just goes ahead and recreates the table
    12/09/12 @ 05:10

    Leave a comment


    Your email address will not be revealed on this site.

    To mislead the spambots.

    Your URL will be displayed.
    (Line breaks become <br />)
    (Name, email & website)
    (Allow users to contact you through a message form (your email will not be revealed.)