So, a little backstory on this one:
I have a lengthy query that I use frequently for my jobs that utilizes the sp_MSForEachDB stored proc. The query creates a temporary table, and then goes through and searches sys.tables, and if a database has a table called T_Study, it will run the query and pull these results into the temporary table.
What I am now trying to do is join in another table from another database, and this database is of a different type. These database are all distinguished by the existence T_BatchStores. All databases that have a T_BatchStores table will also have a table dbo.T_TSyntax, and this is the table on which I will need to join.
Essentially, I am trying to build a universal query that I can run on any server containing this software, and I have these few universal tables, but the names of the databases themselves will vary.
So what I want to do is, in my query that populates my temporary table, add the following:
JOIN '+#MEDDB+'.dbo.T_TSyntax and then my ON clause, etc. Keep in mind that this join occurs within my begin and end clauses and that sp_MSforEachDb will be run on this.
I want #MEDDB to be just a randomly selected name of ANY database on their SQL instance that contains a T_BatchStores table - it does not matter what the name is - I just don't want to modify the query every time I run it.
How can I use my DECLARE #MEDDB and SET/SELECT #MEDDB to work with these requirements?
Also, in some reading, I read that I should use SYSNAME as the data type, but I also know NVARCHAR would work - but I'd just like a tip on which would be ideal.
I have tried the following:
DECLARE #MEDDB SYSNAME
SET #MEDDB = (SELECT TOP 1 name FROM sys.databases WHERE EXISTS (SELECT name FROM sys.tables WHERE name = '''T_BATCHSTORES'''))
SELECT #MEDDB
But this returns 1 row with a NULL value. I'm very much a beginner to SQL, so any assistance would be greatly appreciated!
Note: I am only using Microsoft SQL Server 2008 and 2012 at the present time.
Thanks!
Okay, after heavily modifying the query so that the names aren't actually exactly the same as our actual table structure, here is a slimmed-down version of the query I'm using so that you'll see what I'm going for:
/* Add or change variables as needed and comment back in WHERE statements in Insert section as needed.
You do not need to delete any variables in this section, even if you do not need them.
Simply comment in or out relevant data in the WHERE clause in Section 4. */
/* Section 1: Declaring variables. */
DECLARE #STUID NVARCHAR (65)
DECLARE #IMUID NVARCHAR (200)
DECLARE #ACCN NVARCHAR (100)
DECLARE #MEDDB NVARCHAR (255)
/* Section 2: Assigning values to variables such as an Image file's UID. */
SET #STUID = 'enterSTUID'
SET #IMUID = 'enterIMUIDhere'
SET #ACCN = 'enterACCNhere'
SET #MEDDB = (SELECT TOP 1 name FROM sys.databases WHERE [name] LIKE '%med%'
AND [name] NOT LIKE '%audit%')
/* Section 3: Creating our temporary table to dump our results. */
IF OBJECT_ID('tempdb.dbo.#tempBatchResultsD6') IS NULL
BEGIN
CREATE TABLE #tempBatchResultsD6
(
Database_Name VARCHAR (200),
THING1 VARCHAR(100) NOT NULL,
THING2 VARCHAR(200) NOT NULL,
THING3 DATETIME NOT NULL,
TSyntaxUID VARCHAR (66) NOT NULL,
TSyntaxDesc VARCHAR (128) NOT NULL
)
END
TRUNCATE TABLE #tempBatchResultsD6
/* Section 4: Query that will be used to populate the contents of the temporary table created above.
Utilizing the stored procedure "sp_MSForEachDb," this will search every database on the SQL instance.
Here, we are limiting our results to only searching specific databases by only returning results from databases that have a "T_Studies" table. */
DECLARE #Command NVARCHAR(MAX)
SET #Command = N'USE [?];
IF EXISTS (SELECT * FROM sys.tables WHERE [name] = ''T_Studies'')
BEGIN
INSERT #tempBatchResultsD6
SELECT
DB_Name () as Database_Name,
THING1,
THING2,
THING3,
TS.TSyntaxUID,
TS.TSyntaxDesc
FROM T_Studies ST WITH (nolock)
JOIN T_Patients PT WITH (nolock) ON ST.ST_PT_FOLDERID = PT.PT_FOLDERID
JOIN T_Series SE WITH (nolock) ON ST.ST_FOLDERID = SE.SE_ST_FOLDERID
JOIN T_Images IM WITH (nolock) ON SE.SE_FOLDERID = IM.IM_SE_FOLDERID
JOIN '+#MEDDB+'.dbo.T_TSyntaxes TS WITH (nolock) on IM.IM_TSyntaxID = TS.TSyntaxUID
WHERE ST.STUID = '''+#STUID+'''
--WHERE IM.IM_UID = '''+#IMUID+'''
--WHERE ST.ST_ACCNNO = '''+#ACCN+'''
END'
EXEC sp_MSForEachDb #Command
/* Section 5: Querying our temporary table to get our results. */
SELECT
Database_Name,
THING1,
THING2,
THING3,
TSyntaxUID,
TSyntaxDesc
FROM #tempBatchResultsD6
ORDER BY Database_Name
So as you can see, this is a massive temp table that will pull from all databases that have a T_Studies table in them. It's huge in its actual form, but this is trimmed down significantly.
The problem comes in section 2, where I am using #MEDDB to choose a random database name if the name contains the word "Med" but not the word "audit." This is problematic because it assumes consistent naming across all sites - and while these names are suggested, they are never a guarantee.
To guarantee consistency, I am trying to populate the #MEDDB variable with the name of ANY database on their system that contains a T_BatchStores table instead of the WHERE [name] like portion.
Any advice with this new info would be greatly appreciated!
I am not sure whether I understand your question completely.
But if you wanna loop through all databases, you can use something like the following code. "SELECT XXX" would then be your query, by using "use ' + #DB_Name + ';" you switch to the desired database to execute the your query.
DECLARE #DB_Name varchar(100)
DECLARE #Command nvarchar(max)
DECLARE database_cursor CURSOR FOR
SELECT name
FROM MASTER.sys.sysdatabases
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
set #Command =
'
use ' + #DB_Name + ';
SELECT XXX
'
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
DECLARE #MEDDB NVARCHAR(500)
SET #MEDDB = 'SELECT TOP 1 name FROM sys.databases WHERE EXISTS (SELECT name FROM sys.tables WHERE name = ''T_BATCHSTORES'')'
EXEC (#MEDDB)
This is Dynamic SQL. Of course, I'm not getting any results, either, but I'm not in your database. Still, this allows you to be 'dynamic', and use a variable to modify things:
DECLARE #MEDDB NVARCHAR(500)
DECLARE #MEDDB2 NVARCHAR(100) = 'T_BATCHSTORES'
SET #MEDDB = 'SELECT TOP 1 name FROM sys.databases WHERE EXISTS (SELECT name FROM sys.tables WHERE name = ''' + #MEDDB2 + ''')'
EXEC (#MEDDB)
My recommendation is that you run simpler queries that show what you want, and then you build them into the dynamic method.
For instance, I'm in AdventureWorks right now, so I can do:
SELECT * FROM sys.databases
This gives me a list of all the databases that are available in here.
So maybe I expand that to
SELECT * FROM sys.databases WHERE name = 'AdventureWorks'
This gives me just one line of results. So if that's what I want, I build it into the dynamic portion:
DECLARE #MEDDB NVARCHAR(500)
DECLARE #MEDDB2 NVARCHAR(100) = 'AdventureWorks'
SET #MEDDB = 'SELECT * FROM sys.databases WHERE name =''' + #MEDDB2 + ''''
EXEC (#MEDDB)
It just all depends what you're looking for. I always find the data I want first, and then figure out how to make my query look for it.
Related
I have created a stored procedure which takes as inputs a schema name and a table name and outputs an INT containing the largest value in the id column of the table. I have also created a view containing all the schema names, table names, and primary key column names in my database. I would like to add a column to this view containing the result of my stored procedure, using the schema name and table name values as inputs to the row's stored procedure. I have tried a few different things, but I can't find a way to do it.
Stored procedure:
CREATE PROCEDURE [dbo].[sp_ttw_max_id]
(
#schema VARCHAR(50),
#table VARCHAR(50),
#max_id INT OUTPUT
) AS
BEGIN
-- Another custom stored procedure to help sanitize the input
EXEC sp_ttw_santize #schema, #table, #schema OUTPUT, #table OUTPUT;
DECLARE #param NVARCHAR(255);
SET #param = '#max_id_param INT OUTPUT';
DECLARE #sql NVARCHAR(255);
SET #sql = 'SELECT TOP 1 #max_id_param = [id]
FROM ' + #table + '
ORDER BY id DESC;'
EXEC sp_executesql #sql, #param, #max_id_param = #max_id OUTPUT;
END;
View:
CREATE VIEW [dbo].[pk_columns]
AS
SELECT
col_cnst.TABLE_SCHEMA, col_cnst.TABLE_NAME, COLUMN_NAME
FROM
INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE col_cnst
JOIN
INFORMATION_SCHEMA.TABLE_CONSTRAINTS tbl_cnst ON col_cnst.CONSTRAINT_NAME = tbl_cnst.CONSTRAINT_NAME
WHERE
CONSTRAINT_TYPE = 'PRIMARY KEY';
My attempts
First, I tried adding #max_id to the column list in the view's SELECT statement:
DECLARE #max_id INT;
SELECT col_cnst.TABLE_SCHEMA, col_cnst.TABLE_NAME, COLUMN_NAME, #max_id...
This put a column of nulls on my view. Unfortunately, I can't tell how to actually assign the value. Replacing the parameter name with my EXEC statement didn't help.
Second, I tried to add change the view into a temporary table and put a DEFAULT constraint on my new column, but I had the same problem.
Third, I tried modifying the stored procedure to not return the max ID as an OUTPUT parameter. I replaced all the #max_ids in my earlier attempts with EXECs, but still no good.
Is this even possible?
You cannot include the output of a stored procedure in a view.
However, in this case, it seems like you can get the same data a different way. Rather than using dynamic SQL to query a table directly, you can access the metadata in sys.identity_columns.
DECLARE #schema nvarchar(128),
#table nvarchar(128)
SELECT SchemaName = s.name,
TableName = o.name,
LastValue = ic.last_value,
IncrementValue = ic.increment_value
FROM sys.identity_columns AS ic
JOIN sys.objects AS o ON o.object_id = ic.object_id
JOIN sys.schemas AS s ON s.schema_id = o.schema_id
WHERE s.name = #schema
AND o.name = #table;
By querying the metadata directly, you can now incorporate the query into your view by adding it with the appropriate joins or subquery. It will additionally be significantly faster than querying the table directly. In your case, if you just want a list of all identity columns (assuming every ID is a Primary Key), the above query (with the variables removed) seems to get you pretty much the output you're trying to get.
Also note that schema and table names can contain Unicode characters and be up to 128 characters long. You should ensure that your input parameters support Unicode (Nvarchar), and are sufficiently long (128).
There's a minor difference with regard to sys.identity_columns.last_value and MAX(schema.table.id), which is that an ID value could be consumed (via an insert) that is subsequently rolled back or deleted. This will result in a gap in the ID values in the table, and that gap is reflected when sys.identity_columns.last_value and MAX(schema.table.id) are out of sync. In any forward-looking scenario, the last_value will be most correct, though if you are specifically looking back to identify the "highest committed value that has currently exists in the table" then you would need to calculate the MAX() to be 100% sure the returned value exists.
I am working in an environment where many users have the same (or almost identical) test database set up on a common MSSQL server. We are talking about well over 100 databases for testing purposes. And at the very least, 95+% of them will contain the table I am trying to target.
These test databases are only filled with junk data - I will not be impacting anyone by doing any kind of a search. I am looking at one table, specifically, and I need to determine if any test database has that table actually containing any data at all. It doesn’t matter what the data is, I just need to find a table actually containing any data, so I can determine why that data exists in the first place. (This DB is quite old - almost two decades, so sometimes no-one has a clear answer why something in it exists).
I have been trying to build an SQL statement that iterates through all the databases, and checks that particular table specifically to see if it has any content, to bring back a list of databases that have that table containing data.
So to be specific: I need to find all databases where a specific table has any content at all (COUNT(*) > 0). Right now totally stuck with not much of any clues as to how to proceed.
In both methods replace <tablename> with the table name
Using sp_foreachdb
You can use sp_foreachDb
CREATE TABLE ##TBLTEMP(dbname varchar(100), rowscount int)
DECLARE #command varchar(4000)
SELECT #command =
'if exists(select 1 from [?].INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME =''<TABLE NAME>'') insert into ##TBLTEMP(dbname,rowscount) select ''[?]'',count(*) from [?].dbo.<tablename>'
EXEC sp_MSforeachdb #command
SELECT * FROM ##TBLTEMP WHERE rowscount > 0
DROP TABLE ##TBLTEMP
Using CURSOR
CREATE TABLE ##TBLTEMP(dbname varchar(100), rowscount int)
DECLARE #dbname Varchar(100), #strQuery varchar(4000)
DECLARE csr CURSOR FOR SELECT [name] FROM sys.databases
FETCH NEXT FROM csr INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #strQuery = 'if exists(select 1 from [' + #dbname +'].INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME =''<TABLE NAME>'') INSERT INTO ##TBLTEMP(dbname,rowscount) SELECT ''' + #dbname + '' ', COUNT(*) FROM [' + #dbname + '].[dbo].<table name>'
EXEC(#strQuery)
FETCH NEXT FROM csr INTO #dbname
END
CLOSE csr
DEALLOCATE csr
SELECT * FROM ##TBLTEMP where rowscount > 0
References
Sp MSforeachDB
Run same command on all SQL Server databases without cursors
DECLARE CURSOR (Transact-SQL)
What's a good way to dynamically create tables, then join together all the tables that I have created?
Background
I'm trying to write a stored procedure that collects data from various parts of the database and presents it for use. For example if I wanted to send invoices to both Alice and Bob, this stored procedure would find all the information for the invoice. The trick is that Alice and Bob don't always need all the information I have. If Bob is tax exempt but trades in simoleons, I'll need to include information about currency exchange rates but leave out tax info. I want to give the stored procedure an order number and get back results formatted to the customer.
My solution so far is to create a table holding customer requirements. Then my stored procedure checks the table: if currency data is required I create and populate #Currency, or #Taxes holds tax data and so on. I check the requirement, then create the table as needed. At the end I need to Join the data into one record set.
My problem is that I have a error saying
Incorrect syntax near the keyword 'table'
AND an error saying
Must declare the table variable #Summary
on line 1 where i define #Summary These errors only show up when I use dynamic SQL to join the tables. When I comment out the dynamic SQL and copy-paste the statements into the one it should create, I have the result I want.
Code
I tried to use the following dynamic SQL in Microsoft SQL Server Management Studio
create procedure <procedure> (#OrderNumber varchar(20)) AS
DECLARE #CustomerName varchar(35) -- retrieved based on #OrderNumber
DECLARE #SQLQuery nvarchar(500)
DECLARE #ParamDef nvarchar(500)
DECLARE #SummaryTable table
(
ID varchar(20) --=#OrderNumber
, <Stuff>
)
SET #SQLQuery = 'Select * From #SummaryTable'
SET #ParamDef = '#SummaryTable table'
IF EXISTS(Select <TableName> from CustRequirements where <TableName> = 1 AND Customer = #CustomerName)
BEGIN
--Create table
DECLARE #<TableName> table
(
ID varchar(20)
, <Stuff>
)
--Populate
Insert into <TableName> Select <RelevantData> From <DataSource> where <Condition based on #OrderNumber or #CustomerName>
--Pepare Dynamic SQL
Set #SQLQuery = #SQLQuery + ' FULL OUTER JOIN #<TableName> ON <TableName>.ID = SummaryTable.ID'
SET #ParamDef = ', #<TableName> table'
END
<repeat for other tables>
EXECUTE sp_executesql #SQLQuery, #ParamDef, #Summary, #LineItems, #Taxes, #Currency
Question
Is there something wrong with my code? Is there a better way to do this? The other option I though of was to have IF Exists trees with the entire JOIN statement at the bottom of each branch (Since I can't seem to interrupt the JOIN clause with IF's). The problem with that is that I'll need 2^n JOIN statements to join n possible tables. n in this case might be as high has 20 or 30.
I think I see a problem in the code (maybe 3 problems -- see "questionable" 1 & 2 below) --
1) [Changed on 10/21, after OP's comments] The big problem: table parameters passed in the final "EXECUTE sp_executesql #SQLQuery..." are sometimes not declared.
1a) #Summary is actually never declared... you declared and set #SummaryTable, then use #Summary.
Just change that to #SummaryTable (I did that in (4) below), and I think that will prevent your second error message ("Must declare the table variable #Summary").
1b) All the other tables are sometimes declared: each of their DECLARE statements are within an "IF EXISTS". I suggest either (I) make the declares unconditional (outide IF EXISTS), but still conditionally INSERT... or (II) make the format of the EXECUTE command vary with what's available.
(I doubt the unused table variables need anything in them....)
In point 4 below (added 10/21), I give an example that I have NOT TESTED with my own databases (that test would take a lot more time)... so please let me know how it goes...
2) [questionable 1] Simple case of mixed case ;) Note that the line...
Set #SQLQuery = #SqlQuery + ' FULL OUTER JOIN #<TableName> ON <TableName>.ID = SummaryTable.ID'
... first has an uppercase "SQL", then mixed-case "Sql".
Why I said this is "questionable" -- if your server's COLLATION is case-insensitive, what you typed above would be fine.
3) [questionable 2] You have both '#TableName' and '#Table Name' (with a space). I realize that may just be how you typed it, in posting your question.
Point (4), added in update to answer -- possible code
create procedure <procedure> (#OrderNumber varchar(20)) AS
DECLARE #CustomerName varchar(35) -- retrieved based on #OrderNumber
DECLARE #SQLQuery nvarchar(500)
DECLARE #ParamDef nvarchar(500)
DECLARE #SummaryTable table
(
ID varchar(20) --=#OrderNumber
, <Stuff>
)
SET #SQLQuery = 'Select * From #SummaryTable'
SET #ParamDef = '#SummaryTable table'
--Create table variables, though they may not be populated
DECLARE #LineItems
(
ID varchar(20)
, <Stuff>
)
DECLARE #Taxes
(
ID varchar(20)
, <Stuff>
)
DECLARE #Currencytable
(
ID varchar(20)
, <Stuff>
)
IF EXISTS(Select <TableName> from CustRequirements where <TableName> = 1 AND Customer = #CustomerName)
BEGIN
--Populate
Insert into <TableName> Select <RelevantData> From <DataSource> where <Condition based on #OrderNumber or #CustomerName>
--Prepare Dynamic SQL
Set #SQLQuery = #SQLQuery + ' FULL OUTER JOIN #<TableName> ON <TableName>.ID = SummaryTable.ID'
SET #ParamDef = ', #<TableName> table'
END
<repeat for other tables>
EXECUTE sp_executesql #SQLQuery, #ParamDef, #SummaryTable, #LineItems, #Taxes, #Currency
The solution I've decided tp use is to create a table then use ALTER TABLE to add columns as needed.
CREATE Table #Output
(
InvoiceNumber varchar(20)
, <stuff>
)
IF EXISTS(Select <ThisSegment> FROM CustRequirements WHERE <ThisSegment> = 1 AND Customer = #CustomerName)
BEGIN
ALTER TABLE #Output ADD <ThisSegment> <dataType>
UPDATE #Output
SET <ThisSegment> = <data> from <DataSource>
WHERE <InvoiceNumber = DataSource.invoice> AND <Other conditions>
END
<Repeat as needed>
There are bunch of databases to the SQL server I am connected.
How should I query the sysobjects in order to spot in what database a stored procedure with name 'myStoredProcedure' is located ?
The query should return the database name.
Thanks
I know you are not asking for this, but I'd really download RedGate's Sql Search add-in for SSMS and use that. It allows you to find any object (proc, table, view, column, etc) on any database easily.
And it's free!
I'd give this a try:
CREATE TABLE ##DatabaseList
(
DatabaseName varchar(50)
)
EXECUTE SP_MSForEachDB 'USE [?]; INSERT INTO ##DatabaseList SELECT DB_NAME() FROM [sys].[objects] WHERE name = "MyStoredProcedure" AND type_desc = "SQL_STORED_PROCEDURE"'
SELECT * FROM ##DatabaseList
DROP TABLE ##DatabaseList
That's using the undocumented/ unsupported system stored procedure SP_MSForEachDb and writing any hits to a global temp table, then outputting the contents to the Results window before dropping the table. If you just need to know which database (or databases - there may of course be more than one) has an appropriately named SP, this should do it. If you want to use the output elsewhere as a parameter, it may take a little more work.
By the way, I'm only learning this stuff myself over the last few months so if anyone can critique the above and suggest a better way to go at it I'm happy to receive feedback. Equally, I can answer any further questions posted here to the best of my ability.
Cheers
So out of curiosity I decided to try write this myself, especially since ADG mentioned his solution was using an unsupported, undocumented procedure. This could also be expanded to take a 2nd parameter so where it checks the type = P (stored Proc) you could probably change it to look for other things like views / tables etc.
My solution is a bit long but here goes:
CREATE PROCEDURE spFindProceduresInDatabases
(
#ProcedureName NVARCHAR(99)
)
AS
BEGIN
-- Get all the database names and put them into a table
DECLARE #Db TABLE (DatabaseName Varchar(99))
INSERT INTO #Db SELECT name FROM Sys.databases
-- Declare a table to hold our results
DECLARE #results TABLE (DatabaseName VARCHAR(99))
-- Make a Loop
-- Declare a variable to be incremented
DECLARE #count INT
SET #count = 0
-- Declare the end condition
DECLARE #endCount INT
SELECT #endCount = COUNT(*) FROM #Db
-- Loop through the databases
WHILE (#count < #endCount )
BEGIN
-- Get the database we are going to look into
DECLARE #dbWeAreChecking VARCHAR(99)
SELECT TOP 1 #dbWeAreChecking = DatabaseName FROM #Db
DELETE FROM #Db WHERE DatabaseName = #dbWeAreChecking
-- Create and execute our query
DECLARE #Query NVARCHAR(3000)
SET #Query = N'SELECT #outParam = COUNT(*) FROM '+#dbWeAreChecking+'.sys.sysobjects WHERE type = ''P'' and name = #ProcedureName'
Declare #outParam INT
print (#Query)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #IntVariable INT
SET #ParmDefinition = N'#ProcedureName VARCHAR(99),#outParam INT OUTPUT'
SET #IntVariable = 35
EXECUTE sp_executesql
#Query ,
#ParmDefinition,
#ProcedureName,
#outParam = #outParam OUTPUT
-- If we have a result insert it into the results table
If (#outParam > 0)
BEGIN
INSERT INTO #results(DatabaseName) VALUES(#dbWeAreChecking)
END
-- Increment the counter
SET #count = (#count + 1)
END
-- SELECT ALL OF THE THINGS!!!
SELECT * FROM #results
END
I've got a software suite that is based off of multiple libraries where:
1 library = 1 SQL Database.
Different users can have different access to different libraries.
In addition, the databases are named in a specific manner to help identify which are "mine" and which aren't.
I'd like to create a stored procedure that takes a variable called #UserName and returns the databases that have a name starting with MYDB, where #UserName is found in a table USERS.
I'm figuring that I'll start with EXEC sp_databases, but I'm unsure how to continue.
What I need to know is:
How do I iterate the results of sp_databases to pull out just the databases that have a name matching my pattern?
How do I then check for #UserName in the [USER NAME] column of the USERS table of each database returned from #1?
I'm guessing it has something to do with temp tables and cursors, but I'm not really sure where to start.
Any help?
Thanks!
Here is some proof of concept code to show you an approach. sys.databases contains a more accessible list of databases. You'll pretty much have to use dynamic sql at some point though.
CREATE PROCEDURE MyDBs #userName VARCHAR(255)
AS
BEGIN
DECLARE #max INT
DECLARE #i INT
DECLARE #sql VARCHAR(500)
CREATE TABLE #SQL
(
rid int identity primary key clustered,
query varchar(500)
)
INSERT INTO #SQL(query)
SELECT 'SELECT * FROM ['+ name '+].USERS WHERE username = #UserName'
FROM master.sys.databases
WHERE NAME LIKE '%yourpattern%'
SELECT #max = ##rowcount, #i = 1
WHILE #i <= #max
BEGIN
SELECT #sql = query FROM #sql WHERE rid = #i
EXEC #sql
SET #i = #i + 1
END
DROP TABLE #SQL
For 1, just look at the sp_databases code, copy it and modify it to your needs. For Example (see last 2 conditions of where clause. This is the actual code of the sp_databases stored proc. You can look at it on the master db):
declare #UserName varchar(50)='someuser'
select
DATABASE_NAME = db_name(s_mf.database_id),
DATABASE_SIZE = convert(int,
case -- more than 2TB(maxint) worth of pages (by 8K each) can not fit an int...
when convert(bigint, sum(s_mf.size)) >= 268435456
then null
else sum(s_mf.size)*8 -- Convert from 8192 byte pages to Kb
end),
REMARKS = convert(varchar(254),null)
from
sys.master_files s_mf
where
s_mf.state = 0 and -- ONLINE
has_dbaccess(db_name(s_mf.database_id)) = 1 and
--db_name(s_mf.database_id) like '%'+#UserName+'%' and exists -- you may or may not want to leave this condition here. You'll figure out what condition to use
(select 1 from databasename.dbo.Users where [UserName]=#UserName)
group by s_mf.database_id
order by 1