linked server: four prefixes work with select but not alter - sql-server

I have an SQL Server 13.0 box with
[EC2AMAZ\SQLEXPRESS] as a linked server
I'm running the following commands on the SQL Server 13.0 box
and this select statements work just fine:
select * from [EC2AMAZ\SQLEXPRESS].[import].[dbo].[table]
but this:
ALTER TABLE [EC2AMAZ\SQLEXPRESS].[import].[dbo].[table] ADD field
nvarchar(4000)
throws the error:
The object name 'EC2AMAZ\SQLEXPRESS.import.dbo.table' contains more than the maximum number of prefixes. The maximum is 2.
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near 'field'.
why is it okay to use four prefixes for select but not alter?

You can't run DDL against a linked server. One workaround is to use dynamic SQL:
EXEC [EC2AMAZ\SQLEXPRESS].[import].sys.sp_executesql
N'ALTER TABLE [dbo].[table] ADD field nvarchar(4000);';
The syntax diagram in the official documentation does not include four-part names for ALTER TABLE:
It is officially documented (albeit indirectly) for SELECT in the docs for FROM {<table_source>}:
If the table or view exists outside the instance of SQL Serverl, use a four-part name in the form linked_server.catalog.schema.object.
(Typo is free!)
Such reference does not exist for ALTER TABLE. Yes, it kind of sucks that we have to infer from lack of documentation that something isn't possible, but imagine even trying to document all of the things a feature can't do?
This car:- cannot be used as a flotation device- is not a sufficient source of vitamin C- cannot vote- may not respond to "Betsy"- does not fly- will not fit into bell-bottoms- can't run on carrot juice, diet pepsi, or metamucil...
There is probably a long list of why, including the types of locks required to make schema modifications. But I suspect why isn't the thing that's important here, because answering that question isn't going to change the problem or help you avoid needing to use a workaround.

Related

Find functions using temp tables where NVARCHAR limit does not match its referenced table definition

Problem: Junior SQL dev here, working with a SQL Server database where we have many functions that use temp tables to pull data from various tables to populate Crystal reports etc. We had an issue where a user action in our client caused a string to overflow the defined NVARCHAR(100) character limit of the column. As a quick fix, one of our seniors decided on a schema change to set the column definition to NVARCHAR(255), instead of fixing the issue of the the string getting too long. Now, we have lots of these table based functions that are using temp tables referencing the column in question but the temp table variable is defined as 100 instead of 255.
Question: Is there an easy way to find and update all of these functions? Some functions might not reference the table/column in question at all, but some heavily rely on this data to feed reports etc. I know I can right click a table and select "View Dependencies" in SQL Server Management Studio, but this seems very tedious to have to go through all of them and then update our master schema before deploying it to all customers.
I thought about a find and replace if there is a way to script or export the functions but I fear a problem I will run into is one variable in one function might be declared as TransItemDescription NVARCHAR(100) and one might be TransItemDesc NVARCHAR (100). I've heard of people avoiding temp tables maybe because of these issues so maybe there is just bad database design here?
Thus far I've been going through them one at a time using "View Dependencies" in SSMS.
I think the best solution would be to script out the whole database into a single script from SSMS. Then use Notepad++ (or equivalent) to either find:
All occurrences of NVARCHAR(100)
All occurrences of the variable name, e.g. TransItemDescription, TransItemDesc.
Once you have found all occurrences then make a list of all of the functions to be fixed. Then you would still need to do a manual fix to all functions, but once complete the issue should be totally resolved.

SQL Server and Keyword Schemas

I am in the process of transitioning us from an MSAccess backend to a SQL Server back end.
Without really considering keywords our plan has an Admin, Order and Address schema.I have always read and been taught that you should never use keywords as schema, function,stored procedure, etc. names and that doing so will really hose you.
If I plan to make it standard practice to always explicitely define my schema (E.G. [Admin].CompanyInformation) then is using a keyword an issue?
Once again, qualifying your object names with the schema is NOT related to the use of reserved words as identifiers. You will still encounter a problem using a reserved word as a name even if you qualify it with the schema name. Example:
set nocount on;
use tempdb;
go
create table dbo.[table] (id int not null);
print 'creating dbo.table as a table';
go
-- the next two statements fail
select * from table;
select * from dbo.table;
go
print '';
print 'select from dbo.[table] works**';
select * from dbo.[table];
if object_id('dbo.table') is not null
drop table dbo.[table];
go
So - yes you should use the schema name. And yes - you should avoid the use of reserved words as object names. Doing the former does not negate the need to do the latter. And there are additional rules for object names that you should know - the rules for regular identifiers are https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers.
And even if you choose to NOT follow the rules, you will probably use software that you did not develop and that was not written carefully - which will fail to work correctly when it encounters an object name that is not a regular identifier. And THAT reason is the best reason for adhering to the rules for regular identifiers (one of which is to avoid using reserved words as names).
No, this not an issue if you write [Admin] (not Admin).
P.S. Anyway you should always excplicetly define your schema because default schema is usually dbo

SQL - How to check if altering a table will break any stored procedures

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.

Is one way of stating tables in a query more 'optimal' than another?

Edit: I'm aware that SELECT * is bad practice, but it's used here just to focus the example SQL on the table statement rather than the rest of the query. Mentally exchange it for some column names if you prefer.
Given a database server MyServer (which we are presently connected to in SSMS), with several databases MyDb1, MyDb2, MyDb3 etc and default schema dbo, are any of the following equivilant queries (they will all return exactly the same result set) more "optimal" than the others?
SELECT * FROM MyServer.MyDb1.dbo.MyTable
I was told that this method (explicitly providing the full database name including server name) treats MyServer as a linked server and causes the query to run slower. Is this true?
SELECT * FROM MyDb1.dbo.MyTable
The server name isn't required as we're already connected to it, but would this run 'faster' than the above?
USE MyDb1
GO
SELECT * FROM dbo.MyTable
State the database we're using initially. I can't imagine that this is any better than the previous for a single query, but would it be more optimal for subsequent queries on the same database (ie, if we had more SELECT statements in the same format below this)?
USE MyDb1
GO
SELECT * FROM MyTable
As above, but omitting the default schema. I don't think this makes any difference. Does it?
SQL Server will always look for the objects you sepcify within the current "Context" if you do not specify a fully qualified name.
Is one faster than the other, sure, the same as a file name on your hard drive of "This is a really long name for a file but at long as it is under 254 it is ok.txt" will take up more hard-drive (toc) space than "x.txt". Will you ever notice it, no!
As far as the "USE" keyword, this just sets the context for you, so you dont have to fully qualify object names. The "USE" keyword is NOT sql, you cannot use in in another application (like a vb/c# app) or within a stored procedure but it is like the "GO" keyword in that it tells SSMS to do something, change the context.

SET QUOTED IDENTIFIER should be ON when inserting a record

I am stuck in a rather strange problem with SQL Server 2005, which throws
"SET QUOTED IDENTIFIER should be on when inserting record"
(using as SP) to the particular table. This worked fine earlier but is throwing this error randomly.
I have verified the SP. We didn't manually specify SET QUOTED IDENTIFIER settings inside, so it must be ON by default.
Can someone clarify what could be the problem?
The table must be created with SET QUOTED IDENTIFIER ON right? I didn't check the table script yet.
I have observed that this problem only occur with the SPs doing insert or update on a date column (modifiedAt)... A sample value is '2009-08-10 06:43:59:447'..
Is there a problem with the values passed?
After a long struggle we were able to fix this problem. I just wanted to share the reason.
Our build team maintains a separate in-house tool to deploy scripts, which internally triggers the SQLCMD (shell) utility to execute T-SQL scripts in a db.
Here is the culprit: by default, QUOTED_IDENTIFIER is OFF when running in SQLCMD mode!
Every script run through this tool is created with QUOTED IDENTIFIER OFF. We are the only module which uses indexed views. All the remaining stories you know well in my previous posts :(
NOTE: I am going to vote everyone's post as useful.
Script the stored proc, ensure/change SET options, run the ALTER PROC to ensure SET QUOTED IDENTIFIER ON is set.
Why?
The setting of "SET QUOTED IDENTIFIER" is defined at creation time for stored procs and is always "ON" for tables. Source, BOL.
When a table is created, the QUOTED
IDENTIFIER option is always stored as
ON in the table's metadata even if the
option is set to OFF when the table is
created.
When a stored procedure is created,
the SET QUOTED_IDENTIFIER and SET
ANSI_NULLS settings are captured and
used for subsequent invocations of
that stored procedure.
The default for connections can be defined at the server level (sp_configure 'user options') or database level (ALTER DATABASE). For SSMS, it's under "Tools..Options.. Query Execution..SQL Server..ANSI". It's also the default for client libraries too (except DB-LIb).
Now, it you open an SSMS Query Window and start typing "CREATE PROC.." then it uses SSMS settings when you run the code.
And SET QUOTED IDENTIFIER can not be set at run time inside the stored proc. Show me the a reference before you disagree... From the MS BOL link above:
When executed inside a stored
procedure, the setting of SET
QUOTED_IDENTIFIER is not changed.
You have to work hard to run any code with this OFF... so the most likely fix is to ALTER or re-create the stored proc.
I was just reading this article by Erland Sommarskog, The Curse and Blessings of Dynamic SQL, and it includes the following paragraph in regards to the SET QUOTED IDENTIFIER setting:
The default for this
setting depends on context, but the
preferred setting is ON, and it must
be ON in order to use XQuery, indexed
views and indexes on computed columns.
Does your stored procedure make use of XQuery, indexed views or indexes on computed columns at all?
In SQL Server 2005, SET QUOTED IDENTIFIER is OFF by default, not ON (unless using an ODBC or OLE connection...see this for more information).
You do not need to create the table with SET QUOTED IDENTIFIER ON to use it.
All you need to do is add SET QUOTED IDENTIFIER ON to the beginning of your SP to enable it for the run of the procedure (and make sure that if you don't wish to leave it on, you have SET QUOTED IDENTIFIER OFF to switch it back).
EDIT
I stand corrected. According to this MSDN Page, SET QUOTED IDENTIFIER is ON by default (unless connection with a DB-Library application.

Resources