DIfferent Behavior in SQL 2008 R2 and SQL 2012 - sql-server

When I'm trying to update some data like
if Exists(select * from sys.columns where Name = N'Enabled'
and Object_ID = Object_ID(N'SLBPool'))
begin
update SLBPool set SLBPool.Enabled=1
End
GO
it shows error "Invalid column name 'Enabled'" in SQL 2012,however ,not happened with 2008 R2
how come ?

The only way this should work on any version of SQL Server (certainly as far back as 2000, IIRC) is if you prevent the statement from being compiled until after you've evaluated the if condition - which would indicate dynamic SQL:
if Exists(select * from sys.columns where Name = N'Enabled'
and Object_ID = Object_ID(N'SLBPool'))
begin
exec sp_executesql 'update SLBPool set SLBPool.Enabled=1'
End
GO

Possibly this is because of collation prefs of server instance, check if this works, or produces some other error:
IF EXISTS(SELECT * FROM sys.columns WHERE name = N'Enabled'
AND object_id = OBJECT_ID(N'SLBPool'))
BEGIN
UPDATE SLBPool SET SLBPool.Enabled = 1
END
GO

Related

Convert SQL Server trigger to Oracle and master.dbo.sysprocesses - not duplicate

I tried searching but could not find exactly what I'm looking for. I'm new to SQl Server and involved into SQL Server to Oracle conversion, and it is manual conversion. All I have is SQL Server files.
I see two types of SQL Server triggers - FOR UPDATE and FOR INSERT. They look to me as before update and before insert triggers in Oracle. I'd like to confirm this please and if you can provide examples that would be great.
Also, what is the equivalent to master.dbo.sysprocesses in Oracle please? Is this v$session? I can get user from dual in Oracle. Is this what nt_username is in below code?
Here is typical code examples I need to convert to Oracle - is this before insert?
CREATE TRIGGER trigger_name ON dbo.table_name
FOR Insert AS
declare #InsertUser varchar(32)
BEGIN
SELECT #InsertUser = nt_username from master.dbo.sysprocesses where spid = ##spid
Update table_name
SET dCreateDate = GETDATE(), cCreateUser = #InsertUser
FROM table1 a ,table2 i WHERE a.tab_id = i.tab_id
END
GO
Update Trigger - before update?
CREATE TRIGGER trigger_name ON dbo.table_name
FOR UPDATE AS
declare #UpdateUser varchar(32)
if not update(CreateUser) and not update(CreateDate)
BEGIN
SELECT #UpdateUser = nt_username from master.dbo.sysprocesses where spid = ##spid
Update table_name
SET UpdateDate = GETDATE(), UpdateUser = #UpdateUser
FROM table1 a ,table2 i WHERE a.tab_id = i.tab_id
END
GO
Should I combine these two into if inserting... elsif updating in Oracle?
Thank you very much to all.

Error:create function must be the only statement in the batch

I am trying to firstly check if the function exists then create it, if it doesn't exist.
I'm getting this error from the function:
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[GetRelativeExpiry]') AND type in (N'U'))
BEGIN
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
CREATE FUNCTION [dbo].[GetRelativeExpiry]
(
#Date DATE,
#N INT
)
RETURNS DATE
AS
BEGIN
-- Declare the return variable here
DECLARE #Expiry as DATE;
IF #N > 0
BEGIN
SELECT #Expiry = MAX(E2.Expiry)
FROM (SELECT TOP(#N) Expiry
FROM ExpiryDates E1
WHERE E1.Expiry >= #date
ORDER BY E1.Expiry) AS E2
END
ELSE
BEGIN
SELECT #Expiry = MIN(E2.Expiry)
FROM (SELECT TOP(-#N) Expiry
FROM ExpiryDates E1
WHERE E1.Expiry <= #date
ORDER BY E1.Expiry DESC) AS E2
END
RETURN #Expiry
END
END
I am not sure why I am getting this error, could someone please help?
I am using Microsoft SQL Server Management Studio 2014
CREATE statements, whether they are for TYPE, PROCEDURE, FUNCTION, ... should always be the first statement in a batch.
To work around this in batches like yours execute the CREATE statement using sp_executesql like this:
EXEC sp_executesql N'
-- your CREATE statement here
';
If you are trying to do this in regular window within MS SQL Server Management Studio 2014 (or any prior version), where you would normally write all other queries, then your definition of function must be very first statement that is not commented.
See image below. If statement USE PTCRMstaging_test; was not commented, SQL Server Management Studio would give that same error.

SQL Server 2005: SELECT default value of columns

I'm writing a script that analyses database tables and I'm having problems with fetching the default value of columns from SQL Server 2005.
The following works fine on SQL Server 2008, but when I run the same thing on SQL Server 2005, the result is an empty string, and I can't figure out why.
DECLARE #sDatabase VARCHAR(100);
DECLARE #sTable VARCHAR(100);
DECLARE #sColumn VARCHAR(100);
SET #sDatabase = 'SomeDatabase';
SET #sTable = 'tbl_something';
SET #sColumn = 'SomethingID';
SELECT
syscolumns.name AS column_name,
systypes.name column_type,
syscolumns.length AS column_length,
syscolumns.prec AS column_precision,
syscolumns.scale AS column_scale,
syscolumns.isnullable AS column_nullable,
syscomments.text AS column_default_value -- Should be default value!
FROM
sysobjects
INNER JOIN syscolumns ON sysobjects.id = syscolumns.id
INNER JOIN systypes ON syscolumns.xtype = systypes.xtype
LEFT OUTER JOIN syscomments ON syscomments.id = syscolumns.cdefault
WHERE sysobjects.xtype = 'U'
AND sysobjects.name = #sTable
AND systypes.name != 'sysname'
ORDER BY
sysobjects.name,
syscolumns.colid
Another version is as follows, but it's the same story; returns an empty string on SQL Server 2005, but the correct value on SQL Server 2008.
SELECT COLUMN_DEFAULT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_CATALOG = #sDatabase
AND TABLE_NAME = #sTable
AND COLUMN_NAME = #sColumn
This is used for comparing certain changes between databases. Originally I thought that the problem was because SQL Server 2005 returned default values such as "((0))" while SQL Server 2008 was returning "(0)" for the same default value of the integer 0. That's what SQL Server Management Studio reports respectively. But upon further investigation, it turns out that the default values of SQL Server 2005 are simply not being displayed at all, so it is always recorded as a change when in fact there is none.
Any help deeply appreciated.
Thanks!
Have you tried the sys.default_constraints view?
This snippet finds the default for table TestTable column nr:
create table TestTable (nr float default 3.13)
select definition
from sys.default_constraints dc
join sys.columns c
on c.object_id = dc.parent_object_id
and c.column_id = dc.parent_column_id
where parent_object_id = object_id('TestTable')
and c.name = 'nr'

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 ''?''
'

What is the most portable way to check whether a trigger exists in SQL Server?

I'm looking for the most portable method to check for existence of a trigger in MS SQL Server. It needs to work on at least SQL Server 2000, 2005 and preferably 2008.
The information does not appear to be in INFORMATION_SCHEMA, but if it is in there somewhere, I would prefer to use it from there.
I do know of this method:
if exists (
select * from dbo.sysobjects
where name = 'MyTrigger'
and OBJECTPROPERTY(id, 'IsTrigger') = 1
)
begin
end
But I'm not sure whether it works on all SQL Server versions.
There's also the preferred "sys.triggers" catalog view:
select * from sys.triggers where name = 'MyTrigger'
or call the sp_Helptrigger stored proc:
exec sp_helptrigger 'MyTableName'
But other than that, I guess that's about it :-)
Marc
Update (for Jakub Januszkiewicz):
If you need to include the schema information, you could also do something like this:
SELECT
(list of columns)
FROM sys.triggers tr
INNER JOIN sys.tables t ON tr.parent_id = t.object_id
WHERE t.schema_id = SCHEMA_ID('dbo') -- or whatever you need
This works on SQL Server 2000 and above
IF OBJECTPROPERTY(OBJECT_ID('{your_trigger}'), 'IsTrigger') = 1
BEGIN
...
END
Note that the naive converse doesn't work reliably:
-- This doesn't work for checking for absense
IF OBJECTPROPERTY(OBJECT_ID('{your_trigger}'), 'IsTrigger') <> 1
BEGIN
...
END
...because if the object doesn't exist at all, OBJECTPROPERTY returns NULL, and NULL is (of course) not <> 1 (or anything else).
On SQL Server 2005 or later, you could use COALESCE to deal with that, but if you need to support SQL Server 2000, you'll have to structure your statement to deal with the three possible return values: NULL (the object doesn't exist at all), 0 (it exists but is not a trigger), or 1 (it's a trigger).
Assuming it is a DML trigger:
IF OBJECT_ID('your_trigger', 'TR') IS NOT NULL
BEGIN
PRINT 'Trigger exists'
END
ELSE
BEGIN
PRINT 'Trigger does not exist'
END
For other types of objects (tables, views, keys, whatever...), see: http://msdn.microsoft.com/en-us/library/ms190324.aspx under 'type'.
Tested and doesn't work on SQL Server 2000:
select * from sys.triggers where name = 'MyTrigger'
Tested and works ok on SQL Server 2000 and SQL Server 2005:
select * from dbo.sysobjects
where name = 'MyTrigger' and OBJECTPROPERTY(id, 'IsTrigger')
In addition to the excellent answer by marc_s:
if the existence check is intended prior to dropping or modifying the trigger in some way, use a direct TSQL try/Catch bock, as the fastest means.
For instance:
BEGIN TRY
DROP TRIGGER MyTableAfterUpdate;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS erno WHERE erno = 3701; -- may differ in SQL Server < 2005
END CATCH;
The Error Message will be
Cannot drop the trigger 'MyTableAfterUpdate', because it does not exist or you do not have permission.
Then simply check if the Executed Result returned rows or not, which is easy in direct sql as well as the programmatic APIs (C#,...).
If you're trying to find a server scoped DDL Trigger on SQL Server 2014, you should try sys.server_triggers.
IF EXISTS (SELECT * FROM sys.server_triggers WHERE name = 'your trigger name')
BEGIN
{do whatever you want here}
END
If I told tou anything incorrect, please let me know.
Edit:
I didn't check for this dm on another versions of SQL Server.
Are trigger names forced to be unique in SQL server?
As triggers are by definition applied to a specific table would it not be more efficient to restrict the search to only the table in question?
We have a database with over 30k tables in it all of which have at least one trigger and may have more (bad DB design - quite probably, but it made sense years ago and didn't scale well)
I use
SELECT * FROM sys.triggers
WHERE [parent_id] = OBJECT_ID(#tableName)
AND [name] = #triggerName
I would use this syntax to check and drop trigger
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[SCHEMA_NAME].[TRIGGER_NAME]') AND type in (N'TR'))
DROP TRIGGER [SCHEMA_NAME].[TRIGGER_NAME]
Generated by Sql Server Management Studio:
IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[RolesYAccesos2016_UsuariosCRM_trgAfterInsert]'))
DROP TRIGGER [dbo].[RolesYAccesos2016_UsuariosCRM_trgAfterInsert]
GO
CREATE TRIGGER [dbo].[RolesYAccesos2016_UsuariosCRM_trgAfterInsert]
ON [PortalMediadores].[dbo].[RolesYAccesos2016.UsuariosCRM]
FOR INSERT
AS
...
For select ##version
Microsoft SQL Server 2008 R2 (RTM) - 10.50.1797.0 (X64) Jun 1 2011
15:43:18 Copyright (c) Microsoft Corporation Enterprise Edition
(64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1)
(Hypervisor)

Resources