Set NOCOUNT OFF at database level? - sql-server

Can I set NOCOUNT to be OFF by default for a particular database?
I need it for NHibernate (if it's ON, I get exceptions when saving). I can see the setting to disable it for an entire server (where it's set ON), but we're sharing the server with other databases. Is there a way I can set it to OFF just for my database?
Or is there an NHibernate setting that will do this for me? (I've worked around it for now with a custom DriverConnectionProvider that issues the command whenever it creates a connection. Works ok, but feels a bit awkward)
I'm using SQL Server 2000, btw.
Thanks
Matt

no, there is no database wide setting for SET NOCOUNT.
same question: http://www.eggheadcafe.com/software/aspnet/32120672/set-nocount.aspx

You could use the NH IInterceptor interface's OnPrepareStatement method to modify the NH-generated SQL statements to include a "set nocount off" statement at the top of every sql query issued by your application.
Some bloke called Dave reckons it's "evil" to do so, but it might be your answer. The link takes you to the page on his blog describing how to implement it.
My reservation about doing so is you would be creating a dependency on your application running against a database server that understands "set nocount off" - in other words, you'd be ignoring the configured dialect.

You can set nocount property of database ON/OFF from SSMS as well. Please find below
Right click on instance and select properties
Then select Connections
On right pane, you will find list of properties including 'no count'
Uncheck this property to make it OFF

Set NOCOUNT is Set at DB level. Execute below queries one after another separately. This gives better idea.
SET NOCOUNT ON
Update Users set FirstName='XXXX' where Id='YYYY';
***Command(s) completed successfully.
SET NOCOUNT OFF
Update Users set FirstName='XXXX' where Id='YYYY';
***(1 row(s) affected)

Related

Prevent User Usage of "dbo" in User Databases SQL Server

I am attempting to prevent usage of the default schema of "dbo" in my SQL Server databases. This is being applied to an existing long term project with ongoing maintenance where the developers also manage the SQL Server (are all sysadmin).
This is for the main reason to allow better dependency tracking between code and the SQL Server objects so that we can slowly migrate to a better naming convention. Eg. "dbo.Users", "dbo.Projects", "dbo.Categories" in a DB are nearly impossible to find in code once created because the "dbo." is often left out of SQL Syntax.
However a proper defined schema requires the usage in code. Eg. "Tracker.Users", "Tracker.Projects", etc ...
Even though we have standards set to not use "dbo" for objects it is still accidentally occurring due to management/business pressures for speed to develop.
Note: I'm creating this question simply to provide a solution someone else can find useful
EDIT: As pointed out, for non-sysadmin users the security option stated is a viable solution, however the DDL Trigger solution will also work on sysadmin users. The case for many small teams who have to manage there own boxes.
I feel like it would be 10,000 times simpler to just DENY ALTER on the dbo schema:
DENY ALTER ON SCHEMA::dbo TO [<role(s)/user(s)/group(s)>];
That's not too handy if everyone connects as sa but, well, fix that first.
The following Database DLL Trigger causes error feedback in both the SQL Manager GUI and via Manual TSQL code attempts to create an object for the types specified.
It includes a means to have a special user and provides clear feedback to the user attempting the object creation. It also works to raise the error with users who are sysadmin.
It does not affect existing objects unless the GUI/SQL tries to DROP and CREATE an existing "dbo" based object.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [CREATE_Prevent_dbo_Usage_2] ON DATABASE
FOR CREATE_TABLE, CREATE_VIEW, CREATE_PROCEDURE, CREATE_FUNCTION
AS
DECLARE #E XML = EVENTDATA();
DECLARE #CurrentDB nvarchar(200)=#E.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'NVARCHAR(2000)');
DECLARE #TriggerFeedbackName nvarchar(max)=#CurrentDB+N'.CREATE_Prevent_dbo_Usage'; -- used to feedback the trigger name on a failure so the user can disable it (or know where the issue is raised from)
DECLARE #temp nvarchar(2000)='';
DECLARE #SchemaName nvarchar(2000)=#E.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(2000)');
DECLARE #ObjectName nvarchar(2000)=#E.value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(2000)');
DECLARE #LoginName nvarchar(2000)=#E.value('(/EVENT_INSTANCE/LoginName)[1]', 'NVARCHAR(2000)');
DECLARE #CurrentObject nvarchar(200)=''; -- Schema.Table
IF #LoginName NOT IN ('specialUser') BEGIN -- users to exclude in evaluation.
IF CASE WHEN #SchemaName IN ('dbo') THEN 1 ELSE 0 END = 1 BEGIN -- is a DBO attempt to create.
SET #CurrentObject = #SchemaName+'.'+#ObjectName; -- grouped here for easy cut and paste/modify.
SET #temp='Cannot create "'+#CurrentObject+'".
This Database "'+#CurrentDB+'" has had creation of "dbo" objects restricted to improve code maintainability.
Use an existing schema or create a new one to group the purpose of the objects/code.
Disable this Trigger TEMPORARILY if you need to do some advanced manipulation of it.
(This message was produced by "'+#TriggerFeedbackName+'")';
throw 51000,#temp,1;
END
END
GO
ENABLE TRIGGER [CREATE_Prevent_dbo_Usage] ON DATABASE
GO

SQL Server Linked Server Queries w/ ANSI_WARNINGS OFF

I am trying to use the linked server feature in SQL Server (2014) to run a cross server query (calculation) from a stored procedure.
The stored procedure was originally designed to run a local query (calculation) using dynamic T-SQL (via sp_executeSQL). The expression is generated by our application and can be any arithmetic expression.
A simple example (A / B) query is implemented like:
(dynamic sql)
SELECT f1.Value / f2.Value
FROM dbo.DimDate d
INNER JOIN
dbo.vAverageData f1 ON f1.ParentID=x and f1.TimeStamp = d.TimeStamp
INNER JOIN
dbo.vAverageData f2 ON f2.ParentID=y f2.TimeStamp = d.TimeStamp
WHERE d.TimeStamp BETWEEN #StartDateTime AND #EndDateTime
Now, it gets interesting in that none of the calculation expressions check for or handle conditions such as divide by zero. Instead, the original developer decided to issue two statements before any of the dynamic T-SQL is executed:
SET ANSI_WARNINGS OFF
SET ARITHABORT OFF
This has worked well for years until one day, someone asked us if we could perform cross server queries. Naturally, the first option that popped into my head was to implement (1) a linked server connection between the two servers and (2) modify the dynamic T-SQL generation code (in our application) to prefix each object with the linked server name and database name.
The example above would be transformed into something like:
(dynamic sql)
SELECT f1.Value / f2.Value
FROM dbo.DimDate d
INNER JOIN
dbo.vAverageData f1 ON f1.ParentID=x and f1.TimeStamp = d.TimeStamp
INNER JOIN
*<LinkedServer>.<RemoteDatabase>*.dbo.vAverageData f2 ON f2.ParentID=y f2.TimeStamp = d.TimeStamp
WHERE d.TimeStamp BETWEEN #StartDateTime AND #EndDateTime
The first time, I tried to run one of these cross server queries, I received the infamous:
"Heterogeneous queries require the ANSI_NULLS and ANSI_WARNINGS
options to be set for the connection. This ensures consistent query
semantics. Enable these options and then reissue your query."
Obviously, the easiest thing would be to remove the SET calls mentioned above. However, in our case, they do serve a purpose and prevent the query/transaction from aborting in case of divide by zero, overflows, etc.
At this point (without a major rewrite), assume we have to have those SET calls in place...
Is there anything I can do to make this work without removing the SET calls? Are there any settings on the remote server/database that can be set? What about on the linked server object?
I haven't tried it, but there are database properties for ANSI Warnings Enabled, etc. Would this fix it if it's set consistently on both databases? Is that a bad/dangerous practice?
Both servers are the exact same version of SQL Server (2014) and both databases contain our code, i.e. we can change anything we want.
Whatever the type of linked server it is, there is no way around it per BOL found here.
A connection must have the ANSI_NULLS and ANSI_WARNINGS options set ON
before the connection can execute distributed queries. For more
information, see SET ANSI_DEFAULTS (Transact-SQL)
One way to go about it is to modify the query by adding statements like below. By making a local copy of the remote table, you can minimize the use of the options you don't want, and minimize the changes elsewhere.
SET ANSI_WARNINGS ON;
SELECT Columns_Used_For_Query INTO #Temporary_Table
FROM Remote_Table
WHERE Search_Condition;
SET ANSI_WARNINGS OFF;
--Do other stuff
This might not the best solution in terms of performance, especially when a proper index is crucial. But that's yours to test.
On the side note, if you still get the same error message, then that most likely means the stored procedure was created with ANSI_NULLS OFF, in which case you'd need to turn the option on then ALTER. Stored Procedure remembers ANSI_NULLS and QUOTED_IDENTIFIER setting at the time of creation and alteration.

View executed sql from dynamic sql

I've inherited a complicated application that uses a lot of dynamic SQL. Many of the stored procedures construct and execute significantly different SQL statements depending on input parameters. Is there a way that I can see the executed SQL, without using SQL profiler - ideally from within SQL Server Manager Studio?
I did something more-or-less along the same lines by creating a table called 'WhatHappened' with an AutoInc BigInt as a primary key, and a big varchar(8000) field to hold the dynamically created SQL commands, and then simply wrote the dynamically created SQL into the table, and looked at it with Enterprise Manager later. I don't know if it's a great solution, but it was quick and simple and worked.
You can use PRINT statement
for exp.
IF ##OPTIONS & 512 <> 0
PRINT N'This user has SET NOCOUNT turned ON.';
ELSE
PRINT N'This user has SET NOCOUNT turned OFF.';
GO
use like
PRINT #YourDynamicSQLStatement
ref. https://msdn.microsoft.com/en-IN/library/ms176047.aspx

Giving a database level trigger full access to a different database table [T-SQL]

I'm trying to have a trigger set up in an arbitrary database that will store information in a specific database on execution. However, I found that if the trigger is triggered by someone without explicit access to that database, the trigger execution will fail.
I was hoping to find away around this using:
CREATE TRIGGER [myTrigger]
on database
with execute as 'UserWithPermissions'
but that doesn't seem to work either... Does anyone know if this is possible? Any pointers would be greatly appreciated. Thanks.
In MSSQL Management go to DB-name => Security => Users and make sure the user has access. Also, Windows Network Authentication helps a lot when running procs from other machines
-- edit --
I think what you want is called 'EXECUTE AS'.
CREATE PROCEDURE dbo.usp_Demo
WITH EXECUTE AS 'SqlUser1'
AS
SELECT user_name(); -- Shows execution context is set to SqlUser1.
EXECUTE AS CALLER;
SELECT user_name(); -- Shows execution context is set to SqlUser2, the caller of the module.
REVERT;
SELECT user_name(); -- Shows execution context is set to SqlUser1.
GO

Disable messages in SQL2008 result set

further to these two questions, is there a way to disable the messages that may get sent along with the resultset in SQL2008?
(please note this is nothing to do with the ANSI_WARNINGS setting. Or NOCOUNT.)
Thanks for any help.
Edit: It's not a problem with compatibility settings or table owners. And it's nothing to do with NOCOUNT. Trust me.
No, there's not a way to disable all messages that get sent along with the result sets. Set nocount on/off doesn't have an effect on these types of messages.
You need the NOCOUNT in the body of the Sproc anyway (I appreciate that you've tested it with and without)
In circumstances like this I get the actual call to the Sproc (either from a Debug in my APP, or using SQL Profiler) and then plug that into SSMS or whatever IDE you use, wrapping it in a ROLLBACK transaction (so it can't accidentally make any changes). Note: Log on to SQL Server, with your IDE, using the same credentials as the App will use.
BEGIN TRANSACTION
EXEC StaffEnquirySurnameSearch #searchterm = 'FOOBAR'
ROLLBACK
and see what you get. Use TEXT mode for output, rather than GRID mode which might hide something
Just to show how I think NOCOUNT shoud be added to your SProc:
CREATE PROCEDURE StaffEnquirySurnameSearch
#searchterm varchar(255)
AS
SET NOCOUNT ON
SELECT AD.Name, AD.Company, AD.telephoneNumber, AD.manager, CVS.Position,
CVS.CompanyArea, CVS.Location, CVS.Title, AD.guid AS guid,
AD.firstname, AD.surname
FROM ADCVS AD
LEFT OUTER JOIN CVS ON
AD.Guid=CVS.Guid
WHERE AD.SurName LIKE #searchterm
ORDER BY AD.Surname, AD.Firstname
GO
I note that you are not prefixing the tables with a database owner (most commonly "dbo") which might mean that there are additional copies owned by whomever and that they turn out to be the default from the applications permissions perspective, although I don't think that will change the resultsets [between SQL versions], However, same thing applies to ownership of the Sproc, and there you might be calling some earlier version, created for a different owner.
Ditto where your Sproc name is defined in your ASP.NET code (which I can't seem to find in your linked question) should also have the owner defined, i.e.
EXEC dbo.StaffEnquirySurnameSearch #searchterm = 'FOOBAR'
Did you change the compatibility level when you upgraded from SQL 2000 to 2008? If it is some sort of backward compatibility warning message that might cure it.
Have you tried running the same CONTAINS query without the "OR"?
i.e.:
SELECT * FROM my_table
WHERE CONTAINS(my_column, 'a monkey') -- "a" is a noise word
instead of
SELECT * FROM my_table
WHERE CONTAINS(my_column, 'a OR monkey') -- "a" is a noise word
You can wrap it in a try catch... more info in books online
For example:
CREATE TABLE Test_ShortString(
ShortString varchar(10) NULL
)
begin Try
insert into
Test_ShortString (ShortString)
values ('123456789012345')
End Try
Begin catch
--Select Error_Number() as ErrorNumber
end catch

Resources