Say if using sp_helplognis, want to view result set with filter UserName=db_owner. Is there any way besides output the original result set to a temp table and then query on that temp table? Thanks.
Don't use sp_helplogins: use sys.server_principals
SELECT * FROM sys.server_principals WHERE name = 'bob'
If you want the 2nd resultset of sp_helplogins, then you'd have to use c# or something because loading a temp table will only trap the 1st resultset.
The equivalent of sys.server_principals is sys.database_principals too
FYI: db_owner is in every database already. What are you really trying to do...?
Edit, after comment, something like:
EXEC sp_MSForEachDb '
USE ?
IF DATABASE_PRINCIPAL_ID (''myloginname'') IS NOT NULL
EXEC sp_addrolemember ''db_datareader'', ''myloginname''
'
You can divert the resultset of a sproc into a new table, e.g.
create table #results (...)
insert into #results execute myproc
select * from #results where ...
It's a bit fiddly because you have to reverse-engineer the resultset data types pretty exactly to avoid casting errors.
Related
I'm having an issue with creating dynamic sql statement in SQL Anywhere.
CREATE PROCEDURE pplAnalysis
AS
BEGIN
DECLARE #Sql NVARCHAR(4000)
SELECT #Sql = "select * from cds.ppl"
EXECUTE(#Sql)
END
When I execute this procedure, I get an Column 'select * from cds.ppl' not found error.
Can you please tell me what am I doing wrong?
The issue had to do with syntax and the RESULT clause; after adding semicolons, RESULT clause, and used SET to initialize the Sql variable, here is what worked (tested in SQL Anywhere Network Server Version 12.0.1):
drop proc pplAnalysis;
CREATE PROCEDURE pplAnalysis()
RESULT (cnot CHAR(5), cnull CHAR(5), vnot VARCHAR(5), vnull VARCHAR(5), explanation VARCHAR(50))
BEGIN
DECLARE #Sql NVARCHAR(4000);
SET #Sql = 'select cnot, cnull, vnot, vnull, explanation from dbo.spaces';
EXECUTE ( #Sql );
END;
spaces is a table in the dbo schema and those columns are the same type specified in RESULT
Tested these two ways to execute the procedure and both returned result:
call pplAnalysis();
cnot cnull vnot vnull explanation
----- ----- ----- ----- --------------------------------------------------
Execution time: 0.027 seconds
Procedure completed
or
exec pplAnalysis;
cnot cnull vnot vnull explanation
----- ----- ----- ----- --------------------------------------------------
Execution time: 0.018 seconds
For more details:
Returning result sets from procedures
Create procedure statement
Try first saving the result of the query in a temporal table, and then do a SELECT from the temporal table:
SELECT #Sql = "select into #temp * from cds.ppl"
EXECUTE(#Sql)
SELECT * FROM #temp
Use single quotes.
SELECT #Sql = 'select * from cds.ppl'
After some research, I have edited my answer.
Regarding the EXECUTE ( string-expression ) statement, yes you have to use single quotes instead of double quotes for the string expression. This page mentions:
It lets you execute dynamically prepared statements, such as
statements that are constructed using the parameters passed in to a
procedure. Literal strings in the statement must be enclosed in single
quotes, and the statement must be on a single line.
Which will eliminate the column not found error but the procedure will return this other error:
Result set not permitted in '<batch statement>'
Same error returned when trying to execute this statement alone:
execute ('select * from sysusers')
With probable cause:
You attempted to execute a SELECT statement in a context where a
result set is not permitted.
See my most recent answer for the solution.
And regarding schemas, here's how to refer to objects:
It is always good practice to refer to database objects by a schema
name and the object name, separated by a period (.). For a complete example, to SELECT records from the Employee table in the HumanResources schema of the current database would look like:
SELECT * FROM HumanResources.Employee
To reference an object located in a remote database, the fully
qualified object name includes the server name and the database name.
For example, to SELECT records from the Employee table in the
HumanResources schema in the AdventureWorks database on MyServer would
look like:
SELECT * FROM MyServer.AdventureWorks.HumanResources.Employee
I tested that in SQL Anywhere 12 and it works the same. And even though I was not familiar with schemas, what I'm suggesting you below is actually using schemas, dbowner would be the schema name:
1) select * from dbname.dbowner.tablename
2) select * from dbowner.tablename
3) select * from dbname..tablename (assumes table exists in the dbo schema)
Bottom line.... In your select statement cds.ppl has to be a table named ppl created in the cds schema.
Or if cds is your database name and ppl your table name created in the dbo schema, you are missing a dot:
select * from cds..ppl
Is it possible to do something like this in sql server 2005?
WITH tmpTable AS (EXEC spWhatever)
Or any other way I can query the data returned from the sp? Thanks!!!
Temp table:
CREATE TABLE #foo (col1 int, col2 char(10), ...)
INSERT #foo
EXEC myproc
Or loopback (not sure if this still works). Edit: Could be OPENROWSET as per SQLMenace's answer
SELECT * FROM OPENQUERY (MyServername, 'USE MyDB EXEC myproc')
only with a loopback query if you don't first want to create the table, see here: Store The Output Of A Stored Procedure In A Table Without Creating A Table
example
SELECT * INTO #TempSpWho
FROM OPENROWSET ('SQLOLEDB','Server=(local);TRUSTED_CONNECTION=YES;',
'set fmtonly off exec master.dbo.sp_who')
SELECT * FROM #TempSpWho
as far as i know you can not. But you can try using User Defined Functions (UDF) instead of SP, if you do that you can you use it like a table.
I had the same question. I solved my situation by changing the SP to a VIEW. Now it acts just like a table. That's fine if you don't need to pass any parameters to the SP.
If you do need to pass parameters, make it a table-valued function.
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.
Is it possible to do this? I have some filters set in my source Stored Procedure and I really don't want to have to duplicate it in another just to get the rowcount.
The only way I know how to do this is to insert into a temp table from the stored procedure and then select the count. Unfortunately, there's no pretty way to perform a "select" on a stored procedure.
CREATE TABLE #stuff (id int, status char(6))
INSERT #stuff (id, status)
EXEC dbo.sp_get_stuff
SELECT count(*) FROM #stuff
DROP TABLE #stuff
Edit
The above method will allow you to select from a stored procedure, but as Greg pointed out, a rowcount can be simplified to:
EXEC dbo.sp_get_stuff
SELECT ##Rowcount
This also works:
create proc pTest1
as
select * from comp
go
create proc pTest2
as
exec pTest1
select ##rowcount
GO
If you are really trying to fine tune as much as possible, then you will have to change the source stored procedure. If you are looking at performance, then returning the rowset just to get the count is not something to even consider.
Is there a way when executing a stored procedure in Management Studio to get the data types of the result sets coming back? I'm looking for something like functionality of when you pass a table name to sp_help
You do get to look at the types though, if you call the stored procedure via ADO, ADO.NET, ODBC or the likes: The resulting recordsets have the type information you are looking for. Are you really restricted to Management Studio?
Your best bet would be to change the stored procedure to a function. But that only works if your environment allows it.
No easy way comes to mind without parsing syscomments to see what it's querying from where. If you can edit the SP to select XML, you can append XML_INFO to the query to get the schema back.
Actually, you can do it from within an SP:
EXEC ('if exists (select * from sys.tables where name = ''tmp_TableName'') drop table tmp_TableName')
EXEC ('select * into tmp_TableName from MyTable')
-- Grab the column types from INFORMATION_SCHEMA here
EXEC ('if exists (select * from sys.tables where name = ''tmp_TableName'') drop table tmp_TableName')
Although, I think there must be a better way.
It's not the most elegant solution, but you could use OPENROWSET to put the stored proc results into a table, then use sp_help to get a description of it.
eg
select * into tmp_Results
from openrowset( 'SQLOLEDB.1'
, 'Server=your_server_name;Trusted_Connection=yes;'
, 'exec your_stored_proc')
exec sp_help 'tmp_Results'
drop table tmp_Results
You could always use an actual table that is garrenteed to be unique. It's a kludge, but it's an option. This will not work inside a stored proc though.
if exists (select * from sys.tables where name = 'tmp_TableName')
drop table tmp_TableName
go
select * into tmp_TableName from MyTable
--do some stuff
go
if exists (select * from sys.tables where name = 'tmp_TableName')
drop table tmp_TableName
go