How can I select this in Microsoft Query? - sql-server

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

Related

Join queries from sp_MSForEachTable

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

Change the roles of multiple security accounts

I have many security accounts on the sql database and i want to remove/add roles to them based on a simple string comparison.
Basically i want to list all
accounts
Filter out accounts that DON'T start
with "MyDomain\"
Remove role A.
Add role B.
What i found out by now is that i use sp_helprolemember to list all the accounts and sp_addrolemember and sp_droprolemember. My problem is that i dont know how to "get" the output from sp_helprolemember and work with it.
My first attemt at a soltuion based of feedback.
DROP TABLE [dbo].[XTemp]
create table XTemp(DbRole sysname,MemberName sysname,MemberSID varbinary(85) )
insert XTemp exec sp_helprolemember
select * from XTemp
I made a permanent table to make it simpler to test and debug.
SELECT [DbRole]
,[MemberName]
,[MemberSID]
FROM [ARTICLE].[dbo].[XTemp]
WHERE MemberName like Domain\%'
exec sp_addrolemember 'OldRole MemberName
Assuming that you're using SQL 2005 or later, and executing sp_helprolemember without parameters, this is the query that sp_helprolemember runs (extracted using sp_helptext):
select DbRole = g.name, MemberName = u.name, MemberSID = u.sid
from sys.database_principals u, sys.database_principals g, sys.database_role_members m
where g.principal_id = m.role_principal_id
and u.principal_id = m.member_principal_id
order by 1, 2
This should enable you to collect the information you need into a temp table.
If you'd rather stick to documented behaviour, you can store the output of the SP into a temp table:
create table #t
(DbRole sysname,
MemberName sysname,
MemberSID varbinary(85)
)
insert #t
exec sp_helprolemember
select * from #t
EDIT
There are two ways to use this data to amend your system. One is using a cursor:
DECLARE #memberName sysname
DECLARE curMember CURSOR fast_forward FOR
SELECT MemberName
FROM #t
WHERE MemberName LIKE 'Domain\%'
OPEN curMember
FETCH NEXT FROM curMember INTO #memberName
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC sp_addrolemember 'OldRole', #memberName
FETCH NEXT FROM curMember INTO #memberName
END
CLOSE curMember
DEALLOCATE curMember
The other is using dynamic SQL:
DECLARE #sql NVARCHAR(MAX),
SELECT #sql = 'EXEC sp_addrolemember ''OldRole'', ''' + MemberName + ''''
FROM #t
WHERE MemberName LIKE 'Domain\%'
EXEC sp_executesql #stmt = #sql
As you can see the dynamic SQL version is more compact but requires more effort to maintain.
Remember that after you execute either statement, the data you extracted from sp_helprolemember into a table is no longer up to date, and should probably be refreshed.
You can use Excel to generate SQL queries - I know it sounds lame but it is very simple and powerful. It is especially well-suited for tasks that have to be performed once or only from time to time.
Copy results from Management Studio to Excel.
Remove rows and columns than you don't need.
Use a formula in column B (e.g. ="EXEC sp_dropsrvrolemember '"&A1&"', 'sysadmin'") to generate queries for values stored in column A (the formula can of course reference more than one column with input data and generate really complicated queries).
Copy generated queries from Excel to Management Studio.

Query on multiple databases (SQL server)

I have multi databases with same structure its name like that "Client1234" the different in numbers beside "client" i have table called "Transactions" inside each database and i want to run query to get count all raws in "transactions" table in all databases.
also when i select database i need to check it has the client word and it has numbers beside the word.
Try to use sp_msforeachdb stored procedure like so:
create table #temp ([rows] int, [client] varchar(100))
exec sp_msforeachdb '
if ''?'' like ''Client%'' and exists(select * from ?.sys.tables t where t.name = ''Transactions'')
begin
insert into #temp select count(*), ''?'' from ?..Transactions
end
'
select * from #temp
drop table #temp
You can use dynamic SQL to create these queries:
select 'select count(*) from ' + name + '.dbo.transactions'
from master..sysdatabases
where name like 'Client%'
and isnumeric(substring(name,6,1))
This would return a result set with each row being a SQL query to count a specific database. It could be consumed by a programming language, used as a cursor, etc.. If you provide more detail I may be able to provide a better example.
When using Fosco's method, it is a good idea to put in brackets [] around the database name:
SELECT 'SELECT count(*) FROM ' + '[' + name + ']' + '.dbo.transactions'
FROM master..sysdatabases
WHERE name like 'Client%' and isnumeric(substring(name,6,1))
If the name and number of the databases you wish to query is not known beforehand then you can only do this by using a dynamic query. You'll need to generate a script like
SELECT COUNT(*) FROM Client1.dbo.Transactions
SELECT COUNT(*) FROM Client2.dbo.Transactions
...
Of course you need to have your appropriate permissions in place for each database.

OBJECT_ID of object in another database - how to find database ID or name/fully qualified object name?

Example:
USE AnotherDB
-- This works - same ID as from other DB
SELECT OBJECT_ID('AnotherDB.ASchema.ATable')
-- This works
SELECT OBJECT_NAME(OBJECT_ID('AnotherDB.ASchema.ATable'))
USE ThisDB
-- This works - same ID as from other DB
SELECT OBJECT_ID('AnotherDB.ASchema.ATable')
-- Gives NULL
SELECT OBJECT_NAME(OBJECT_ID('AnotherDB.ASchema.ATable'))
Obviously the metadata functions expect a current database. The BOL entries typically have language like this for functions like OBJECT_NAME etc.:
The Microsoft SQL Server 2005 Database
Engine assumes that object_id is in
the context of the current database. A
query that references an object_id in
another database returns NULL or
incorrect results.
The reasons I need to be able to do this:
I can't USE the other database from within an SP
I can't create a proxy UDF stub (or alter anything) in the other databases or in master (or any other database besides my own) to help me out.
So how can I get the database from OBJECT_ID('AnotherDB.ASchema.ATable') when I'm in ThisDB?
My goal is to take a possibly partially qualified name from a configuration table, resolving it in the current context to a fully qualified name, use PARSENAME to get the database name and then dynamic SQL to build a script to be able to get to the meta data tables directly with database.sys.* or USE db; sys.*
You should be able to do this:
SELECT
name
FROM
AnotherDB.sys.objects --changes context
WHERE
object_id = OBJECT_ID('AnotherDB.ASchema.ATable')
This is what you effectively do with OBJECT_ID('AnotherDB.ASchema.ATable')
This means that you could rely on dbname.sys.objects and avoid confusion with metadata functions.
Note: the new Catalog views are designed to be used and not change from version to version, as per the link. In the old days, it was consider bad practice to use system tables but the stigma still remains.
So, you can safely rely on sys.objects rather that the metadata functions.
Do I understand it correctly that you want the db id of AnotherDB?
SELECT *
FROM master..sysdatabases
WHERE name = 'AnotherDB'
Otherwise, you can USE other db's in dynamic SQL if it helps:
DECLARE #SQL NVARCHAR(MAX)
, #objId INT
SET #SQL = N'
USE AnotherDB
SELECT #id = OBJECT_ID(''customer'')
'
EXEC SP_EXECUTESQL #SQL
, N'#id INT OUTPUT'
, #id = #objId OUTPUT
SELECT #objId
OR Execute SP's in other dbs with:
EXEC AnotherDB.dbo.ProcedureName
#paramX = ...
, #paramY = ...
Take a look at the PARSENAME function in TSQL - will allow you to pull out any of the 4-part portions of a fully (or non-fully) qualified name. For the database in your example:
select parsename('AnotherDB.ASchema.ATable',3)
returns:
AnotherDB
select parsename('AnotherDB.ASchema.ATable',2)
returns:
ASchema
If non-fully qualified, you'll get null results if you ask for the portion of a name that isn't included in the string:
select parsename('ASchema.ATable',3)
returns:
NULL
I had the same issue but with OJBECT_SCHEMA_NAME as well. Following on from chadhoc's response using parsename works with OBJECT_NAME like:
DECLARE #OrigTableName NVARCHAR(MAX);
SELECT #OrigTableName = 'AnotherDB.ASchema.ATable'
SELECT OBJECT_NAME(OBJECT_ID(#OrigTableName), DB_ID(PARSENAME(#OrigTableName, 3)))
, OBJECT_SCHEMA_NAME(OBJECT_ID(#OrigTableName), DB_ID(PARSENAME(#OrigTableName, 3)))
I used the following solution:
DECLARE #SchemaName varchar(255) = 'SchemaName'
DECLARE #ObjectName varchar(255) = 'ObjectName'
SELECT o.*
FROM AnotherDB.sys.objects AS o
INNER JOIN AnotherDB.sys.schemas AS s ON o.schema_id = s.schema_id
WHERE s.name = #SchemaName
AND o.name = #ObjectName
IF NOT EXISTS (
SELECT si.name
FROM <DatabaseName>.sys.indexes si
INNER JOIN <DatabaseName>.sys.objects so
ON si.object_id = so.object_id
WHERE si.name = '<IndexName>'
AND so.name = '<TableName>'
)
BEGIN
CREATE INDEX [<IndexName>] ON [<DatabaseName>].[<Schema>].[<TableName>]
([column1])
INCLUDE ([<column2>],,,,
)
WITH (online = ON)
END

Find a table across multiple databases SQL SERVER 2005

I exported a table to a server but I can't find the table. Maybe I didn't put the right destination database. How can I find this table if my server has multiple databases, without opening each one of them?
I use MS Sql Server Management Studio 2008.
Rough and dirty, but it would do the job.
-- Instructions. Replace "table_name_here" with actual table name
sp_MSforeachdb 'USE ?
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N''[table_name_here]'') AND OBJECTPROPERTY(id, N''IsUserTable'') = 1)
BEGIN
PRINT ''Found in db ?''
END'
One way
SELECT DISTINCT DB_NAME(database_id)
FROM [sys].[dm_db_index_operational_stats](NULL,NULL,NULL,NULL)
WHERE OBJECT_NAME(object_id,database_id) = 'table_name'
Or if you are reasonably confident it would be in the dbo schema in whichever database
SELECT name
FROM sys.databases
WHERE CASE
WHEN state_desc = 'ONLINE'
THEN OBJECT_ID(QUOTENAME(name) + '.[dbo].[table_name]', 'U')
END IS NOT NULL
Based off Martin Smith's answer above but generalised into a view to give a sort of cross-DB version of sys.tables -
CREATE VIEW ListTablesAllDBs
AS
SELECT
DB_NAME(database_id) as DBName,
OBJECT_SCHEMA_NAME(object_id,database_id) as SchemaName,
OBJECT_NAME(object_id,database_id) as TableName
FROM
[sys].[dm_db_index_operational_stats](NULL,NULL,NULL,NULL)
Now, if only I can work out a way to do the same for columns.......
EDIT - Ignore this, finding it sometimes misses tables altogether.
Minor clarification just to avoid headaches for those with 'SuperUsers' who don't know how to name DBs:
EXEC sp_MSForEachDB '
USE [?]
IF OBJECT_ID(''mytable'') IS NOT NULL AND
OBJECTPROPERTY(OBJECT_ID(''mytable''), ''IsTable'') = 1
PRINT ''Found here: ?'''
select 'select * from '+name+'.sys.tables where name=
''[yourtable]'';' from sys.databases
Instead of [yourtable], type the name of the missing table, and run the result again.
EXEC sp_MSForEachDB '
USE ?
IF OBJECT_ID(''mytable'') IS NOT NULL AND
OBJECTPROPERTY(OBJECT_ID(''mytable''), ''IsTable'') = 1
PRINT ''?''
'

Resources