home
-- TSQL - Custom Keyboard Shortcuts, building dynamic sql
Author Nigel Rivett
I recently had a request to create a keyboard shortcut to highlight a table name and return the top 10 rows from all tables with that name.
An added complication is that if a schema is included it should return just that table (note, this needs to in quotes to work with the shortcut).
keyboard shortcuts are meant to take stored procedures and append the highlighted text.
This is fine if you can create a stored procedure in the database but if not you need to work with what is already available.
To create a shortcut in management studio
tools, options, Keyboard.Query Shortcuts
Select a free entry and type in the query and save
Any new query window will be able to access the shortcut
Note: already open windows will not access it.
first of all some test data
create schema a
go
create schema b
go
create table a.t1 (s varchar(20))
go
create table b.t1 (s varchar(20))
go
create table dbo.t1 (s varchar(20))
go
insert a.t1 select 'qwer'
insert a.t1 select 'qwer'
go
insert b.t1 select 'qwerty'
insert b.t1 select 'qwerty'
go
insert dbo.t1 select 'dboversion'
insert dbo.t1 select 'dboversion'
go
select * from a.t1
select * from b.t1
select * from t1
Try this with
select top 10 * from
ctrl+3 is probably the first open entry.
Open a new query window.
Type in t1, highlight it and press ctrl+3 and it should give up to 10 rows from the default schema table (dbo?).
In a stored procedure I would probably get all the tables with that name and loop through them.
But here we cann't create a stored procedure and the query needs to have the table name as the last text.
I will now go through the process of building the query.
This introduces techniques of how to biold any dynamic sql query.
There may be other ways to do this and maybe other features with keyboard shortcuts but the my first thought is
sp_executeSQL - this will take a parameter as the last item which can be used in a query.
so
sp_executesql N'select top 10 * from t1
Returns the result
But
sp_executesql N'select top 10 * from @obj', N'@obj varchar(200)', @obj=t1
gives an error.
The parameter can be used in an expression but not as a tablename as in
sp_executesql N'select top 10 * from t1 where s = @obj', N'@obj varchar(200)', @obj='dboversion'
What we need is to 9execute
'select top 10 * from ' + @obj
or
'select top 10 * from ' + 't1'
of course
sp_executesql N'select top 10 * from ' + 't1'
fails because a stored procedure doesn't accept an expression as a parameter.
We need something that will search for tablenames and execute the select statment onm each one.
When written like that it immediately suggests sp_MSforeachtable
This table a command which will be executed on each table returned by a where clause filter.
It's worth looking at the script for the stored procedure to see how it works and what is needed.
The where clause for the sp is
+ N' where OBJECTPROPERTY(o.id, N''IsUserTable'') = 1 ' + N' and o.category & ' + @mscat + N' = 0 '
+ @whereand)
so
sp_MSforeachtable 'select top 10 * from ?', @whereand=' and (o.name=''t1'')
This returns the data from each table and also uses a parameter for the table name.
It looks like we are getting close
sp_executesql can take the table name as a parameter to execute a query
sp_MSforeachtable can execute a query on each table with a given name.
All we need to do is to get sp_execute sql to create the query using sp_MSforeachtable then execute it.
declare @s nvarchar(1000)
select @s = 'sp_MSforeachtable sp_MSforeachtable @command1=''select top 10 * from ?'', @whereand='' and ( o.name=''''t1'''' )'''
exec sp_executesql @s, N'@obj varchar(200)', @obj='t1'
Looks promising and produces the result.
Notice the doubling of the quotes as we go deeper into the embedded queries.
But if we replace the literal table name with the parameter
declare @s nvarchar(1000)
select @s = 'sp_MSforeachtable sp_MSforeachtable @command1=''select top 10 * from ?'', @whereand='' and ( o.name=''''@obj'''' )'''
exec sp_executesql @s, N'@obj varchar(200)', @obj='t1'
We get nothing. "obj is now a character string in the query not a parameter.
We need to be able to build the query string using @obj as a parameter.
If you've built queries using dynamic sql you'll know that exec ('...') will do exectly that.
So we are looking for a query of the form
sp_MSforeachtable sp_MSforeachtable @command1='select top 10 * from ?', @whereand=' and ( o.name=''' + @obj + ''' )'
To do this we wrap this in an exec so that it buidls the statement.
exec ('sp_MSforeachtable sp_MSforeachtable @command1=''select top 10 * from ?'', @whereand='' and ( o.name='''''' + @obj + '''''' )'''
Now we wrap this in sp_executesql to pass in the parameter
sp_executesql N'exec (''sp_MSforeachtable @command1=''''select top 10 * from ?'''', @whereand='''' and ( o.name='''''''''' + @obj + '''''''''' )'''' '')', N'@obj varchar(200)', @obj=t1
And this gives the result.
There was a second part though - to return the result from the single table if the schema is included.
This is not difficult as we can use object_id to check if the full table identifier is resolved or we can check for a full stop in the name if the default schema is also being used.
just change the @whereand clause (and this is why I always include brackets because this is concatenated with a where clause in stored procedure).
( o.name='''''''''' + @obj + '''''''''' )
becomes
( (object_id('''''''''' + @obj + '''''''''') is not null and o.id = object_id('''''''''' + @obj + '''''''''')) or (object_id('''''''''' + @obj + '''''''''') is null and o.name='''''''''' + @obj + '''''''''') )
or
( ('''''''''' + @obj + '''''''''' like ''''''''%.%'''''''' and o.id = object_id('''''''''' + @obj + '''''''''')) or ('''''''''' + @obj + '''''''''' not like ''''''''%.%'''''''' and o.name='''''''''' + @obj + '''''''''')
so the final query is
sp_executesql N'exec (''sp_MSforeachtable @command1=''''select top 10 * from ?'''', @whereand='''' and ( (object_id('''''''''' + @obj + '''''''''') is not null and o.id = object_id('''''''''' + @obj + '''''''''')) or (object_id('''''''''' + @obj + '''''''''') is null and o.name='''''''''' + @obj + '''''''''') )'''' '')', N'@obj varchar(200)', @obj=t1
or
sp_executesql N'exec (''sp_MSforeachtable @command1=''''select top 10 * from ?'''', @whereand='''' and ( ('''''''''' + @obj + '''''''''' like ''''''''%.%'''''''' and o.id = object_id('''''''''' + @obj + '''''''''')) or ('''''''''' + @obj + '''''''''' not like ''''''''%.%'''''''' and o.name='''''''''' + @obj + '''''''''') )'''' '')', N'@obj varchar(200)', @obj=t1
To place this in the keyboard shortcut just remove the final t1 and it will use any highlighted text.
home