I have two schemas on a database named DBO and Switch. I have created this DDL trigger that logs DDL changes on DBO to a table. I then check if the objects affected by the DDL are partitioned or not and if yes I run the same DDL on the other schema Switch. This approach works fine unless the user doesn't specify the schema name in the DDl statement.
I am looking for a way to check the issued DDl for the presence of schema name, and if not present then issue the DDL by default on SWitch schema.
Any ideas on how can I achieve this? I am new to TSQL coding and would appreciate anyone helping me out with this one.
In EVENTDATA available to use in DDL Trigger, there are following fields (among others) available:
<EVENT_INSTANCE>
<DatabaseName>RT-BOOKS</DatabaseName>
<SchemaName>dbo</SchemaName>
<ObjectName>Books_PL$ID</ObjectName>
<TSQLCommand>
<CommandText>
</CommandText>
</TSQLCommand>
</EVENT_INSTANCE>
If <SchemaName> is not enough for you (if understood correctly, you want to check if user explicitly used schema name in a query), then try to parse <CommandText> using <SchemaName> and <ObjectName>.
Related
Is there a nice way before I alter a table (e.g. remove a column), to see if that this will break any stored procedures?
I am trying to do this in MS SQL Server
Use the query here to search all stored procedures for the table and column name. You will probably still want to look at the code for each one you find to verify that it will or won't break.
you can use the following query to search for the table name in any stored procedures:
SELECT name
FROM sys.procedures
WHERE Object_definition(object_id) LIKE '%Your_Table_Name%'
I suggest you:
Make sure you have a separate environment (DEV)
Use the sample code from here to create a proc that confirms all objects in the database can be recompiled
How to Check all stored procedure is ok in sql server?
Use it - I can guarantee you will already have failing objects before you remove your column
Remove your column and use it again to see if more things broke
The more mature approach to this is to put your database into a database project and build that. But you can't do this until your database is valid.
I'd like to use SQL OUTPUT clause to keep history of the records on my database while I'm using Entity Framework. To achieve this, EF needs to generate the following example for a DELETE statement.
Delete From table1
output deleted.*, 'user name', getdate() into table1_hist
Where field = 1234;
The table table1_hist has the same columns as table1, with the addition of two columns to store the name of the user who did the action and when it happened. However, EF doesn't seem to have a way to support this SQL Server's clause, so I'm lost on how to implement that.
I looked at EF's source code, and the DELETE command is create inside a internal static method (GenerateDeleteSql in System.Data.Entity.SqlServer.SqlGen.DmlSqlGenerator class), so I can't extend the class to add the behavior I want. It looks like I'll have to rewrite the SQL Server provider based on the existing code, but that is something I'd like to avoid...
So, my question is if there's another option to do this (an extension, for example) or do I have to rewrite this provider?
Thank you.
Have you considered either
Using Stored Procedures to encapsulate your data logic
A delete trigger to capture the data
Change Data Capture (Enterprise edition only)
not actually deleting the data - merely setting a flag in the data to mark it as deleted.
As the title suggests I am confused as to why some tables in my database fall over if you do something like;
SELECT * FROM [user].[table]
And yet on another tables it works fine.
I am testing some code that will eventually be on a server that cries if you don't use [user].[table] so I would really like to force this on my machine.
Could someone explain why this happens and possible show me how to fix it.
More Info
Here is the message I get when I try and run a query using [user].[table] instead of just [table];
[Microsoft][ODBC SQL Server
Driver][SQL Server]Invalid object name
'usr.tbl'
The "user" bit is the schema a table belongs to
So you can have dbo.table and user.table in the same database.
By default, SELECT * FROM table will usually look for the dbo.table. However, if the login/user has a different default schema then it will look for thatschema.table
To fix it:
You can use ALTER SCHEMA .. TRANSFER.. to fix the current setup
Ongoing, ensure every table reference has the correct schema on CREATE, ALTER, SELECT, whatever
Also see "User-Schema Separation" on MSDN
What you refer to as [user] is actually something called a schema. Every user has a default schema, which means that when you are logged in as that user you can refer to the tables in the default schema without the schema prefix. One way to solve this would to be to make sure that no user has the default schema where the tables are located. Basically you can just make an emptry schema and use that as the default schema for all your users.
Go to YourDatabase->Security->Users and see the properties (by right clicking) to change the default schema for your users.
Is there something in SQL Server similar to USE (to switch databases) that can control the owner prefix that is used for tables?
For example, we have an application that insists on creating tables "theServiceAccount.TheTableName" ; What we really want is to force it to put the table names under dbo... so "dbo.TheTableName" . We don't have a good way to change the SQL that the application runs (it is vended), other than a hook when it starts up that allows us to run some SQL. So it would be great if we could run a sql at that point which would make subsequent create table (or other operations) default to dbo instead of the service account being used.
I do realize that the create table syntax allows one to specify the owner, but that doesn't seem to be an option at this point. From what I can tell, the SQL this application generates never specifies the owner; it just has the table name in the SQL it runs.
Thanks!
In 2005, by default each user has their own default schema, unless specified.
This should do what you need:
USE databasename
ALTER USER theServiceAccount WITH DEFAULT_SCHEMA = dbo
You can also change this via SSMS by looking at the user properties and changing the default schema
I believe you can do this by creating a user with the default schema you want and then using the EXECUTE AS statement (see http://msdn.microsoft.com/en-us/library/ms181362.aspx)
In your example you could create a user (or use dbo, not advised) called 'specialDBO' that has their default schema set to dbo. Then you have something like this:
USE [myfabdb];
EXECUTE AS USER = 'speicalDBO';
... blah blah blah...
REVERT;
Remember, you can't have the USE statement after the EXECUTE AS statement.
If I have tables like this:
ImportSet1.Users
ImportSet2.Users
ImportSet3.Users
Then in my sproc I do this:
CREATE PROCEDURE [ImportSet2].[UpdateUsers]
...
UPDATE Users
set blah = 234
WHERE id = 234
This seems to work, but why? Since when did that prefix [ImportSet2] signify part of the table name? (in this case ImportSet2)
The sproc is built under the ImportSet2 schema, so, by default, it will reference objects in the ImportSet2 schema if no schema name is specified.
I believe it is best-practice, however, to fully-qualify objects with their schema name.
To answer "since when", certainly by 2000 you could have objects owned by owners other than dbo. Since 2005, MS separated the concept of owners and schemas.
I believe the feature appeared in an early release of SQL Server, either 6.5 or 7.0. So it's hardly new (although there's considerable pain using the feature before 2005)