Give permissions to Create/Drop views only - sql-server

I'm working with
Microsoft SQL Server 2019 (RTM-GDR) - 15.0.2095.3 (X64) Apr 29 2022 18:00:13
Copyright (C) 2019 Microsoft Corporation
Standard Edition (64-bit) on Windows Server 2016 Datacenter 10.0 <X64> (Build 14393: ) (Hypervisor)
I want to give a user rights to only CREATE and DROP VIEWS and deny rights to CREATE and DROP tables, schemas, or the whole database.
Is there a combination on the permissions level available to achieve this? So far all I found was that ALTER rights on the schema are required to create views, which however also gives users rights to actions I want to deny them.
The background is that we want to give users read-only rights to the database with the exception of creating and deleting views.

As I mentioned in my (now deleted) comments, using a schema might be the easier solution here. Although you can give a USER permissions to explicitly CREATE a VIEW the ALTER can't be an granular. Instead, however, you could give them access to a specific schema and then they can create (and ALTER) their views as they see fit. This is a "quick" example demonstrating the method:
USE master;
GO
CREATE DATABASE TestDB;
GO
USE TestDB;
GO
CREATE TABLE dbo.YourTable (ID int IDENTITY(1,1) CONSTRAINT PK_YourTable PRIMARY KEY,
SomeInt int NOT NULL);
GO
CREATE TABLE dbo.AnotherTable (ID int IDENTITY CONSTRAINT PK_AnotherTable PRIMARY KEY,
YourID int NOT NULL CONSTRAINT FK_AnotherTable_YourID FOREIGN KEY REFERENCES dbo.YourTable(ID),
SomeDate date NULL);
GO
INSERT INTO dbo.YourTable (SomeInt)
VALUES(1),(17),(12),(1634),(-5);
GO
INSERT INTO dbo.AnotherTable (YourID,
SomeDate)
VALUES(1,GETDATE()),(1,'20220101'),
(3,GETDATE()),
(4,'20221001'),(4,'20221002'),(4,'20221003'),
(5,'20221215'),(5,'20221015');
GO
GO
CREATE SCHEMA V; --V for Vende.... View
GO
CREATE USER SomeUser WITHOUT LOGIN;
GO
GRANT ALTER, CONTROL,SELECT ON SCHEMA::V TO SomeUser;
GRANT CREATE VIEW TO SomeUser;
GO
EXECUTE AS USER = 'SomeUser';
GO
--This will fail
CREATE VIEW dbo.NoAccess AS
SELECT ID,
YourID,
SomeDate
FROM dbo.AnotherTable;
GO
SELECT *
FROM dbo.NoAccess;
GO
--This'll work
CREATE VIEW V.RelatedRows AS
SELECT Y.ID AS YourID,
Y.SomeInt,
A.ID AS AnotherID,
A.SomeDate
FROM dbo.YourTable Y
JOIN dbo.AnotherTable A ON Y.ID = A.YourID;
GO
SELECT *
FROM V.RelatedRows;
GO
--Alter the View to a LEFT JOIN
CREATE OR ALTER VIEW V.RelatedRows AS
SELECT Y.ID AS YourID,
Y.SomeInt,
A.ID AS AnotherID,
A.SomeDate
FROM dbo.YourTable Y
LEFT JOIN dbo.AnotherTable A ON Y.ID = A.YourID;
GO
--For this example, they also have no direct access to the tables; you may need to change this.
SELECT *
FROM dbo.YourTable;
GO
REVERT;
GO
USE master;
GO
DROP DATABASE TestDB;
The above will both CREATE and ALTER the VIEW V.RelatedRows, while failing to create the VIEW dbo.NoAccess. As noted as well, I don't give explicit access to dbo schema to the USER, they can only access the data through permission chaining. That may not be desired, but I wanted to demonstrate that the user doesn't actually even need direct access to the table to be able to be able to use it in this scenario.

Related

SQL Server ownership chain cross schema with different owners for view selecting from multiple schemas

I have 1 database with multiple schemas, some owned by a different user than the default 'dbo' user.
I have a view in one of these 'dbo' schemas, that selects from 5 tables in other 'dbo' schemas, and then 2 tables in a 'UserA' schema.
I want to grant a user group access to the view in the 'dbo' schema and not the underlying tables. When granting permission to the view, I get errors saying cannot select from the tables owned by 'UserA'. Understandable and expected because the view (and thus authorizations granted) are for 'dbo'. So how do I also grant access to the 'UserA' tables without directly assigning them to my user group.
Any recommendations? I tried to find if there is some way to grant access to the view through both 'dbo' and 'UserA', but it seems only 1 owner can grant select permissions? I also tried making views of the 'UserA' table in the 'dbo' schema and then granting permission to those new 'dbo' views, but that didn't work either.
No permissions on the underlying tables are needed when all objects involved are owned by the same user. This is known as ownership chaining in SQL Server.
It seems you have different schemas which are owned by different users, breaking the chain. Tables are owned by the schema's owner by default (i.e. inherited) but this can be overridden by changing the owner at the table level for specialized requirements. Below is an example script that illustrates this method.
Using granular object ownership rather than inheriting the schema owner is not something that should be done routinely. It is not intuitive for most and adds administrative burden.
USE tempdb;
GO
CREATE USER UserA WITHOUT LOGIN;
GRANT CREATE TABLE TO UserA;
CREATE USER UserB WITHOUT LOGIN;
GRANT CREATE TABLE TO UserB;
CREATE USER UserC WITHOUT LOGIN;
CREATE ROLE YourUserGroup;
ALTER ROLE YourUserGroup ADD MEMBER UserC;
GO
CREATE SCHEMA UserA AUTHORIZATION UserA;
GO
CREATE SCHEMA UserB AUTHORIZATION UserB;
GO
CREATE TABLE dbo.Table1(ID int NOT NULL CONSTRAINT PK_Table1 PRIMARY KEY);
GO
EXECUTE AS USER = 'UserA';
GO
CREATE TABLE UserA.Table1(ID int NOT NULL CONSTRAINT PK_Table1 PRIMARY KEY);
GO
REVERT;
GO
EXECUTE AS USER = 'UserB';
GO
CREATE TABLE UserB.Table1(ID int NOT NULL CONSTRAINT PK_Table1 PRIMARY KEY);
GO
REVERT;
GO
CREATE VIEW dbo.View1
AS
SELECT
t1.ID AS dboTable1ID
, t2.ID AS UserATable1ID
, t3.ID AS UserBTable1ID
FROM dbo.Table1 AS t1
JOIN UserA.Table1 AS t2 ON t2.ID = t1.ID
JOIN UserB.Table1 AS t3 ON t3.ID = t2.ID;
GO
GRANT SELECT ON dbo.View1 TO YourUserGroup;
GO
EXECUTE AS USER = 'UserC';
GO
--this fails due to broken ownership chain
SELECT * FROM dbo.View1;
GO
REVERT;
GO
--change table owner to common owner
ALTER AUTHORIZATION ON OBJECT::UserA.Table1 TO dbo;
ALTER AUTHORIZATION ON OBJECT::UserB.Table1 TO dbo;
GO
EXECUTE AS USER = 'UserC';
GO
--this now succeeds because all objects involved are owned by dbo
SELECT * FROM dbo.View1;
GO
REVERT;
GO
DROP VIEW dbo.View1;
DROP TABLE dbo.Table1;
DROP TABLE UserA.Table1;
DROP TABLE UserB.Table1;
DROP SCHEMA UserA;
DROP SCHEMA UserB;
DROP USER UserA;
DROP USER UserB;
DROP USER UserC;
GO

Changing the Order of Columns in a Table Permanently Using T-SQL query

My table is student_register and has four columns like
1. srno
2. firstname
3. lastname
4. middlename
I want the column middlename in third position permanently in table using SQL Server 2005 query.
Thank you.
There's no way to do what you want without dropping and readding the table. To see how Management Studio accomplishes this (at least in 2012, but I think this applies to 2005 too), go to Management Studio's Options > Designers > Table and Database Designer > Uncheck Prevent saving changes that require table re-creation.
Once you do that you can go in to the table designer, change the order of the columns and instead of clicking "Save", click "Save Change Script" to see the SQL.
Here is what SQL 2012 would generate:
/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_Table_1
(
TEst1 nchar(10) NULL,
Test3 nchar(10) NULL,
Test2 nchar(10) NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_Table_1 SET (LOCK_ESCALATION = TABLE)
GO
IF EXISTS(SELECT * FROM dbo.Table_1)
EXEC('INSERT INTO dbo.Tmp_Table_1 (TEst1, Test3, Test2)
SELECT TEst1, Test3, Test2 FROM dbo.Table_1 WITH (HOLDLOCK TABLOCKX)')
GO
DROP TABLE dbo.Table_1
GO
EXECUTE sp_rename N'dbo.Tmp_Table_1', N'Table_1', 'OBJECT'
GO
COMMIT
Since it's a one time thing the simplest approach would be to use Visual Database Tools for that
How to: Change Column Order (Visual Database Tools) SQL Server 2005
In Object Explorer, right-click the table with columns you want to reorder and click Design (Modify in SP1 or earlier). The table opens in Table Designer.
Select the box to the left of the column name that you want to reorder.
Drag the column to another location within the table.
To do it in TSQL you'll need:
create a temp table with correct order of columns
insert data into temp table from original table
drop original table
rename temp table to original name

How do I create a user in SQL-Server that only has access to one table, and can only insert rows

I have an SQL server database, with soon to be two databases, which I use for a website.
I already have a user account which is read-only for database 1 to search our products inventory. I'd like to create a seperate account for database 2 only, for table 1 ONLY, that ONLY allows inserting records (no update or delete or anything else). Im trying to be as redundant as possible with access restrictions (on top of code to try and prevent sql injection, if someone were to somehow get something through, I dont want the database itself to allow it).
So bottom line question, How do I create a user in SQL server that has restricted access to only x table in y database and can only read/insert records, and nothing else?
create the user, don't give any roles like db_datareader or db_datawriter
then GRANT INSERT ON YourTable TO SomeUser
if you want insert and select
GRANT INSERT, SELECT ON YourTable TO SomeUser
(1) To give a user with limited access to one Table only
GRANT SELECT ON [schemaName].[tableName] to [username]
Go
(2) To grant INSERT Permission.
GRANT INSERT ON [schemaName].[tableName] TO [username]
Syntax for granting access to a single table:
GRANT access_type ON table_name TO [user name]
Syntax for revoking access for a single table:
REVOKE access_type ON table_name FROM [user name]
where access_type can be SELECT, INSERT, DELETE...
Grant select on dbname.dbo.tablename to username
it giving this error :
Cannot find the object 'APP_TBL_Log', because it does not exist or you do not have permission.
I am logged on as "sa"

Create multiple views inside a schema - SQL Server

How can I create multiple views inside the CREATE SCHEMA statement?
I want to create a SCHEMA, and create two views inside it in the same statement, so all those statements work as a one unit? Succeed or fail together!
From MSDN: http://msdn.microsoft.com/en-us/library/ms189462.aspx
"CREATE SCHEMA can create a schema, the tables and views it contains,
and GRANT, REVOKE, or DENY permissions on any securable in a single
statement. CREATE SCHEMA transactions are atomic. If any error occurs
during the execution of a CREATE SCHEMA statement, none of the
specified securables are created and no permissions are granted."
,
How can I do this? I tried this:
CREATE SCHEMA [MYSCHEMA] AUTHORIZATION [dbo]
CREATE VIEW [VIEW1]
AS
SELECT [ID]
,[NAME]
FROM [dbo].[TABLE1]
/* Here is the Problem */
GO
CREATE VIEW [VIEW2]
AS
SELECT [ID]
,[NAME]
FROM [dbo].[TABLE2]
GO
If I include a GO statement just after first view creation, then script runs but second view VIEW2 is created under the dbo schema, not under MYSCHEMA, and doesn't run as a single unit either.
If I remove the GO after the first view, then it gives an error saying
CREATE VIEW must be the first statement of a batch
for the second CREATE VIEW statement.
How do I solve this and create both views as a part of CREATE SCHEMA statement?
CREATE SCHEMA [MYSCHEMA] AUTHORIZATION [dbo]
CREATE VIEW [VIEW1] AS SELECT [ID], [NAME] FROM [dbo].[TABLE1]
CREATE VIEW [VIEW2] AS SELECT [ID], [NAME] FROM [dbo].[TABLE2]
GO

Tables created by default in user schema

In Sql Server 2008, when I create a table without schema prefix:
create table mytable ( id int identify )
it usually ends up in the schema dbo, with name dbo.mytable.
However, on one of our servers, the tabel ends up belonging to me:
andomar.mytable
Which configuration difference could explain this?
It depends what your default schema is within that database. Even in SQL Server 2005, if your default schema in that one database is andomar, then any tables created without an explicit schema will end up there.
Check the user properties in that database (not the login properties) and see what the default schema is.
If you don't define schema in which you create table it will always use default one.
you can create it like this:
USE DataBaseName -- define database to use
GO
BEGIN TRAN - if you will have any error everything will roll back
CREATE TABLE testovi.razine - schema name is "testovi" and tablename is "razine"
(
id INT NOT NULL IDENTITY(1,1),
razina NVARCHAR(50) NULL,
razinaENG NVARCHAR(50) NULL,
kreirao UNIQUEIDENTIFIER NULL,
VrijemeKreiranja DATETIME NULL
)
ON [PRIMARY]
GO
When you create table always set constraint and index on column most used for transaction
ALTER TABLE testovi.razine ADD CONSTRAINT
PK_mat_razine PRIMARY KEY CLUSTERED
(id) WITH(IGNORE_DUP_KEY=OFF, --check duplicate and don't ignore if try to insert one
STATISTICS_NORECOMPUTE=OFF, -- important for statistic update and query optimization
ALLOW_PAGE_LOCKS=ON) -* I believe that this is default, but always put it to on if not
ON [PRIMARY]
GO
if ##error<>0
BEGIN
ROLBACK TRAN
END
ELSE
BEGIN
COMMIT TRAN --if everything passed o.k. table will be created
END
If you want to set default schema you have to know that it is user based default so you can set it with code:
USE espabiz -- database;
ALTER USER YourUserName WITH DERAULT_SCHEMA = SchemaName; -- SchemaName is default schema for defined user
Ping if you need additional help or mark answer it you find it usable :)

Resources