When I try to run below query(Sql Server) I get exception saying
ExecuteSqlScriptwithTransaction: failed with exception ALTER DATABASE
statement not allowed within multi-statement transaction.
DECLARE #sql nvarchar(500)
IF((SELECT (size * 8 /1024.0)*1000 FROM sys.database_files df WHERE df.name like 'Test') < 9000000)
BEGIN
SET #sql = 'ALTER DATABASE Test MODIFY FILE ( NAME = N''Test'', SIZE = 10000000KB );'
EXEC (#sql)
END
GO
Tried like below but same error
DECLARE #sql nvarchar(500)
IF((SELECT (size * 8 /1024.0)*1000 FROM sys.database_files df WHERE df.name like 'Test') < 9000000)
BEGIN
ALTER DATABASE Test MODIFY FILE ( NAME = N'Test', SIZE = 10000000KB )
END
GO
The ExecuteSqlScriptwithTransaction method named in the title suggests the code executes the script in a transaction. The ALTER DATABASE documentation specifically states:
The ALTER DATABASE statement must run in autocommit mode (the default
transaction management mode) and is not allowed in an explicit or
implicit transaction.
So the solution is to execute the script using a different method, one without an explict transaction.
I'm trying to learn SQL triggers to automatically handle events in my database but I'm having some problems with execution.
If I run the following code:
declare #userid numeric(18,0);
declare #username nvarchar(max);
set #userid = 400
execute GetUserNameFromID #userid,#username output
select #username
which calls the following stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE GetUserNameFromID
-- Add the parameters for the stored procedure here
#UserID numeric(18,0),
#UserName nvarchar(MAX) OUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #UserName = u.name from Users u where ID=#UserID
END
GO
I get a nice result 'sometestuser'
But when calling it from my trigger it fails to return a value from the stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Trigger [dbo].[CheckIfUserHasNoItemsLeft] on [dbo].[Items] for update
As
Begin
set nocount on
declare #inactive_user nvarchar(50);
declare #userid numeric(18,0);
declare #username nvarchar(MAX);
if ( select Count(*) from inserted ) > 1 RaIsError( 'CheckIfIserHasNoItemsLeft: No more than one row may be processed.', 25, 42 ) with log
if update(InactiveUser)
set #inactive_user = (select InactiveUser from inserted)
if #inactive_user is not null
set #userid = (select CID from inserted)
execute GetuserNameFromID #userid,#username output
if #username is not null
insert into tasks (Task) values ('The last item for ' + #username + ' has been marked inactive, check if this user should now be also marked inactive.')
End
InactiveUser is the name of the app user who has marked this item inactive, it is what I am using as a check to see if the item has been set inactive rather than create an additional boolean column just for this purpose.
I'm sure it's something simple but information on If...Then statements for SQL seems to be limited and a lot of answers suggest using Case but the query editor gives me errors about incorrect syntax no matter which way I try to do it that way.
As I'm learning I'm more than happy for someone to show me a completely new way of handling this if what I've done is wrong or bad design. I'm hoping to create a set of triggers that will add items to the tasks table for administrators to check when user accounts appear to be stale and other maintenance checks etc.
I am using SQL server 2005.
Thank you.
Edit: Changed 'value <> null' to 'value is not null'
Edit2: Added HABO's suggestion to throw an error if more than one row is detected.
How about we take a whole new approach to this. Processes like this are exactly why the inline table valued functions were created.
Let's start by converting your stored procedure to an inline table valued function.
CREATE FUNCTION GetUserNameFromID
(
#UserID numeric(18,0)
) RETURNS TABLE
AS RETURN
SELECT u.name
from Users u
where ID = #UserID
GO
That is a LOT simpler and cleaner than that stored procedure with an output variable.
Here is where it really starts to make a difference. Here is what you could do with that trigger using the newly created iTVF.
ALTER Trigger [dbo].[CheckIfUserHasNoItemsLeft] on [dbo].[Items] for update
As Begin
set nocount on
if update(InactiveUser)
insert into tasks (Task)
select 'The last item for ' + u.name + ' has been marked inactive, check if this user should now be also marked inactive.'
from inserted i
cross apply dbo.GetUserNameFromID(i.CID) u
end
This is super simple AND it is fully set based so if you update 1 or 1,000 rows it will work correctly.
I need to create a stored procedure (1 or more) that I can call from the master db (or other db) in a scheduled job to restore permissions (user and privs) to a database that has been restored from a source db. I do not want to create the users at the source db level because I want to restrict access to that server, so the sproc will need to be executed once the restore is completed to grant access. I currently have:
use (database);
if ( select objectproperty(object_id('dbo.spMaint_RestorePermissions_database'), 'IsProcedure') ) is null
exec ('create procedure dbo.spMaint_RestorePermissions_database as select 1');
go
alter procedure dbo.spMaint_RestorePermissions_database
as
set nocount on;
---- grant user permission to access database
create user [domain\userid] for login [domain\userid]
----- grant user access rights to database
exec sp_addrolemember 'db_datareader', 'domain\userid'
go
One of the restrictions of stored procs is that they cannot contain use database; statements. To accomplish what you're looking for, you could run sp_executesql from master and pass in a tsql string that executes sp_executesql in the context of a specific database. Something like this:
--This is the tsql statement that gets executed on a specific user db.
--You would use this to build your "create proc", "alter proc", "create user", etc statements.
DECLARE #InnerSql NVARCHAR(MAX) = 'SELECT DB_NAME()'
DECLARE #DB SYSNAME = 'DatabaseName'
DECLARE #Tsql NVARCHAR(MAX) = '[' + #DB + ']..sp_executesql N''' + #InnerSql + ''''
EXEC sp_executesql #Tsql;
I am working in a database where each user has a table in their schema called FindResults
eg: MyDatabase.User1.FindResults, MyDatabase.User2.FindResults, etc.
If I run a SELECT query on this table while logged in as one of the users it works just fine. However, I have a stored procedure (MyDatabase.dbo.ReadFindResults) that tries to run a SELECT query on this table, it fails because it tries to read MyDatabase.dbo.FindResults (does not exist). I have gotten around this by using dynamic SQL, but I was hoping there was a way to avoid this.
Is there a way to tell the stored procedure to use the current user's schema or perhaps something to change the scope to allow it to find the table I want?
EDIT: Here is the code for the stored procedure
-- Returns the IDs contained in the given find results set
CREATE PROCEDURE [dbo].[ReadFindResults]
#resultsid int -- The ID of the results set
AS
BEGIN
SELECT objectid FROM FindResults WHERE resultsid = #resultsid
END
GO
In your stored procedure you can say:
SELECT cols FROM MyDatabase..FindResults;
(Leaving out the schema name.)
However this seems very error-prone, and IMHO you should either have separate, schema-bound stored procedures as well, or a single table with a column to indicate whose row it is.
A hack could be to execute as the username:
DECLARE #sql NVARCHAR(255) = N'EXECUTE AS USER = N''' + SUSER_SNAME() + '''';
EXEC sp_executesql #sql;
SELECT whatever FROM Findresults;
But I haven't had the opportunity to test this (you're better equipped to test in your scenario anyway).
It still seems like a remarkably avoidable problem in the first place, but maybe that's just me.
You could use dynamic SQL like this:
DECLARE #sql NVARCHAR(1024) = "SELECT something FROM [userName].someTable"
DECLARE #userName NVARCHAR(255) = SUSER_SNAME()
SET #sql = REPLACE(#sql, "[userName]", #userName)
EXEC sp_executesql #sql
That too is a hakish way of doing that query. More reading about dynamic SQL here: http://www.sommarskog.se/dynamic_sql.html
Im at home right now and do not have access to a SQL Server. I will edit my post in the morning when Im at work if needed.
I have SQL Server 2008 with a linked Sybase server and I am trying to execute a stored procedure on the Sybase server using OPENQUERY. If I have a stored proc that doesn't take parameters it succeeds fine. If I have a stored proc with parameters it fails. I even tried a very basic stored proc that only took an int an that still failed. Below is the syntax I am using:
select * from
OPENQUERY([LINKSERVER],'exec database.user.my_stored_proc ''AT'',''XXXX%'',''1111'',1')
Msg 7357, Level 16, State 2, Line 3
Cannot process the object "exec database.user.my_stored_proc 'AT','XXXX%','1111',1". The OLE DB provider "ASEOLEDB" for linked server "LINKSERVER" indicates that either the object has no columns or the current user does not have permissions on that object.
As the proc will execute just fine without parameters, I don't think it is a permission issue.
This worked for me,
SELECT * FROM OPENQUERY(LOCALSERVER, 'SET FMTONLY OFF EXEC snr.dbo.GetAllSignals #controlRunId = 25, #experimentRunId = 26')
I was creating temporary tables, and that's why i got access denied
Here is more info http://www.sommarskog.se/share_data.html#OPENQUERY
I create a sp that doesn't return any value and it doesn't work.
Your SP in mysql have to return a value!
for example I do this in "mysql":
CREATE DEFINER=`root`#`localhost` PROCEDURE `MyPro`(IN `Name` VARCHAR(50), IN `Id` INT, OUT `Result` INT)
MODIFIES SQL DATA
BEGIN
DECLARE Result INT;
SET Result = 0;
INSERT into MyTable (Id,Name) VALUES(Id,Name);
SELECT Result;
END
That "Id" and "Name" is input parameter and "Result" is output parameter
and create linked server in SQL SERVER and call it like this:
select * from openquery
(
Test,'call mydb.MyPro(''Name'',''16'', #P0);'
)
It works for me :D
Linked Servers and OPENQUERY, Gems to MS SQL Server...that are wolves in sheep clothing. I've found the following solutions to work when dealing with parameters
If the SP is basically just SELECT statements, the move the same to a VIEW and just pass SQL statements via OPENQUERY.
Build the OPENQUERY as a string and then use execute_sql.
You could also see if it works to precede exec with SET FMTONLY ON:
OPENQUERY([LINKSERVER],'SET FMTONLY ON; exec database.user.my_stored_proc ''AT'',''XXXX%'',''1111'',1')
If you try this and it works, you should probably Google FMTONLY+OPENQUERY to get an idea of what it means.
Try this,
SELECT * FROM OPENQUERY(linked_server_name, 'SELECT postgres_procedure_name (parameters)');
I experienced a very similar issue, but my SP wasn't taking any parameters.
I tried experimenting with altering the query sent through the openquery to include 'SET NOCOUNT ON' and 'SET FMTONLY OFF' but this had no difference.
The only solution that worked for my stored procedure was dropping the existing version, and altering the code to specifically 'SET NOCOUNT ON'
After doing this I was able to successfully run my stored proc through my linked server connection.
First of all you have to add hard code text fields then you have to
replace it by your parameters value like FromDate,TillDate,EmpID,CompCode,0,DeptID,DesgId,LocationID,AtnType
DECLARE #startdate varchar(255) = '2019-12-17'
DECLARE #enddate varchar(255) = '2019-12-17'
Set #SQL = 'SELECT * FROM OPENQUERY(' + quotename(#LinkedServer) + ',' + '''' +
'SET FMTONLY OFF; exec [TAP].[dbo].[GetAttendanceList] ' + 'FromDate,TillDate,EmpID,CompCode,0,DeptID,DesgId,LocationID,AtnType,1'')'
You have to replace your parameters values shown below
set #SQL=REPLACE(#SQL,'FromDate',+''''+''''+#startdate+''''+'''')
set #SQL=REPLACE(#SQL,'TillDate',+''''+''''+#enddate+''''+'''')
set #SQL=REPLACE(#SQL,'CompCode',+''''+''''+#CompCode+''''+'''')
set #SQL=REPLACE(#SQL,'AtnType',+''''+''''+''''+'''')
if #EmpID is Null
begin
set #SQL=REPLACE(#SQL,'EmpID','null')
end
if #DeptID is Null
begin
set #SQL=REPLACE(#SQL,'DeptID','null')
end
if #DesgId is Null
begin
set #SQL=REPLACE(#SQL,'DesgId','null')
end
if #LocationID is Null
begin
set #SQL=REPLACE(#SQL,'LocationID','null')
end
print #SQL
exec ( #SQL)