Database users are similar to SQL
Server logins in that they are principals within the scope of a
database. These users can be granted or denied specific permissions
such as SELECT
on a specific table. They can also be
included in database roles. All database users are members of the
public role. Thus, any permissions that are given to the public role
will be in effect given to every database user.
1. Database Users
When you create a database, a few database users are created for you. One of them is dbo
,
which is the database owner; as the name implies, the role has
permission to perform all activities within the database. Any member of
the sysadmin fixed server role, who accesses a database is
automatically mapped to the dbo
user.
The guest
database user is also
always created. When SQL Server users log into a database where they do
not have mappings, they are automatically mapped to the guest account. guest
is created and is disabled by default. Thus, the default behavior for
SQL Server logins that have no specific mapping is to not have any
access at all to the database.
The sys
and INFORMATION_SCHEMA
views are created and used by SQL Server to provide you with views,
dynamical management views, and catalog views of information about your
database. An example of a catalog view is sys.database_princpals
. This catalog view will show you information about database users and roles for the given database.
2. Schemas
When a database user is created, the user is assigned to a default schema. A schema
is a logical collection of database objects. By grouping objects in a
schema, a DBA can grant permissions to the schema that in turn would
affect all the objects within the schema. If the user does not have a
default schema, but the user is a member of a group that has a default
schema, the default schema of the group will be used.
An Example of the “Wrong” Way
For example, assume you have two database users: DBAUser
and DevUser
. DBAUser
is mapped to a SQL Server login who is a member of the sysadmin
group. DevUser
is a valid database user within the Accounting
database. DevUser
has no specific permissions granted, nor is it included in any database role other than public
. The DBAUser
user would like to give DevUser
the ability to add tables to the Accounting
database but is concerned about the security impact of this action.
The following script sets up the example I’m describing. It creates a database, a login, and a user named DevUser
. Then the script grants the CREATE TABLE
privilege to that user.
USE master
GO
CREATE DATABASE Accounting
GO
CREATE LOGIN DevLogin WITH PASSWORD='asdif983*#@YRfjndsgfD'
GO
USE Accounting
GO
CREATE USER DevUser FOR LOGIN DevLogin
GO
GRANT CREATE TABLE TO DevUser
GO
However, just having the CREATE TABLE
privilege is not enough. If DevUser
connected to SQL Server and tried to issue the following statement:
USE Accounting
GO
CREATE TABLE Customers
(id INT NOT NULL,
firstname VARCHAR(20) NOT NULL,
lastname VARCHAR(40) NOT NULL)
GO
then DevUser
would receive the following error message:
Msg 2760, Level 16, State 1, Line 1
The specified schema name "dbo" either does not exist or you do not have permission to use
it.
Just because DevUser
has the permission to create a table within the Accounting
database doesn’t mean that user can start creating tables. The error
message that comes back tells you that this user doesn’t have access to
a schema called dbo
. By default, database users that are created without a default schema specified are assigned the dbo
schema.
In this example, since the administrator never granted DevUser
access to the dbo
schema, DevUser
cannot create objects within that schema. At this point, DBAUser
could issue the following statement to grant DevUser
the ability to add a table to the dbo schema:
GRANT ALTER ON SCHEMA::dbo TO DevUser
The “Right” Way
Granting the ALTER
permission on the dbo
schema to DevUser
enables that user to create the table. However, by granting ALTER
on this schema, DevUser
can intentionally or unintentionally affect all the other objects within the dbo
schema. For this reason, it is a best practice to create schemas that
serve a specific purpose and grant permissions only to those users who
need them. To correct this example, let’s have the developer create
their new Customers
table in a schema called People
. To start, the DBA will create the People
schema and grant ALTER
permissions to DevUser
. The script is as follows:
CREATE SCHEMA People
GO
GRANT ALTER ON SCHEMA::People TO DevUser
GO
Now DevUser
can issue the following statement to create the Customers
table within the People
schema:
USE Accounting
GO
CREATE TABLE [People.Customers]
(id INT NOT NULL,
firstname VARCHAR(20) NOT NULL,
lastname VARCHAR(40) NOT NULL)
GO
Four-Part Naming Convention
From the previous code sample, the table was created within the People
schema. This can be seen by the two-part name People.Customers
. You can create objects names using up to four parts. Formally the parts are as follows: Server.Database.Schema.Object
.
Note
There is another capability within SQL Server that allows you to link
two SQL Servers together from a query perspective. When you reference
another SQL Server instance within a query, you can create that SQL
Server instance as a linked server to the current SQL Server instance
that you are using.
For example, if you had created a linked server to the SQLPRODUCTION_2
server, you could issue a T-SQL statement that would create a table on the SQLPRODUCTION_2
server as follows:
CREATE TABLE [SQLPRODUCTION_2.Accounting.People.Customers]
More commonly, statements are executed within
the current server context, so the first part is rarely used. The
current database context is also usually defined earlier in the script
(via a USE
statement or via the default database in the connection string), so the second part is also not as common within scripts.
Default Schema
Previously, you learned that by default database users that are created without a default schema specified are assigned the dbo
schema. The exception to this is if the user is mapped to a Windows group and that group has a default schema defined.
As a DBA, you can assign the default schema at user creation time. An example script is as follows:
CREATE USER DevUser FOR LOGIN DevLogin
WITH DEFAULT_SCHEMA = People
You might think of this statement as assigning the default schema.
Reassigning Schema Ownership
Prior to SQL Server 2005, there were essentially two schemas: dbo
and another named after the user. Thus, if DevUser
created the Customers
table within his or her user schema, the two-part name for the Customers
table would be DevUser.Customers
.
The problem with having application schemas based on usernames is that
such a schema prevents you from ever deleting the underlying user. If DevUser
leaves the company, you are stuck maintaining that user because of the
objects within the user’s schema. This behavior was a huge pain in the
rear for many DBAs. And to circumvent the problem, the poor practice of
creating all objects within the dbo
schema came to be.
Since SQL Server 2005, you can now easily
reassign the ownership of the schema, allowing you to drop the
previous, underlying database user with ease. The following script will
reassign the People
schema to TestUser
.
ALTER AUTHORIZATION ON SCHEMA::People TO TestUser
Having reassigned ownership of the People
schema to TestUser
, you may now drop DevUser
.