SQL Server and Keyword Schemas - sql-server

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

Related

linked server: four prefixes work with select but not alter

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.

REST Backend with specified columns, SQL questions

I'm working with a new REST backend talking to a SQL Server. Our REST api allows for the caller to pass in the columns/fields they want returned (?fields=id,name,phone).
The idea seems very normal. The issue I'm bumping up against is resistance to dynamically generating the SQL statement. Any arguments passed in would be passed to the database using a parameterized query, so I'm not concerned about SQL injection.
The basic idea would be to "inject" the column-names passed in, into a SQL that looks like:
SELECT <column-names>
FROM myTable
ORDER BY <column-name-to-sort-by>
LIMIT 1000
We sanitize all column names and verify their existence in the table, to prevent SQL injection issues. Most of our programmers are used to having all SQL in static files, and loading them from disk and passing them on to the database. The idea of code creating SQL makes them very nervous.
I guess I'm curious if others actually do this? If so, how do you do this? If not, how do you manage "dynamic columns and dynamic sort-by" requests passed in?
I think a lot of people do it especially when it comes to reporting features. There are actually two things one should do to stay on the safe side:
Parameterize all WHERE clause values
Use user input values to pick correct column/table names, don't use the user values in the sql statement at all
To elaborate on item #2, I would have a dictionary where Key is a possible user input and Value is a correponding column/table name. You can store this dictionary wherever you want: config file, database, hard code, etc. So when you process user input you just check a dictionary if the Key exists and if it does you use the Value to add a column name to your query. This way you just use user input to pick required column names but don't use the actual values in your sql statement. Besides, you might not want to expose all columns. With a predefined dictionary you can easily control the list of available columns for a user.
Hope it helps!
I've done similar to what Maksym suggests. In my case, keys were pulled directly from the database system tables (after scrubbing the user request a bit for syntactic hacks and permissions).
The following query takes care of some minor injection issues through the natural way SQL handles the LIKE condition. This doesn't go as far as handling permissions on each field (as some fields are forbidden based on the log-in) but it provides a very basic way to retrieve these fields dynamically.
CREATE PROC get_allowed_column_names
#input VARCHAR(MAX)
AS BEGIN
SELECT
columns.name AS allowed_column_name
FROM
syscolumns AS columns,
sysobjects AS tables
WHERE
columns.id = tables.id AND
tables.name = 'Categories' AND
#input LIKE '%' + columns.name + '%'
END
GO
-- The following only returns "Picture"
EXEC get_allowed_column_names 'Category_,Cat%,Picture'
GO
-- The following returns both "CategoryID and Picture"
EXEC get_allowed_column_names 'CategoryID, Picture'
GO

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.

How can I check if a word is a reserved keyword in Sybase (can't be used as column name)?

Question:
How can I (programmatically) obtain a complete list of reserved keywords in Sybase?
Specifically, ones that can not be a column name in a table.
Alternately, how can I check whether a specific identifier is a reserved keyword in Sybase?
Background:
I have a process which takes a comma separated file with headers and loads into a temp table in Sybase.
The goal is to have the temp table column names match the file column names.
This will fail if the file has a column named after a reserved keyword.
I'd like to catch that scenario BEFORE the CREATE TABLE statement fails.
Notes:
I am looking for a Sybase-version-independent solution.
Therefore "copy all the words in Sybase Reference Manual (e.g. this for v.12.5) is NOT a valid answer. I'm perfectly aware I can do that. But it will not work in Sybase 15 without changing the keyword list by hand.
If the solution exists but not available in earlier Sybase versions, I need something compatible with Sybase 12.5 and later
I'm also perfectly aware of how to do this by creating a table with any words I have, trapping CREATE TABLE failure, and reading which word failed. I'm looking for a more elegant solution if available.
Found a way after more Googling!
select name from master..spt_values where type="W"
First, turn on "quoted_identifier" in your config (set quoted_identifier on). Then escape all your column names with double quotes.
That way you don't need to catch which ones are reserved words, and all columns will have the names you expect them to have.

What is the use of the square brackets [] in sql statements?

I've noticed that Visual Studio 2008 is placing square brackets around column names in sql. Do the brackets offer any advantage? When I hand code T-SQL I've never bothered with them.
Example:
Visual Studio:
SELECT [column1], [column2] etc...
My own way:
SELECT column1, column2 etc...
The brackets are required if you use keywords or special chars in the column names or identifiers. You could name a column [First Name] (with a space) – but then you'd need to use brackets every time you referred to that column.
The newer tools add them everywhere just in case or for consistency.
They're handy if your columns have the same names as SQL keywords, or have spaces in them.
Example:
create table test ( id int, user varchar(20) )
Oh no! Incorrect syntax near the keyword 'user'.
But this:
create table test ( id int, [user] varchar(20) )
Works fine.
They are useful if you are (for some reason) using column names with certain characters for example.
Select First Name From People
would not work, but putting square brackets around the column name would work
Select [First Name] From People
In short, it's a way of explicitly declaring a object name; column, table, database, user or server.
During the dark ages of SQL in the 1990s it was a good practice as the SQL designers were trying to add each word in the dictionary as keyword for endless avalanche of new features and they called it the SQL3 draft.
So it keeps forward compatibility.
And i found that it has another nice side effect, it helps a lot when you use grep in code reviews and refactoring.
Regardless of following a naming convention that avoids using reserved words, Microsoft does add new reserved words. Using brackets allows your code to be upgraded to a new SQL Server version, without first needing to edit Microsoft's newly reserved words out of your client code. That editing can be a significant concern. It may cause your project to be prematurely retired....
Brackets can also be useful when you want to Replace All in a script. If your batch contains a variable named #String and a column named [String], you can rename the column to [NewString], without renaming #String to #NewString.
Column names can contain characters and reserved words that will confuse the query execution engine, so placing brackets around them at all times prevents this from happening. Easier than checking for an issue and then dealing with it, I guess.
The brackets can be used when column names are reserved words.
If you are programatically generating the SQL statement from a collection of column names you don't control, then you can avoid problems by always using the brackets.
In addition
Some Sharepoint databases contain hyphens in their names. Using square brackets in SQL Statements allow the names to be parsed correctly.
They are useful to identify each elements in SQL.
For example:
CREATE TABLE SchemaName.TableName (
This would actually create a table by the name SchemaName.TableName under default dbo schema even though the intention might be to create the table inside the SchemaName schema.
The correct way would be the following:
CREATE TABLE [SchemaName].[TableName] (
Now it it knows what is the table name and in which schema should it be created in (rightly in the SchemaName schema and not in the default dbo schema)
I believe it adds them there for consistency... they're only required when you have a space or special character in the column name, but it's cleaner to just include them all the time when the IDE generates SQL.

Resources