I am trying to build a dependency tree for a database by tracing object relationships through sys.sql_expression_dependencies (or I might use sys.dm_sql_referenced_entities instead if it's the only way to accomplish this).
I notice that for some referenced objects, I get the referenced_entity_name but not the referenced_schema_name or (crucially) the referenced_id. Looking through Microsoft's page on sys.sql_expression_dependencies I see that these columns can be NULL when "The schema of the referenced entity depends on the schema of the caller and is resolved at run time." Looking into the referencing stored procedure, I see that it refers to the referenced object as simply MyObject, not dbo.MyObject. (Virtually all of this database is in the dbo schema, so some people - myself included - have sometimes lazily neglected to include explicit schema references). I tried changing the procedure definition to explicitly reference dbo.MyObject, and then looked again in sys.sql_expression_dependencies, and I do indeed see the referenced_schema_name and the referenced_id that were previously missing.
I can't, at the moment, fix all objects in the database so that they make all references explicitly by schema. So, my question is: where the Microsoft page says "The schema of the referenced entity depends on the schema of the caller and is resolved at run time" does this simply mean that the SQL engine will always infer that the schema of the referenced object is the same as the schema of the referencing object? If so, I can then use MyReferencingObjectSchema + MyReferencedObjectSchema to look up the object_id for the referenced object and continue building my tree. Or is it more complicated than that?
It's more complicated than that, I'm afraid. It will look for an object with the right name in the connection's default schema as well. This is why you usually don't have to put the schema name in for dbo - that's the usual default schema.
What order it looks for things I don't know - default or current first - but that should be easily testable.
Related
Last week, as a part of one requirement, I wrote a script to generate object definition for all database objects.
While testing, I found that for few stored procedures, [sys.objects].name was not matching with name in actual object definition (as returned by OBJECT_DEFINITION(Object_ID)). It was very strange and I saw it first time in life.
While thinking for what could be the reason of same, I found that it happens when we rename stored procedure from Object Explorer (View--> Object Explorer in SQL Server Management studio).
Just wondering, is there any way to retrieve actual object name (in this case, SP name)?
I had the same problem. It appears SP_RENAME doesn't update the object definition. From the sp_rename link, microsoft says:
Renaming a stored procedure, function, view, or trigger will not change the name of the corresponding object either in the definition column of the sys.sql_modules catalog view or obtained using the OBJECT_DEFINITION built-in function. Therefore, we recommend that sp_rename not be used to rename these object types. Instead, drop and re-create the object with its new name.
I had a similar situation, where a stored procedure had been renamed using sp_rename. The new name used was iterative, with an extension of *_1. If the original name was 'MyProcedure', the new name would have been 'MyProcedure_1'.
'MyProcedure' represented the production code. 'MyProcedure_1' represented code that had been production code at one time, but was now obsolete. Indeed, 'MyProcedure_1' referenced objects that were no longer present in the database.
When looking at the name in sys.objects, the new name with the extension was there ('MyProcedure_1'), but the object_definition returned the old name ('MyProcedure'), but with the code for 'MyProcedure_1'.
This was discovered via a call to 'MyProcedure', which errored out, due to the missing objects.
The solution was to DROP 'MyProcedure_1', which effectively removed the object_id, and the erroneous object_definition, and reCREATE it. Of course we had to address the missing objects. And - we spread caution about using sp_rename for objects other than tables/columns.
I recently used - EXEC sp_rename '<source table name>', '<destination table name>' to rename an existing table and want to execute the same on one of our live server. Is there any issue in using this procedure to rename a table?. I am asking this because one of our DBA says there will be problems in using this procedure on live server.
Is nothing referencing the table you're renaming? That would be the only instance where I would think renaming the table would not have an impact. If the table was not referenced by anything however, what would be the purpose of the table?
you can read more about sp_rename here:
http://msdn.microsoft.com/en-us/library/ms188351.aspx
Specifically note the following:
Renaming an object such as a table or column will not automatically
rename references to that object. You must modify any objects that
reference the renamed object manually. For example, if you rename a
table column and that column is referenced in a trigger, you must
modify the trigger to reflect the new column name. Use
sys.sql_expression_dependencies to list dependencies on the object
before renaming it.
There is no major issue with renaming the table using that procedure. The only thing you need to remember is that while that command is being executed, the locks that are applied on that table won't allow you to query the data, but that should only take only a couple of milliseconds, so you should be fine.
P.S. Don't forget to modify your views, procedures, functions etc :)
Below is the only caution as described inthe microsoft official web site.
Changing any part of an object name can break scripts and stored procedures. We recommend you do not use this statement to rename stored procedures, triggers, user-defined functions, or views; instead, drop the object and re-create it with the new name.
More details at : http://msdn.microsoft.com/en-us/library/ms188351.aspx
EXEC sp_rename is recommended only when we sure that all the depended SP, View function are not get affected. Make sureyou changed or deleted the depended objects.
Perhaps your DBA can share the details of his/her concerns. Renaming a table will of course be a breaking change for any objects that reference the table so you'll need to perform due diligence to ensure dependent objects are changed to use the new name. The rename operation will also require a short schema modification lock and void existing referencing cached plans, so be aware of this if the table is heavily used.
Can someone please explain to me how SQL Server uses dot notation to identify
the location of a table? I always thought that the location is Database.dbo.Table
But I see code that has something else in place of dbo, something like:
DBName.something.Table
Can someone please explain this?
This is a database schema. Full three-part name of a table is:
databasename.schemaname.tablename
For a default schema of the user, you can also omit the schema name:
databasename..tablename
You can also specify a linked server name:
servername.databasename.schemaname.tablename
You can read more about using identifiers as table names on MSDN:
The server, database, and owner names are known as the qualifiers of the object name. When you refer to an object, you do not have to specify the server, database, and owner. The qualifiers can be omitted by marking their positions with a period. The valid forms of object names include the following:
server_name.database_name.schema_name.object_name
server_name.database_name..object_name
server_name..schema_name.object_name
server_name...object_name
database_name.schema_name.object_name
database_name..object_name
schema_name.object_name
object_name
An object name that specifies all four parts is known as a fully qualified name. Each object that is created in Microsoft SQL Server must have a unique, fully qualified name. For example, there can be two tables named xyz in the same database if they have different owners.
Most object references use three-part names. The default server_name is the local server. The default database_name is the current database of the connection. The default schema_name is the default schema of the user submitting the statement. Unless otherwise configured, the default schema of new users is the dbo schema.
What #Szymon said. You should also make a point of always schema-qualifying object references (whether table, view, stored procedure, etc.) Unqualified object references are resolved in the following manner:
Probe the namespace of the current database for an object of the specified name belonging to the default schema of the credentials under which the current connection is running.
If not found, probe the namespace of the current database for an object of the specified name belonging to the dbo schema.
And if the object reference is to a stored procedure whose name begins with sp_, it's worse, as two more steps are added to the resolution process (unless the references is database-qualified): the above two steps are repeated, but this time, looking in the database master instead of the current database.
So a query like
select *
from foo
requires two probes of the namespace to resolve foo (assuming that the table/view is actually dbo.foo): first under your default schema (john_doe.foo) and then, not being found, under dbo (dbo.foo'), whereas
select *
from dbo.foo
is immediately resolved with a single probe of the namespace.
This has 3 implications:
The redundant lookups are expensive.
It inhibits query plan caching, as every execution has to be re-evaluated, meaning the query has to be recompiled for every execution (and that takes out compile-time locks).
You will, at one point or another, shoot yourself in the foot, and inadvertently create something under your default schema that is supposed to exist (and perhaps already does) under the dbo schema. Now you've got two versions floating around.
At some point, you, or someone else (usually it happens in production) will run a query or execute a stored procedure and get...unexpected results. It will take you quite some time to figure out that there are two [differing] versions of the same object, and which one gets executed depends on their user credentials and whether or not the reference was schema-qualified.
Always schema-qualify unless you have a real reason not to.
That being said, it can sometimes be useful, for development purposes to be able to maintain the "new" version of something under your personal schema and the "current" version under the 'dbo' schema. It makes it easy to do side-by-side testing. However, it's not without risk (which see above).
When SQL sees the syntax it will first look at the current users schema to see if the table exists, and will use that one if it does.
If it doesn't then it looks at the dbo schema and uses the table from there
I know databases aren't supported by CREATE SYNONYM, but I'm looking to achieve the functionality this would provide.
We've got Database A which contains views to tables on Database B. The trouble is "Database B" isn't always called "Database B". We use database projects for deployments, which at the moment fall over with an "Invalid Object Name" error if there isn't a "Database B".
The workaround at the moment is to open up the .dbschema file and do a find and replace. I guess another option would be to create a load of table synonyms.
What's the best way of changing the database a number of views reference without changing each view individually?
Thanks
Synonyms are a good way to do this. You have to create the synonyms at the object level though (as you've discovered). An easy way to do this would be to write a script that runs through the list of tables in DatabaseB (from your example) and creates a synonym for each one in DatabaseA. Keep the name of the synonym the same so the code in your views doesn't have to change. For instance, you you have tbl_a, tbl_b, and tbl_c in DatabaseB, you'd want your script to eventually do the following:
create synonym [otherDb].[tbl_a] for [DatabaseB].[schemaB].[tbl_a]
create synonym [otherDb].[tbl_b] for [DatabaseB].[schemaB].[tbl_b]
create synonym [otherDb].[tbl_c] for [DatabaseB].[schemaB].[tbl_c]
Now, in your view code, you'll always use [otherDb].[tbl_a], [otherDb].[tbl_b], and [otherDb].[tbl_c]. Hope this makes sense.
Last year I helped my current client with the implementation of a very similar design. We wrote a set of functions and stored procedures which generate the views automatically. Whenever you need to change the target database it generates the code to drop and recreate all of the views.
The code wasn't too difficult. It just uses the system tables to generate view code. I also wrote a Powershell prototype that uses SMO to do the same thing. The key is to have it automated to the point of requiring a single call so that you can do it easily and accurately.
We also included an exception table that used a pattern match of tables to exclude from view generation. It included a schema column and a table name column, each of which accepted LIKE patterns, so you could put "my_schema" and "%" to exclude all tables in the my_schema schema.
One master stored procedure accepted a target database name and would generate the entire script. Once the script is generated you can run it in SSMS or have that part automated as well.
This whole thing would be even easier if you just wanted to generate synonyms. We were using views so that we could change column lists, etc. and have the view DB look different than the target DB where needed.
I have an assortment of database objects (tables, functions, views, stored procedures) each scripted into its own file (constraints are in the same file as the table they alter) that I'd like to be able execute in an arbitrary order. Is this possible in SQL Server 2005?
Some objects as an example:
Table A (references Table B)
Table B (references Function A)
Function A (references View A)
View A (references Table C)
Must be run in the following order:
Table C
View A
Function A
Table B
Table A
If the scripts are run out of order, errors about the missing objects are thrown.
The reason I ask is that in a project I'm working on we maintain each database object in its own file (for source control purposes), and then maintain a master script that creates each database object in the correct order. This requires the master script to be manually edited any time an object is added to the schema. I'd like to be able to just execute each script as it is found in the file system.
In my experience the most problematic issue is with views, which can reference recursively. I once wrote a utility to iterate through the scripts until the errors were all resolved. Which only works when you're loading everything. Order was important - I think I did UDTs, tables, FKs, views (iteratively), SPs and UDFs (iteratively until we decided that SPs calling SPs was a bad idea, and UDFs are generally a bad idea.)
If you script the foreign keys into separate files, you can get rid of table-table dependencies, if you run the FK script after creating all tables.
As far as I'm aware, functions and procedures check for object existence only in JOIN clauses.
The only difficulty I found was views depending on views, as a view definition requires that the objects the view depends on do exist.
I found this page where the author has written a nice procedure for doing exactly what you are talking about. Sounds like you just need to have two versions of it, one for disabling the constraints and another to re-enable then.
APEX SQL Script is supposed to analyze the dependencies and order the script appropriately, but even then I've had problems.