syntax difference between .. and . in SQL Server in sysobjects - sql-server

I've seen something like this in SQL Server (running this query against the master database):
select * from tempdb..sysobjects
which seems to return exactly the same results as:
select * from tempdb.sys.objects
I've seen that the double dot can be used as a way to omit the schema name but I don't see anything omitted here, going by that logic then tempdb..objects would be valid which is not).

tempdb..objects will be interpretted as tempdb.dbo.objects
Both are two different system views
sys.objects
Contains a row for each user-defined, schema-scoped object that is
created within a database, including natively compiled scalar
user-defined function.
sys.sysobjects
Contains one row for each object that is created within a database,
such as a constraint, default, log, rule, and stored procedure
Note : This SQL Server 2000 system table is included as a view for backward compatibility. We recommend that you use the current SQL Server system views instead. To find the equivalent system view or views, see Mapping System Tables to System Views (Transact-SQL). This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature.

Related

How to access LinkedServer on another database in SQL Server

I want to know how to access LinkedServer of databaseA from databaseB in SQL Server.
I need to know sample code. Thanks.
If the servers are already linked, are both running SQL Server (you're not linking to a different kind of database completely), and you are connected to databaseB with a login having appropriate permissions, here is an example:
SELECT <columns>
FROM ServerName.databaseA.schema.Table alias
WHERE alias.Column = 'SomeValue'
Note you need to use all four parts of the name (server, database, schema, object), and therefore you will definitely want to use a table alias. The schema is practically almost always dbo, and can often be elided with just an extra . ( FROM ServerName.databaseA..Table).
But as long as you get the name right, you can use items in databaseA as if they were there in B, including for JOINs and similar. However, performance can be poor, because the server for databaseB must put together an execution plan without knowing anything about indexes or statics from databaseA.
If the databaseA is something other than SQL Server, you will need to use OPENQUERY(). Like the first option, OPENQUERY() results can be given an alias and then used with JOIN, APPLY, subquery, etc, and the same warning about performance applies.

Table sysobjects has changed or does not longer exist after SQL Server 2005. What is the equivalent?

I am looking at a report for upgrade compatability on sql server and seeing the following error:
Table sysobjects has changed or does not longer exist after SQL Server 2005. Using it may cause errors. For more details, please see: Line X, Column Y.
We are moving to SQL server 2016 what would I need to replace sysobjects with.
The portion of the stored proc that is generating the above 110 compatibility message looks as follows:
SELECT name FROM sysobjects
Many of the system tables from earlier releases of SQL Server are now
implemented as a set of views. These views are known as compatibility
views, and they are meant for backward compatibility only. The
compatibility views expose the same metadata that was available in SQL
Server 2000. However, the compatibility views do not expose any of the
metadata related to features that are introduced in SQL Server 2005
and later.
Here you can find the list of System Compatibility Views
Besides, if you search in google for sysobject/other "old" system table, the first thing that will be written there is that the table is deprecated, use new_ system_view instead, this way you can find the new one

Name clash with sys.sysusers system view in SQL Server

(Note that this was on SQL Server 2008, but I have a colleague who reports the same issue on SQL Server 2014.)
I'm using a framework that supports multiple database back-ends, and our application has a table called sysUsers, which works fine in MySQL.
We now need to install it on SQLServer and it appears that this name conflicts with a built-in system view. The system view is sys.sysusers and the application table is dbo.sysUsers.
I am aware that the case difference is irrelevant to SQL Server, however the schema seems to be being ignored for some reason.
SELECT * FROM sys.sysusers; returns records from sys.sysusers. This is wholly as expected.
SELECT * FROM sysUsers; returns records from sys.sysusers. This is surprising (I would have thought the local schema would take precedence) but perhaps explicable.
However, SELECT * FROM dbo.sysUsers; still returns records from sys.sysusers. This seems just plain wrong as I am explicitly selecting the dbo schema.
I haven't found anything in the MS documentation that says these names are reserved.
I have tried renaming the table and hacking the code to use a different name, and everything works (i.e. this is nothing to do with the SQLServer integration within the application) and the same results are seen when running the queries from the management console directly. Therefore this appears to definitely be an issue with the conflicting table name and not a middle-ware error or syntax difference.
If this table name is reserved, why does MSSMS allow me to create it? If it is not reserved, why does it not let me query it?
And how can I work round the problem without requiring application updates (as these would be a migration headache for other deployments).
There are at least three workarounds, but none guarantee that no code has to be rewritten (except the one that's horribly unsafe):
Use a case-sensitive collation when creating your database (CREATE DATABASE Foo COLLATE Latin1_General_CS_AS). In this case, sysUsers will be a different object from sysusers, in all circumstances. You can set a case-insensitive collation immediately after creating the database so your data doesn't end up case-sensitive, as this is probably not what the end users want. Obviously this won't work if your application is actually relying on case-insensitive object names, unless you rewrite your queries carefully. Note that this means that all database objects, even those created afterwards, will have case-sensitive names, as this is embedded in the system tables on creation and can't be changed afterwards.
Use a schema other than dbo. The system table mapping occurs only for that scheme, not any others. If your application uses its own schema exclusively, any sysusers you create in that will not be aliased to sys.sysusers. (This isn't documented anywhere, but it is how it works.) Note that in order for this to work, you must always specify the schema explicitly even when it is the default schema for your user, otherwise you will again get the system table (I'd consider this a bug, but it's probably a necessity because of the way old scripts will assume sysusers resolves anywhere).
Enable the Dedicated Administrator Connection, restart SQL Server in single user mode, switch the mssqlsystemresource database to READ_WRITE and DROP VIEW sysusers. This will remove sys.sysusers from all databases. Doing this will void your warranty, it will cause Microsoft Support to laugh at you if you come crying to them, it may make installing future Service Packs and updates impossible and is emphatically not recommended, but I'm mentioning it anyway, for science. No code anywhere should be using this view, but, you know, I'm not an engineer working on SQL Server itself.
Note that lowering the compatibility level is not a workaround, which I mention for completeness. This has no effect on how these table names are resolved, even if it was a desirable approach (which it's not).
I consider the change made in SQL Server 2012 to ignore the dbo qualifier and resolve to these old, deprecated names anyway a mistake and if it were up to me I'd at least make it possible to opt out of this behavior with a trace flag, but it's not up to me. You could consider opening up an issue on Microsoft Connect for it, because the current behavior makes it needlessly complicated for RDBMS-agnostic code to run.

SQL Server How to add a linked server to the same instance without performance impact

in my company, we have several environments with MS SQL database servers (SQL 2008 R2, SQL 2014). For the sake of simplicity, let us consider just a TEST environment and a PROD environment and two sql servers in each. Let the servers be called srTest1, srTest2, srProd1, srProd2 and each be running a default MS SQL Server instance. We work with multiple databases, say DataDb, ReportDb, DWHDb.
We want to keep the same source code in T-SQL for both TEST and PROD, but the problem is the architecture or distribution of the above mentioned databases in each environment:
TEST:
srTest1 - DataDb
srTest2 - DWHDb, ReportDb
PROD:
srProd1 - DataDb, ReportDb
srProd2 - DWHDb
Now, say, in ReportDb, we write stored procedures with many SELECTs referencing tables and other objects in DataDb and DWHDb. In order to have source code as universal as possible, we decided to create linked servers for each database on each db server in each environment and name them with respect to the database they're created for. Therefore, there'll be these linked servers:
lnkDataDb, lnkReportDb and lnkDWHDb on srTest1,
lnkDataDb, lnkReportDb and lnkDWHDb on srTest2,
lnkDataDb, lnkReportDb and lnkDWHDb on srProd1,
lnkDataDb, lnkReportDb and lnkDWHDb on srProd2.
And we'll adjust the source in the stored procs accordingly. For instance:
Instead of
SELECT * FROM DataDb.dbo.Contact
We'll write
SELECT * FROM lnkDataDb.DataDb.dbo.Contact
The example above is reasonable for a situation where the database from which you execute the query (ReportDb) lies on a different server than that with the referenced table (DataDb). Which is the case for the TEST environment. But not so in PROD. It is performance I'm here concerned about. The SQL Server will treat that SELECT as a "remote query" no matter whether, in fact, it is a reference to a local object or not.
Now, it comes the most important part:
If you check these 3 queries for their actual execution plans, you'll see an interesting thing:
(1) SELECT * FROM DataDb.dbo.Contact
(2) SELECT * FROM srProd1.DataDb.dbo.Contact
(3) SELECT * FROM lnkDataDb.DataDb.dbo.Contact
The first two (query #1 and #2) have the same execution plan (the fastest possible) even if you use the four-part name manner of referencing the table Contact in #2.
The last query has a different plan (remote query, thus slower).
The question is:
Can you somehow create a linked server to self (the same sql server instance, the default instance actually) as an "alias" to the name of the host (srProd1) in order for the SQL server to be forced to understand it as local and not issue "remote execution" plans?
Thanks a lot for any hints
Pavel
Recently I found a workaround which seems to solve this kind of issues more efficiently and more elegantly than the solution with self-pointing linked servers.
If you work (making reports, for example) with multiple databases on multiple SQL servers and the physical distribution of the databases on the servers is a challenge since it may differ from one environment to another (e.g. TEST vs PROD), I suggest this:
Use three-part db object names whenever possible. If the objects are local, then execution plans are also local, and thus effective.
Example:
SELECT * FROM DataDb.dbo.Contact
If you happen to run the above query from within a different SQL server instance (residing on a different physical machine, for example, but this not necessarily, the other SQL server instance could be installed even on the same machine), briefly if you're about to use a four-part name:
SELECT * FROM lnkDataDb.DataDb.dbo.Contact
Then you can circumvent that using the following trick:
Let's assume lnkDataDb points to srTest2 and you're executing your queries from srTest1. Now, you'll create a "fake" database DataDb on your local server (srTest1). This fake DataDb shall contain no real db objects (no tables, no views, no stored procedures, no UDFs etc.). There shall only be synonyms defined in it. (And there also shall be the same schemas in it as those in the real DataDb on srTest2). These synonyms shall be named exactly the same way as their real db-object counterparts in DataDb on srTest2. Example:
-- To be executed on srTest1.
EXEC sp_addlinkedserver
#server = N'lnkDataDb',
#srvproduct = N'',
#provider = N'SQLNCLI',
#datasrc = N'srTest2'
;
GO
CREATE DATABASE [DataDb];
GO
USE [DataDb];
GO
CREATE SYNONYM dbo.Contact FOR lnkDataDb.DataDb.dbo.Contact;
GO
Now, if you want to SELECT rows from the table dbo.Contact residing in the database DataDb on srTest2 and you're executing your query from srTest1, you'll use a simple three-part table name:
SELECT * FROM DataDb.dbo.Contact
Of course, on srTest1, this is not a table, that's just a synonym referencing the same-named table on srTest2. However, that's the trick, you use the same query syntax as if you were executing it on srTest2 where the real db object resides.
There are disadvantages of this approach:
On the local server, at the beginning, there must not be a database
with the same name as the remote one. Because you're about to create
a "fake" database with that name to reflect the names of remote
db objects.
You're creating one database that is almost empty, thus
increasing the mess of various databases residing on your local
SQL server. This might provoke reluctance of your database admin
if they prefer having as few databases as possible.
If you're developing your T-SQL scripts in SQL Server Management
Studio, for example, using synonyms cuts you off from the convenience
of the IntelliSense feature.
Advantages outweigh the above-mentioned disadvantages, though:
Your scripts work in any environment (DEV, TEST, PROD) without
the need to change any part of the source code.
If the other database you're querying data from resides on the same
SQL server instance as your script, you also use the three-part name
convention and your SQL server evaluates the query in execution plan
as local which is OK. (This is what the original question of this
post was searching to solve.)
If the other database you're querying data from resides on another
SQL server instance, you still use a "local syntax manner" of a SQL
query (with the synonym) which, only at runtime, evaluates in
a remote execution plan. Which is also fine because the db object
actually is remote.
To summarize
The query executes as local if the referenced object is local, the query executes as remote if the referenced object is remote, but the T-SQL script is always the same. You don't have to change a letter in it.

Python - extracting a SQL Server database schema to a file

Often I need to extract the complete schema of an existing SQL Server DB to a file. I need to cover every object -- tables, views, functions, SPs, UDDTs, triggers, etc. The purpose is so that I can then use a file-diff utility to compare that schema to a baseline reference.
Normally I use Enterprise Manager or Management Studio to script out the DB objects and then concatenate those files to make one big file in a consistent predictable order. I was wondering whether there's a way to accomplish this task in Python? Obviously it'd take an additional package, but having looked at a few (pyodbc, SQLAlchemy, SQLObject), none of them seem really suited to this use case.
If you can connect to SQL Server and run queries in Python then yes – it’s possible but it will take a lot of effort and testing to get it to work correctly.
Idea is to use system tables to get details about each object and then generate DDL statements based on this. Some if not all DDL statements already exist in sys.syscomments table.
Start off by executing and examining this in SSMS before you start working in Python.
select *
from sys.tables
select *
from sys.all_columns
select *
from sys.views
select *
from sys.syscomments
All system tables documentation from MSDN.
I've used this PowerShell strategy in the past. Obviously, that isn't Python, but it is a script you can write then execute from within Python. Give this article a read as it may be your easiest (and cheapest) solution: http://blogs.technet.com/b/heyscriptingguy/archive/2010/11/04/use-powershell-to-script-sql-database-objects.aspx
As a disclaimer, I was only exporting stored procedures, not every single object.

Resources