Adding quotes to dynamic SQL

  • This is driving me nuts. I know I'm missing something really simple, but I can't figure out what it is. So I'd appreciate a quick peer review.

    We're in the middle of upgrading our servers. I'm identifying all objects that will be affected by a server split (I.E., they'll need a linked server added) and am loading that information into a table so I can do this one at a time. EDIT: I'm trying to write sp_helptext sql commands into a column of my table. That way I can just cut-n-paste the silly thing from my table into a query window and run the code.

    I've messed with these stupid single quotes so many times Here's what I've got:

    IF (SELECT Table_Name FROM Information_schema.Tables WHERE Table_Name = 'SQL2012_useBI_UpdateObjects' ) IS NULL

    CREATE TABLE dbo.SQL2012_useBI_UpdateObjects (DBName VARCHAR(50), Reference VARCHAR(20),

    ObjectName VARCHAR(200), ObjectType VARCHAR(2), SchemaName VARCHAR(50), HelpTextCmd VARCHAR(300));

    EXEC sp_MSforeachDB @Command1 = 'USE [?];

    INSERT INTO dbo.SQL2012_useBI_UpdateObjects

    (DBName, Reference, ObjectName, ObjectType, SchemaName, HelpTextCmd)

    SELECT DB_Name(), ''BI_'', CONVERT(VARCHAR(200),so.Name),

    so.type, CONVERT(VARCHAR(50),ss.name),

    '' USE '' + CONVERT(VARCHAR(50),DB_Name()) + '' EXEC sp_helptext '' + ss.name + ''.'' + so.name + '';''

    FROM sys.objects so

    INNER JOIN sys.schemas ss

    ON so.schema_id = ss.schema_id

    INNER JOIN sysusers su

    ON so.schema_id = su.UID

    INNER JOIN sys.sql_modules sm

    ON so.Object_ID = sm.Object_ID

    WHERE sm.definition LIKE ''%BI[_]%'''

    This works, except it won't put single quotes around the schema.table name. I get "USE DBName EXEC sp_helptext MySchema.MyTable;" when I'm trying to get "USE DBName EXEC sp_helptext 'MySchema.MyTable';" as the result.

    But every time I mess with the code, it errors out.

    I tried:

    EXEC sp_MSforeachDB @Command1 = 'USE [?];

    SELECT DB_Name(), ''BI_'', CONVERT(VARCHAR(200),so.Name), so.type, CONVERT(VARCHAR(50),ss.name),

    '' USE '' + CONVERT(VARCHAR(50),DB_Name()) + '' EXEC sp_helptext '''' + ss.name + ''.'' + so.name + '''';''

    FROM sys.objects so

    INNER JOIN sys.schemas ss

    ON so.schema_id = ss.schema_id

    INNER JOIN sysusers su

    ON so.schema_id = su.UID

    INNER JOIN sys.sql_modules sm

    ON so.Object_ID = sm.Object_ID

    WHERE sm.definition LIKE ''%BI[_]%''

    ORDER BY so.type, so.Name'

    And get "Msg 102, Level 15, State 1, Line 6

    Incorrect syntax near ' + so.name + ';'."

    And then, when I manage not to get an error, I end up with it literally adding "ss.name" and "so.name" to the string (like "EXEC sp_helptext + ss.name...").

    Can someone help me figure out what I'm missing here?

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • Check out the QuoteName function in BOL.

    __________________________________________________________________________________________________________
    How to Post to get the most: http://www.sqlservercentral.com/articles/Best+Practices/61537/

  • Short suggestion, CHAR(39)

    😎

  • So, the trick is that in the innermost quoted command, the EXEC sp_helptext, you want single quotes around schema.object. Since it's inside a string, each of those single quotes will need to be escaped, so you'll need two consecutive single quotes for each of the single quotes you want.

    However, that is also inside a string, so each of those single quotes will need to be escaped. That means you'll need four consecutive single quotes for each single quote in the innermost string.

    Something like this:

    IF (SELECT Table_Name FROM Information_schema.Tables WHERE Table_Name = 'SQL2012_useBI_UpdateObjects' ) IS NULL

    CREATE TABLE dbo.SQL2012_useBI_UpdateObjects (DBName VARCHAR(50), Reference VARCHAR(20),

    ObjectName VARCHAR(200), ObjectType VARCHAR(2), SchemaName VARCHAR(50), HelpTextCmd VARCHAR(300));

    EXEC sp_MSforeachDB @Command1 = 'USE [?];

    INSERT INTO CreditDBA_Admin.dbo.SQL2012_useBI_UpdateObjects

    (DBName, Reference, ObjectName, ObjectType, SchemaName, HelpTextCmd)

    SELECT DB_Name(), ''BI_'', CONVERT(VARCHAR(200),so.Name),

    so.type, CONVERT(VARCHAR(50),ss.name),

    '' USE '' + CONVERT(VARCHAR(50),DB_Name()) + '' EXEC sp_helptext '''''' + ss.name + ''.'' + so.name + '''''';''

    FROM sys.objects so

    INNER JOIN sys.schemas ss

    ON so.schema_id = ss.schema_id

    INNER JOIN sysusers su

    ON so.schema_id = su.UID

    INNER JOIN sys.sql_modules sm

    ON so.Object_ID = sm.Object_ID

    WHERE sm.definition LIKE ''%BI[_]%'''

    Cheers!

  • The easy way to do this is to create the results that you are looking for and then globally replace all of the single quotes with two single quotes before adding the single quotes around the whole expression.

    Drew

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

  • Jacob Wilkins (2/11/2016)


    So, the trick is that in the innermost quoted command, the EXEC sp_helptext, you want single quotes around schema.object. Since it's inside a string, each of those single quotes will need to be escaped, so you'll need two consecutive single quotes for each of the single quotes you want.

    However, that is also inside a string, so each of those single quotes will need to be escaped. That means you'll need four consecutive single quotes for each single quote in the innermost string.

    Something like this:

    IF (SELECT Table_Name FROM Information_schema.Tables WHERE Table_Name = 'SQL2012_useBI_UpdateObjects' ) IS NULL

    CREATE TABLE dbo.SQL2012_useBI_UpdateObjects (DBName VARCHAR(50), Reference VARCHAR(20),

    ObjectName VARCHAR(200), ObjectType VARCHAR(2), SchemaName VARCHAR(50), HelpTextCmd VARCHAR(300));

    EXEC sp_MSforeachDB @Command1 = 'USE [?];

    INSERT INTO dbo.SQL2012_useBI_UpdateObjects

    (DBName, Reference, ObjectName, ObjectType, SchemaName, HelpTextCmd)

    SELECT DB_Name(), ''BI_'', CONVERT(VARCHAR(200),so.Name),

    so.type, CONVERT(VARCHAR(50),ss.name),

    '' USE '' + CONVERT(VARCHAR(50),DB_Name()) + '' EXEC sp_helptext '''''' + ss.name + ''.'' + so.name + '''''';''

    FROM sys.objects so

    INNER JOIN sys.schemas ss

    ON so.schema_id = ss.schema_id

    INNER JOIN sysusers su

    ON so.schema_id = su.UID

    INNER JOIN sys.sql_modules sm

    ON so.Object_ID = sm.Object_ID

    WHERE sm.definition LIKE ''%BI[_]%'''

    Cheers!

    GRRRRR. I spent 3 hours trying to find this solution. I did escape my quotes. Honest I did.

    Now I get to go count your quotes vs mine to find out where it was I mucked up. Thanks, Jacob. This help.

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • So apparently I didn't go far enough on my quotes. I was doing 4 / 5 instead of 6. At least it works now.

    Thanks, everyone.

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • Glad I could help!

    If it helps, here's that string constructed step-by-step (all of it assuming your FROM clause):

    Step 1:

    SELECT 'EXEC sp_helptext '+ss.name+'.'+so.name+';'

    That generates the EXEC sp_helptext for every schema.object, but there are no single quotes around schema.object. To do that, we need insert a literal single quote into the string, which of course needs to be escaped, so we insert a pair of single quotes in the appropriate places:

    SELECT 'EXEC sp_helptext '''+ss.name+'.'+so.name+''';'

    That gives us what we want when run with your FROM clause as a standalone query. Of course, all of this is within the string for EXEC sp_MSforeachDB, so each of the single quotes in that above command need to be escaped with another single quote. The occurrences of 1 single quote become 2, and the occurrences of 3 single quotes become 6, yielding the version in code I posted.

    I know all too well how easy it is to get all turned around with multiple levels of dynamic SQL, so I'm just glad I could help end the struggle against the insidious single quote 🙂

  • Slightly longer suggestion here

    😎

  • Whenever I am building out dynamic SQL I always use SET QUOTED_IDENFITIER OFF first and then use double quotes in the outer sections of text. Then I never have to worry about how many stupid single quotes I need to string together to get the various requirements needed!! 😎

    Best,
    Kevin G. Boles
    SQL Server Consultant
    SQL MVP 2007-2012
    TheSQLGuru on googles mail service

  • TheSQLGuru (2/11/2016)


    Whenever I am building out dynamic SQL I always use SET QUOTED_IDENFITIER OFF first and then use double quotes in the outer sections of text. Then I never have to worry about how many stupid single quotes I need to string together to get the various requirements needed!! 😎

    Oh, stop being logical.

    We're DBAs. Logic isn't supposed to be a part of our jobs. @=)

    EDIT: And thank you for the suggestion. I'll look into it.

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • Brandie Tarvin (2/12/2016)


    TheSQLGuru (2/11/2016)


    Whenever I am building out dynamic SQL I always use SET QUOTED_IDENFITIER OFF first and then use double quotes in the outer sections of text. Then I never have to worry about how many stupid single quotes I need to string together to get the various requirements needed!! 😎

    Oh, stop being logical.

    We're DBAs. Logic isn't supposed to be a part of our jobs. @=)

    EDIT: And thank you for the suggestion. I'll look into it.

    While I am EXCEPTIONALLY logical and rational (just ask my wife and daughter!!), this recommendation has more to do with one of my other significant traits: I am also exceptionally LAZY!! 😀

    And you are welcome! This little tip WILL save you a LOT of irritation when dealing with dynamic SQL, I promise!

    Best,
    Kevin G. Boles
    SQL Server Consultant
    SQL MVP 2007-2012
    TheSQLGuru on googles mail service

  • TheSQLGuru (2/12/2016)


    Brandie Tarvin (2/12/2016)


    TheSQLGuru (2/11/2016)


    Whenever I am building out dynamic SQL I always use SET QUOTED_IDENFITIER OFF first and then use double quotes in the outer sections of text. Then I never have to worry about how many stupid single quotes I need to string together to get the various requirements needed!! 😎

    Oh, stop being logical.

    We're DBAs. Logic isn't supposed to be a part of our jobs. @=)

    EDIT: And thank you for the suggestion. I'll look into it.

    While I am EXCEPTIONALLY logical and rational (just ask my wife and daughter!!), this recommendation has more to do with one of my other significant traits: I am also exceptionally LAZY!! 😀

    And you are welcome! This little tip WILL save you a LOT of irritation when dealing with dynamic SQL, I promise!

    I'll have to give this tip a try next time I write dynamic SQL. Which could be really soon since I tend to write quite a bit here due to the lack of design work done for the database. It basically is treated as a data store.

  • TheSQLGuru (2/11/2016)


    Whenever I am building out dynamic SQL I always use SET QUOTED_IDENFITIER OFF first and then use double quotes in the outer sections of text. Then I never have to worry about how many stupid single quotes I need to string together to get the various requirements needed!! 😎

    Wait. You set QUOTED_IDENTIFIER OFF? Not ON?

    Brandie Tarvin, MCITP Database AdministratorLiveJournal Blog: http://brandietarvin.livejournal.com/[/url]On LinkedIn!, Google+, and Twitter.Freelance Writer: ShadowrunLatchkeys: Nevermore, Latchkeys: The Bootleg War, and Latchkeys: Roscoes in the Night are now available on Nook and Kindle.

  • Brandie Tarvin (2/26/2016)


    TheSQLGuru (2/11/2016)


    Whenever I am building out dynamic SQL I always use SET QUOTED_IDENFITIER OFF first and then use double quotes in the outer sections of text. Then I never have to worry about how many stupid single quotes I need to string together to get the various requirements needed!! 😎

    Wait. You set QUOTED_IDENTIFIER OFF? Not ON?

    Of course. Simple test/proof:

    SET QUOTED_IDENTIFIER OFF

    GO

    CREATE TABLE #tmp (a varchar(10))

    GO

    INSERT #tmp VALUES ('asdf')

    go

    DECLARE @a varchar(10) = 'asdf'

    EXEC ("select * from #tmp where a = '" + @a + "'")

    GO

    PRINT "DONE"

    GO

    SET QUOTED_IDENTIFIER ON

    GO

    DECLARE @a varchar(10) = 'asdf'

    EXEC ("select * from #tmp where a = '" + @a + "'")

    DROP TABLE #tmp

    Best,
    Kevin G. Boles
    SQL Server Consultant
    SQL MVP 2007-2012
    TheSQLGuru on googles mail service

Viewing 15 posts - 1 through 15 (of 15 total)

You must be logged in to reply to this topic. Login to reply