Join queries from sp_MSForEachTable - sql-server

I'm using the following query to get the times when a table was last updadted by users:
EXEC sp_MSForEachTable 'SELECT ''?'' as TableName,
last_user_update,
user_updates,
index_id
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID(''SP3D_DB_RESEARCH_MDB'') AND
OBJECT_ID = OBJECT_ID(''?'')'
But in the results window I get like a table with one row for each result. Is there any way to join them as an unique query so I can sort the results?
I'm using SQL Server 2008 R2 and Microsoft SQL Server Management Studio.

You can not JOIN with the procedure but you will be able to get the result into one (temp)Table(variable), which you might use for joins in a second step using INSERT INTO with the EXEC. e.g.
Declare #Collect Table (Name Varchar(100),cnt integer)
Insert into #Collect
EXEC sp_MSForEachTable 'SELECT ''?'' as TableName,Count(*) from ?'
Select * from #Collect

Related

Simple way to select a column from all databases on a server instance in SQL Server 2014 Management Studio?

I am using SQL Server 2014 Management Studio. I tried this query:
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%SomeColumn%'
I get this after executing above query:
However, I know that the column I specified in the WHERE is a valid column in one of my tables in one of my databases.
I just thought there would be maybe a table where each row has information on a column (including which table it belongs to and which database); so I could query for column 'SomeColumn' and then see which table(s) and database(s) it is in.
You can use sp_MSforeachdb
DECLARE #sql VARCHAR(MAX)
SET #sql =
'USE ?;
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_CATALOG LIKE ''%%''
AND COLUMN_NAME LIKE ''%SomeColumn%'''
EXEC sys.sp_MSforeachdb #sql
This may work for you:
EXEC sp_MSforeachdb 'USE ? SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME LIKE ''%SomeColumn%'''
The sp_msforeachdb sp will run your statement on all databases on your server.

Azure T-SQL SELECT concatenation behavior

I have really strange problem (or misunderstanding) of the string concatenation on Azure Sql. I used to build T-SQL code for EXEC like this:
DECLARE #tsql nvarchar(max)
SELECT #tsql = CONCAT(#tsql, Prop1, Prop2) FROM Table
PRINT #tsql
This works fine in SQL from 2012 to 2016. But in Azure SQL I have really strange behavior: only LAST row is in #tsql
Here is live T-SQL to clean up some tables:
DECLARE #deleteTsql nvarchar(max)
SET #deleteTsql = ''
-- just show all table
SELECT O.[name] FROM [sys].[objects] O
LEFT JOIN sys.schemas SCH on O.schema_id = SCH.schema_id
WHERE (SCH.[name] = 'dbo' AND [type] = 'U') or (SCH.[name] = 'data' and O.[name] = 'Objects')
ORDER BY O.create_date desc
-- build T-SQL to cleanup
SELECT #deleteTsql = CONCAT(#deleteTsql, 'PRINT ''Deleting data from ', O.[name], '''', CHAR(10), CHAR(13), 'DELETE FROM [', SCH.[name], '].', '[', O.[name],']', CHAR(10), CHAR(13)) FROM [sys].[objects] O
LEFT JOIN [sys].[schemas] SCH on O.[schema_id] = SCH.[schema_id]
WHERE (SCH.[name] = 'dbo' AND [type] = 'U') or (SCH.[name] = 'data' and O.[name] = 'Objects')
ORDER BY O.create_date desc
PRINT #deleteTsql
This works fine in SQL 2016. For instance I have tables data.Objects, dbo.Table1 and dbo.Table2. Then following will be printed:
(3 rows affected)
PRINT 'Deleting data from Objects'
DELETE FROM [data].[Objects]
PRINT 'Deleting data from Table1'
DELETE FROM [dbo].[Table1]
PRINT 'Deleting data from Table2'
DELETE FROM [dbo].[Table2]
But if I do the same on Azure SQL (v12) database with same tables then I got this:
(3 rows affected)
PRINT 'Deleting data from Table2'
DELETE FROM [dbo].[Table2]
So only last record is in #deleteTsql.
Why?????
The result for aggregate concatenation (with the SELECT #x=#x+... syntax) is undefined. See KB 287515 and this answer. Using CONCAT does not change that. As Panagiotis Kanavos suggested, you should use STRING_AGG or GROUP_CONCAT.
And one more thing: in my databases, I get the results from a single row using your query, even in SQL Server 2016 or SQL Server 2017. So it's not an Azure thing, it's just depending on the execution plan (if it is using a nested loops join, you get all the rows; if it is using a merge join, you get a single row). That may be dependant on the number of rows in the system tables, the CPU count, the updated statistics, etc.

Run same query in SSMS on multiple databases in the same server

It is possible in SSMS to run the same query on some databases?
I was thinking something like an array with database names and cycling through it, maybe with SQLCMD mode.
some pseudocode:
:setvar arr ["db1", "db2", "db3"]
foreach $db in $arr
:setvar database $db
use $(database)
go
select * from table
Thanks
-- To Achive your Desire OutpUt You Have to Use Dynamic Query
-- you can Achieve this in TSQL
-- TO Know The Database ID Run Below Query
/*
SELECT * FROM Sys.databases WHERE database_id >4
*/
USE MASTER
GO
BEGIN TRAN
DECLARE #strt INT,#End INT,#Database NVARCHAR(255)
SELECT * INTO #T FROM Sys.databases WHERE database_id IN (4,5,6)-- Here you Have to Defined the Database ID
ORDER BY 1
SELECT ROW_NUMBER ()OVER (ORDER BY database_Id)Db_Id,* INTO #TT FROM #T
SET #strt=1
SELECT #End=Max(Db_ID)FROM #tt
WHILE #strt<=#END
BEGIN
DECLARE #string NVARCHAR(MAX)
SELECT #Database=NAME FROM #TT WHERE Db_ID=#strt
Set #string=' Select * from '+#Database+'..Table_Name'
SET #strt=#strt+1
PRINT #string
EXEC(#string)
END
ROLLBACK TRAN
Here's an example using two of my databases (Staging and Warehouse) to hit the sys.columns table in each. Just change out the IN filter with the names of whichever databases you want, and the ".sys.columns" with the schema/table name you need.
DECLARE #query NVARCHAR(MAX) = ''
;
SELECT #query += CONCAT('SELECT * FROM ',[name],'.sys.columns;')
FROM sys.databases
WHERE [name] IN ('Staging','Warehouse')
;
EXEC sp_executesql #query;
You can do this with a Local Server Group as well.
View --> Registered Servers
Right-click Local Server Group and create new
Add new server registrations to the group (any databases you want to query). Be sure to specify the database in the Connection Properties tab
Now you can right-click the Local Server Group folder and execute a new query, which will run on all the databases in that folder.

how to Find a patricular table Table on a SQL Server across all Databases?

I want to find a table in SQL Server, let's say "XYZ". i don't know in which DB it is located. The server has many DBs
SELECT * FROM sys.Tables
WHERE
name LIKE '%XYZ%'
You can make use of SP sp_Msforeachdb - this will be executed on every single database you have in the server.
EXEC sp_Msforeachdb "USE [?]; SELECT '[?]' dbname, *
FROM sys.tables
WHERE name like '%XYA%'"
This query will return a listing of all tables in all databases on a SQL instance:
DECLARE #command varchar(1000)
SELECT #command = 'USE ? SELECT name FROM sysobjects WHERE xtype = ''U'' AND Name LIKE ''%A'' ORDER BY name'
EXEC sp_MSforeachdb #command

How can I select this in Microsoft Query?

I have a stored procedure and a simple table.
I need to join this two object then allow user to see the result using Microsoft Query in Excel.
This is what I have. The Exec SP_Budget create global temp table and fill ##tmpBudget
exec SP_Budget;
Select g.name, g.address,g.Amount,b.BudgetAmt from gTable g
Left join ##tmpBudget b on b.NameID=g.NameID
Microsoft query can only do a simple
select * from tTable
how can I do this?
I have to have the stored procedure because it does UNpivot inside the SP_Budget
EDIT:
The more I think about this. I think I need to post the original SP_Budget
so here it is. Because maybe a better approach is to create a function rather than SP_Budget. Here is my SP_Budget. Is it possible to convert this SP to a function?
--this link show me how to build column list for the PIVOT/UNPIVOT http://stackoverflow.com/questions/9585094/sql-server-pivots-displaying-row-values-to-column-headers
--this link show me how to build column list of a specific table http://stackoverflow.com/questions/18775409/unpivot-with-dynamic-columns-plus-column-names
--here we build the dynamic query for the column list for the PIVOT/UNPIVOT
declare #sql AS NVARCHAR(MAX);
declare #cols nvarchar(max);
select #cols = coalesce(#cols+N',', N'') + quotename(c.name) from syscolumns c
inner join sysobjects o on c.id = o.id and o.xtype = 'u'
where o.name = 'AcctHist' and c.name not in ('PID', 'UID') and c.name like 'ptdbal%' and c.name <> 'PtdBal12' order by c.colid
--Construct the full T-SQL statement
--and execute dynamically
SET #sql = N'select
DB,Acct,Sub,cpnyid
,Fiscyr+
CASE WHEN len(Convert(varchar(2),CONVERT(int,right(Period,2))+1))=1
THEN ''0''+Convert(varchar(2),CONVERT(int,right(Period,2))+1)
ELSE Convert(varchar(2),CONVERT(int,right(Period,2))+1)
END "Period"
,Amounts
from (
SELECT A.DB,A.Sub,A.acct,A.FiscYr,A.CpnyID
, sum(A.PtdBal00) "PtdBal00"
,sum(A.PtdBal01) "PtdBal01"
,sum(A.PtdBal02) "PtdBal02"
,sum(A.PtdBal03) "PtdBal03"
,sum(A.PtdBal04) "PtdBal04"
,sum(A.PtdBal05) "PtdBal05"
,sum(A.PtdBal06) "PtdBal06"
,sum(A.PtdBal07) "PtdBal07"
,sum(A.PtdBal08) "PtdBal08"
,sum(A.PtdBal09) "PtdBal09"
,sum(A.PtdBal10) "PtdBal10"
,sum(A.PtdBal11) "PtdBal11"
FROM vz_Finance_Budget A
Group by A.DB,A.Sub,A.acct,A.FiscYr,A.CpnyID
)xx
UNPIVOT (Amounts for Period in ('+#cols+')) unpiv;';
EXEC sp_executesql #sql;
Edit2:
Thank you for all the suggestions. I decided that the limiting factor is microsoft query itself. Plus microsoft query should be replaced with something newer (I think). Instead of configuring my server to allow openrowset or OPENQuery. I will look into microsoft query replacement.
not sure if this is the right way to go. but I will update here. thanks.
Edit3: Trying this blog now: http://blogs.office.com/2010/06/07/running-a-sql-stored-procedure-from-excel-no-vba/ I will update when I complete it
As far as I know you can have explicit JOIN in Microsoft Query
Description of the usage of joins in Microsoft Query
SELECT ....
FROM tbl1, tbl2
WHERE tbl1.Id = tbl2.Id
Update
If you want to have the result set in Excel, You can use OPENROWSET to export the data from SQL Server to Excel.
INSERT INTO OPENROWSET('Microsoft.Jet.OLEDB.4.0',
'Excel 8.0;Database=C:\testing.xls;',
'SELECT name, address, Amount, BudgetAmt FROM [Sheet1$]')
SELECT g.name, g.address, g.Amount, b.BudgetAmt FROM gTable g
LEFT JOIN #tmpBudget b ON b.NameID = g.NameID
As you just mentioned earlier, you need to save your proc result into a temp table first
sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO
SELECT * INTO #tmpBudget
FROM OPENROWSET('SQLNCLI'
,'Server=(local)\SQL2008;Trusted_Connection=yes;'
,'EXEC SP_Budget')
I solved this using this blog below
http://blogs.office.com/2010/06/07/running-a-sql-stored-procedure-from-excel-no-vba/
basically in excel, when you click data tab - From other sources - instead of "from microsoft query". I select "from SQL server". With "from SQL Server". I have the option in the "Connection properties - definition" to select the command type to SQL (instead of table)
the blog explains this with screenshot... Thanks

Resources