patternsqlMinor
Passing a literal ? to sp_MSforeachdb
Viewed 0 times
sp_msforeachdbpassingliteral
Problem
I am trying to search for the
The WHERE clause at this time is:
This renders to:
I need it to render as:
? character in a string, but across all dbs on a server. Since the ? mark is a placeholder for the database name, how may I format the query so it knows I mean to search for ? and not replace it with the database name?The WHERE clause at this time is:
WHERE DirectoryPath LIKE ''%?%''This renders to:
WHERE DirectoryPath LIKE '%DATABASENAME%'I need it to render as:
WHERE DirectoryPath LIKE '%?%'Solution
Updates thanks to Martin. If you view the text for the procedure:
You will see that it passes the
Since it is really looking for the literal
So extrapolating that, we can construct this ugly variation:
That all said, you could write your own version of
-
https://sqlblog.org/2010/12/29/a-more-reliable-and-more-flexible-sp_msforeachdb
-
https://sqlblog.org/2010/02/08/bad-habits-to-kick-relying-on-undocumented-behavior
-
http://www.mssqltips.com/sqlservertip/2201/making-a-more-reliable-and-flexible-spmsforeachdb/
EXEC sys.sp_helptext N'sp_MSforeachdb';You will see that it passes the
@replacechar as NCHAR(1) (default N'?') into sys.sp_MSforeach_worker. Peeling back another layer of the onion, you will see really ugly code in that procedure that loops through every character in the command and rebuilds it. I didn't study every single line but I could not find any evidence of an ability to escape or preserve the actual question mark conditionally, unless - as Martin points out - you override it with a different character that can't naturally appear in the command. So perhaps something like:EXEC sp_MSforeachdb N'SELECT ''Ƥ'', other_columns FROM [?].dbo.whatever
WHERE DirectoryPath LIKE ''%?%'';', N'Ƥ';
-- Ƥ is NCHAR(420), chosen randomlySince it is really looking for the literal
? character, a possibly easier way would be this:EXEC sys.sp_MSforeachdb N'PRINT ''?'' + ''-'' + CONVERT(VARCHAR(32), 0x3F)';So extrapolating that, we can construct this ugly variation:
EXEC sys.sp_MSforeachdb N'SELECT ''?'', other_columns FROM [?].dbo.whatever
WHERE DirectoryPath LIKE ''%'' + CONVERT(VARCHAR(32), 0x3F) + ''%'';';That all said, you could write your own version of
sp_MSforeachdb that uses a different default value for @replacechar, so you don't have to override it manually. You probably should be writing your own version instead of relying on the built-in procedure anyway, as I point out in these posts - it is unsupported, undocumented, and actually has a very high frequency bug where it skips databases due to the cursor options used:-
https://sqlblog.org/2010/12/29/a-more-reliable-and-more-flexible-sp_msforeachdb
-
https://sqlblog.org/2010/02/08/bad-habits-to-kick-relying-on-undocumented-behavior
-
http://www.mssqltips.com/sqlservertip/2201/making-a-more-reliable-and-flexible-spmsforeachdb/
Code Snippets
EXEC sys.sp_helptext N'sp_MSforeachdb';EXEC sp_MSforeachdb N'SELECT ''Ƥ'', other_columns FROM [?].dbo.whatever
WHERE DirectoryPath LIKE ''%?%'';', N'Ƥ';
-- Ƥ is NCHAR(420), chosen randomlyEXEC sys.sp_MSforeachdb N'PRINT ''?'' + ''-'' + CONVERT(VARCHAR(32), 0x3F)';EXEC sys.sp_MSforeachdb N'SELECT ''?'', other_columns FROM [?].dbo.whatever
WHERE DirectoryPath LIKE ''%'' + CONVERT(VARCHAR(32), 0x3F) + ''%'';';Context
StackExchange Database Administrators Q#52073, answer score: 7
Revisions (0)
No revisions yet.