Avoid alter and drop command on a Table and SP in SQL Server - sql

I have a table and a SP in SQL Server. I want to add Permissions on a table and SP that no one can change the Structure of table and Logic of SP. Is there any way to specify such type of Permissions. Any Trigger which avoids drop and alter commands, or any other way to do this.
Thanks in Advance.

You need to create and use a separate user that has only privileges that you explicitly allow it to (eg GRANT SELECT from table or GRANT EXECUTE on your stored procedure).
Rather than looking at it as disallowing certain actions you should consider what actions are allowed (see Principle of Least Privilege).

It is highly recommended that you manage the permissions on the objects. However, if you have no control over the permissions, consider setting up a database DDL trigger to at least log the events.
create table AuditTable
(
event_type varchar(max) not null
, tsql_command varchar(max) not null
, modified_by varchar(128) not null default (current_user)
, modified_time datetime not null default (getdate())
)
go
create trigger log_database_level_event
on database
for ddl_database_level_events
as
insert AuditTable
(
event_type
, tsql_command
)
values
(
eventdata().value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(max)')
, eventdata().value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'varchar(max)')
)
go
create user tester without login
go
execute as user = 'tester'
go
create proc test_proc
as
select ##version
go
alter proc test_proc
as
select 1
go
revert
go
select * from AuditTable
go

Yes, this is possible but not using constraint . Constraint is a bussiness rule kind of validation and here your question about Permission on Objects so now
this is clear that you need to define permission on object for specific user.If you want to
secure your Table and Stored Procedure then please follow this step.
Create one new User/Login with specific Database/Objects permission.
Give grant on your Secure table using - GRANT SELECT ON <TableName> TO <Username>
GIVE grant on your Secure Stored Procedure using - GRANT EXECUTE ON <SP Name> TO <Username>
for further regarding permission please do some search on Google .

Related

Row level policy doesn't work on my table

I have a table which I'm trying to apply a policy on, the setup looks something like this:
create role anonymous nologin;
create schema api;
create schema private;
create table private.mytable(
id serial primary key,
description text default ''
);
create view api.mytable as select * from private.mytable;
insert into api.mytable (description) values ('row 1'), ('row 2');
grant usage on schema api to anonymous;
grant select on api.mytable to anonymous;
alter table private.mytable enable row level security;
create policy mytable_policy on private.mytable
for select
using (null);
When I set the role to anonymous and select all records from mytable:
set role anonymous;
select * from api.mytable;
I excpect no rows to be returned since my expression in the using clause in the policy is null but I get everything.
I tried different postgresql versions (9.5, 9.6, 10.3) but they all have the same behaviour, am I doing something wrong here?
update
https://stackoverflow.com/a/33863371/5315974
RLS won't work with views like that. You can use RLS for views though it is limited.
what you can do is
alter view api.mytable owner to anonymous ;

Track logins sql

I have a job that runs on my server to track the last login on my sql server so I can audit inactive users.
First I enabled track successful logins on the server
I created a table called TRACK_LOGIN and run this daily:
INSERT INTO dbadb.dbo.TRACK_LOGIN (logontime, logon, loginname) EXEC XP_READERRORLOG 0, 1, [LOGIN SUCCEEDED FOR USER]
Now that that information is in the TRACK_LOGIN table I query DISTINCT out of that table and put it in another table with this query:
SELECT DISTINCT SUBSTRING(LOGINNAME,PATINDEX('%''%',LOGINNAME)+1,PATINDEX('%.%',LOGINNAME)-PATINDEX('%''%',LOGINNAME))FROM TRACK_LOGIN
I would also like to query the column logontime along with the distinct login so I have a list daily of who logs in and what time they login?
Please help modify the select statement above to include distinct logins along with their last logontime.
This is intended on allowing me to look back at my users last login and eliminate those on the server that are not used.
I understand that you have already put some real effort into make this work, but I would still suggest to go with a different approach that yields a much cleaner result:
Logon triggers
This will allow you to insert the right type of data into your table and will not force you to parse back log entries.
This example here shows a different use case, but I think you will have no issue to port it to your own problem.
CREATE TRIGGER MyLogonTrigger ON ALL SERVER FOR LOGON
AS
BEGIN
IF SUSER_SNAME() <> 'sa'
INSERT INTO Test.dbo.LogonAudit (UserName, LogonDate, spid)
VALUES (SUSER_SNAME(), GETDATE(), ##SPID);
END;
GO
ENABLE TRIGGER MyLogonTrigger ON ALL SERVER;
Ok to track logins I did this, I abounded the first method and implemented this:
First I created a table called logonaudit:
CREATE TABLE LogonAudit
(
AuditID INT NOT NULL CONSTRAINT PK_LogonAudit_AuditID
PRIMARY KEY CLUSTERED IDENTITY(1,1)
, UserName NVARCHAR(255)
, LogonDate DATETIME
, spid INT NOT NULL
);
I then had to grant insert on that table:
GRANT INSERT ON dbadb.dbo.LogonAudit TO public;
I created another table called auditloginresults:
create table auditLoginResults
(
AuditID INT,
Username NVARCHAR(255),
LogonDate DATETIME,
SPID INT
);
I then created a trigger to log all logins and times to the first table LogonAudit. I had to create a logon called login_audit and allow it to insert into my tables. I then had to use the origional_login() to log the users login, if you dont do this it will block all logins that are not sa
CREATE TRIGGER MyLogonTrigger
ON ALL SERVER WITH EXECUTE AS 'login_audit'
FOR LOGON
AS
BEGIN
INSERT INTO DBADb.dbo.LogonAudit (UserName, LogonDate, spid)
VALUES (ORIGINAL_LOGIN(), GETDATE(), ##SPID);
END;
Now I created a job (you will need to create a job to run at a specific time with this code, This is not the code for the job just the code you would run in your job) to query the first table LogonAudit and put the results into the auditloginResults table, after that step I cleaned out the first table LogonAudit by running another step to delete data in the first table. Im not going to post the job to keep the threat clean but here is what is run in the job
The create job step 1--------------------------------------------------------
INSERT INTO DBADb.dbo.auditLoginResults
SELECT I.*
FROM DBADb.[dbo].[LogonAudit] AS I
INNER JOIN
(SELECT UserName, MAX([logondate]) AS MaxDate
FROM DBADb.[dbo].[LogonAudit]
GROUP BY UserName
) AS M ON I.logondate = M.MaxDate
AND I.UserName = M.UserName
`
-----NOW create job to purge the logonaudit table step 2
DELETE FROM dbadb.dbo.auditLoginResults;
-----now create a stored procedure to execute this will query the auditloginreaults and provide you the last login of everyone that has ever logged into the database
SELECT I.*
FROM DBADb.[dbo].[auditLoginResults] AS I
INNER JOIN
(SELECT UserName, MAX([logondate]) AS MaxDate
FROM DBADb.[dbo].[ auditLoginResults]
GROUP BY UserName
) AS M ON I.logondate = M.MaxDate
AND I.UserName = M.UserName

can I give SQL Server database name with hyphen like abc-123?

I created a sql server database with name of abc-123, in that I created a table Emp, when I run likeselect * from abc-123.emp; I am getting the results.
But when I am trying to grant some privilege to the user I unable to do that, getting syntax error near hyphen .
will any one help me?
Make sure you are escaping the names with [] (T-SQL) or "" (ANSI SQL). You are using non-standard naming.
-- Sample select
SELECT * FROM [abc-123].[dbo].[emp];
SELECT * FROM "abc-123"."dbo"."emp";
1 - Can you send me an example of the grant TSQL? If you are doing the action from SSMS, right click and script the code.
2 - Here is the link to the GRANT TSQL command. I do not see any syntax like you are trying.
http://technet.microsoft.com/en-us/library/ms188371.aspx
TO 'drupal'#'localhost' IDENTIFIED BY 'Drup#l';
First, it should be [drupal#localhost]. Second, I never seen the IDENTIFIED BY clause. Where are you getting that information from?
3 - Here is a quick TSQL script that creates a badly named database and user. If possible, change the name of the database and user.
Also, if you are granting permissions at the table level other than db_owner (very granular and a-lot of maintenance), then create an user defined database role. Add securables to the role and add your user to the role.
http://technet.microsoft.com/en-us/library/ms187936.aspx
Sample code.
-- Create new database
create database [abc-123]
go
-- Use new database
use [abc-123];
go
-- Create table from sample data
select
[BusinessEntityID]
,[PersonType]
,[NameStyle]
,[Title]
,[FirstName]
,[MiddleName]
,[LastName]
,[Suffix]
,[EmailPromotion]
, cast([AdditionalContactInfo] as varchar(max))
as [AdditionalContactInfoTxt]
, cast([Demographics] as varchar(max))
as [DemographicsTxt]
,[rowguid]
,[ModifiedDate]
into
[abc-123].[dbo].[emp]
from
AdventureWorks2012.Person.Person;
-- Create a login
CREATE LOGIN [drupal#localhost] WITH PASSWORD=N'Ja08n13$', DEFAULT_DATABASE=[abc-123]
GO
-- Create a user
CREATE USER [drupal#localhost] FOR LOGIN [drupal#localhost] WITH DEFAULT_SCHEMA=[dbo]
GO
-- Add to database owner role
EXEC sp_addrolemember 'db_owner', [drupal#localhost]
GO
Output with user in db_owner group.
Use Back Quote for the DB name
select * from `abc-123`.emp;
or, select the existing database with a USE statement and run the query.
USE `abc-123`;
select * from emp;
Use [] round the database name:
SELECT * FROM [abc-123].[dbo].emp;
OR
SELECT * FROM [abc-123].dbo.emp;
if you are using databasename with table name then suppose to specify the schema name also.select * from [abc-123].dbo.emp

Is a stored procedure with EXECUTE AS OWNER a valid replacement for a view selecting from third-schema tables?

A database user A should only have access to specific data.
This data is currently provided by a view B.VIEW1 selecting from tables owned by schema B and C.
CREATE VIEW [B].[VIEW1] AS SELECT * FROM [B].[VIEW2], [C].[VIEW1]
Since C.VIEW1 is not owned by B, Ownership Chains apply.
That means although A is granted SELECT permission ON B.VIEW1, it can't select from.
SELECT permission denied on object 'C.VIEW1', database '...', schema '...'.
Is a stored procedure B.PROC1 with EXECUTE AS OWNER Clause a valid replacement for B.VIEW1 in terms of security?
CREATE PROC [B.PROC1] WITH EXECUTE AS OWNER AS BEGIN SELECT * FROM [B.VIEW2], [C].[VIEW1] END
Or are there any negative side-effects which will possibly lead to any security problems?
In terms of security, this seems to be a good way to prevent access to underlying tables.
A negative side-effect is that you can't filter the resultset generated by the stored procedure by a WHERE, GROUP BY clause or similar.
But this is not that tragic if defining static constraints in an underlying view
or defining "dynamic" constraints via stored proc's input parameters.
1) Static constraints in underlying view
CREATE VIEW [B].[VIEW3] AS SELECT * FROM [B].[VIEW2], [C].[VIEW1] WHERE [X]='Something' AND [Y] = GETDATE()
CREATE PROC [B].[PROC1] WITH EXECUTE AS OWNER AS BEGIN SELECT * FROM [B].[VIEW3] END
2) Dynamic constraints via input parameters
CREATE PROC [B].[PROC1] (#X varchar(30), #Y DATETIME) WITH EXECUTE AS OWNER AS BEGIN SELECT * FROM [B].[VIEW2], [C].[VIEW1] WHERE [X]=#X AND [Y]=#Y AND

Dynamic use of T-SQL schemas

Is there a way which I can omit the schema of objects used in a stored procedure and these objects aren't bound to the schema of stored procedure but the schema of logged used in manner that the same stored procedure produce different results for user in different schemas?
For better understanding what I'm trying to do, below I'll try to explain better.
Supposing the following database:
CREATE TABLE [dbo].[SampleTable01] (...)
CREATE TABLE [dbo].[SampleTable02] (...)
CREATE TABLE [dbo].[SampleTable03] (...)
CREATE TABLE [dbo].[SampleTable04] (...)
In this database, the number following the name of the table represents the owner of the table (it is a legacy system and I can't change that).
To integrate that into .net Entity Framework, I come with a solution of creating synonyms in different schemas, so changing the connections string I can change the objects used without changing my database context or my programming logic.
Like this.
CREATE SCHEMA [s01]
CREATE SYNONYM [s01].[SampleTable] FOR [dbo].[SampleTable01]
...
CREATE SCHEMA [s04]
CREATE SYNONYM [s04].[SampleTable] FOR [dbo].[SampleTable04]
This solutions is working pretty well, but I need to duplicate all the stored procedures used, because the stored procedures are bound to a specific object.
When I create the following stored procedure:
CREATE PROCEDURE [dbo].[usp_SampleProc] AS
SELECT * FROM [SampleTable]
The stored procedure will produce an error, because the [SampleTable] doesn't exists in the schema [dbo].
What I'm doing is duplicating the stored procedures to match the schema from the logged user.
So I'm doing this:
CREATE PROCEDURE [s01].[usp_SampleProc] AS
SELECT * FROM [s01].[SampleTable]
...
CREATE PROCEDURE [s04].[usp_SampleProc] AS
SELECT * FROM [s04].[SampleTable]
A user in [s01] schema will get values from [s01].[SampleTable] and a user in [s04] schema will get values from [s04].[SampleTable], when executing [usp_SampleProc] without specifying the schema, which is my expected result.
So far so good, this isn't productive in my real scenario. I have thousand of tables, hundreds of procedures and dozen of schemas (I know this is ugly, but I integrating a legacy system with .net, and so far, it is the best solution which I come).
So, the question again:
Is there a way which I can omit the schema of objects used in the stored procedure and these objects aren't bound to the schema of the stored procedure but the schema of the logged in user in manner that the same stored procedure produces different results for users in different schemas?
These are the two ways I know to do what I'm trying to do.
Both ways will be transparent to developers, so they won't need to understand the complexity of the solution.
Below I created a sample which everyone can use:
Original legacy database creation: remains unchanged, since the legacy applications still using the database.
CREATE TABLE [dbo].[SampleTable01] (
value varchar(100)
)
INSERT INTO [dbo].[SampleTable01] VALUES ('[dbo].[SampleTable01]')
CREATE TABLE [dbo].[SampleTable02] (
value varchar(100)
)
INSERT INTO [dbo].[SampleTable02] VALUES ('[dbo].[SampleTable02]')
CREATE TABLE [dbo].[SampleTable03] (
value varchar(100)
)
INSERT INTO [dbo].[SampleTable03] VALUES ('[dbo].[SampleTable03]')
CREATE TABLE [dbo].[SampleTable04] (
value varchar(100)
)
INSERT INTO [dbo].[SampleTable04] VALUES ('[dbo].[SampleTable04]')
GO
User and schema separation used by my application: those are a lot of duplicated code, but will be generated by the application setup.
CREATE SCHEMA [S01]
GO
CREATE SCHEMA [S02]
GO
CREATE SCHEMA [S03]
GO
CREATE SCHEMA [S04]
GO
CREATE USER USER_S01 WITHOUT LOGIN WITH DEFAULT_SCHEMA = S01
GO
CREATE USER USER_S02 WITHOUT LOGIN WITH DEFAULT_SCHEMA = S02
GO
CREATE USER USER_S03 WITHOUT LOGIN WITH DEFAULT_SCHEMA = S03
GO
CREATE USER USER_S04 WITHOUT LOGIN WITH DEFAULT_SCHEMA = S04
GO
CREATE SYNONYM [S01].[SampleTable] FOR [dbo].[SampleTable01]
CREATE SYNONYM [S02].[SampleTable] FOR [dbo].[SampleTable02]
CREATE SYNONYM [S03].[SampleTable] FOR [dbo].[SampleTable03]
CREATE SYNONYM [S04].[SampleTable] FOR [dbo].[SampleTable04]
GO
GRANT DELETE ON SCHEMA::[S01] TO [USER_S01]
GRANT EXECUTE ON SCHEMA::[S01] TO [USER_S01]
GRANT INSERT ON SCHEMA::[S01] TO [USER_S01]
GRANT REFERENCES ON SCHEMA::[S01] TO [USER_S01]
GRANT SELECT ON SCHEMA::[S01] TO [USER_S01]
GRANT UPDATE ON SCHEMA::[S01] TO [USER_S01]
GRANT EXECUTE ON SCHEMA::[S01] TO [USER_S01]
GO
GRANT DELETE ON SCHEMA::[S02] TO [USER_S02]
GRANT EXECUTE ON SCHEMA::[S02] TO [USER_S02]
GRANT INSERT ON SCHEMA::[S02] TO [USER_S02]
GRANT REFERENCES ON SCHEMA::[S02] TO [USER_S02]
GRANT SELECT ON SCHEMA::[S02] TO [USER_S02]
GRANT UPDATE ON SCHEMA::[S02] TO [USER_S02]
GRANT EXECUTE ON SCHEMA::[S02] TO [USER_S02]
GO
GRANT DELETE ON SCHEMA::[S03] TO [USER_S03]
GRANT EXECUTE ON SCHEMA::[S03] TO [USER_S03]
GRANT INSERT ON SCHEMA::[S03] TO [USER_S03]
GRANT REFERENCES ON SCHEMA::[S03] TO [USER_S03]
GRANT SELECT ON SCHEMA::[S03] TO [USER_S03]
GRANT UPDATE ON SCHEMA::[S03] TO [USER_S03]
GRANT EXECUTE ON SCHEMA::[S03] TO [USER_S03]
GO
GRANT DELETE ON SCHEMA::[S04] TO [USER_S04]
GRANT EXECUTE ON SCHEMA::[S04] TO [USER_S04]
GRANT INSERT ON SCHEMA::[S04] TO [USER_S04]
GRANT REFERENCES ON SCHEMA::[S04] TO [USER_S04]
GRANT SELECT ON SCHEMA::[S04] TO [USER_S04]
GRANT UPDATE ON SCHEMA::[S04] TO [USER_S04]
GRANT EXECUTE ON SCHEMA::[S04] TO [USER_S04]
GO
Solution 1 (my choice): consists in using same procedure name in different schemas. One procedure for each user (which have its own schemas).
CREATE PROCEDURE [S01].[usp_SampleProc]
AS
SELECT * FROM [SampleTable]
GO
CREATE PROCEDURE [S02].[usp_SampleProc]
AS
SELECT * FROM [SampleTable]
GO
CREATE PROCEDURE [S03].[usp_SampleProc]
AS
SELECT * FROM [SampleTable]
GO
CREATE PROCEDURE [S04].[usp_SampleProc]
AS
SELECT * FROM [SampleTable]
GO
Solution 2: uses dynamic created, since in time of execution the table references will be resolved to synonym inside user's schema.
GRANT EXECUTE ON SCHEMA::[dbo] TO [USER_S01]
GRANT EXECUTE ON SCHEMA::[dbo] TO [USER_S02]
GRANT EXECUTE ON SCHEMA::[dbo] TO [USER_S03]
GRANT EXECUTE ON SCHEMA::[dbo] TO [USER_S04]
GO
CREATE PROCEDURE [dbo].[usp_SampleProc]
AS
exec(N'SELECT * FROM [SampleTable]')
GO
Execution: Exactly the same for both solutions.
EXECUTE AS USER = 'USER_S01'
EXEC [usp_SampleProc]
REVERT;
EXECUTE AS USER = 'USER_S02'
EXEC [usp_SampleProc]
REVERT;
EXECUTE AS USER = 'USER_S03'
EXEC [usp_SampleProc]
REVERT;
EXECUTE AS USER = 'USER_S04'
EXEC [usp_SampleProc]
REVERT;
Reason of choice: I wan't the developer to simplify the creation and test of procedures. And to solve bugs that occurred in production. In the manner I decided to use, the procedure will be exact the same for all schemas. So, will be easy to test a problem that occurs in that schema just by logging with that and solving that for all schemas.
The disadvantage of the solution, is that I can't put schemas in the tables inside procedures. So it will be a minor performance loss.
In some situations you don't really have to choice to rely on Dynamic SQL.
Instead of creating more and more objects, try to dynamically call your table.
It could look something like this :
CREATE PROCEDURE [dbo].[usp_SampleProc]
AS
BEGIN
DECLARE #SQL varchar(MAX)
set #SQL = 'SELECT col1, col2, ... FROM [SampleTable'+ SUSER_SNAME() +']'
exec(#SQL)
END
You might have to transform the username to fit your naming convention.
Also, you should not use "select *" in this context, since it's not compiled you could end up with some surprise if there is any modification in the table structure.
If I were you, I'd get very familiar with SqlCmd.exe (command line utility) and using variables.
I'm gonna try to put the code for 5 files below.
I will place a tag before the code (the contents of the file) with the name of the file like this:
|||||||||||||||||||MyFileName.txt|||||||||||||||||||
You will not put this in the contents of the file, but everything below this "marker" line will be the contents of the file. You need name the files exactly as I have them. And you will put all files in the same directory.
After you have all the files created, you need to edit the (one) .bat file and update a few pieces of information. (Mainly, where your sqlcmd.exe exists on your machine, and the name of your sqlserver/instance where you have rights to create a database using integrated authentication.
Here are the common locations:
%ProgramFiles%\Microsoft SQL Server\100\Tools\Binn\sqlcmd.exe
%ProgramFiles%\Microsoft SQL Server\90\Tools\Binn\sqlcmd.exe
%ProgramFiles% (x86)\Microsoft SQL Server\90\Tools\Binn\sqlcmd.exe
Let's go!
|||||||||||||||||||MasterRunMeBatFile.bat|||||||||||||||||||
REM Find the location of your SQLCMD.EXE
set __sqlCmdLocation=c:\Program Files (x86)\Microsoft SQL Server\90\Tools\binn\SQLCMD.EXE
REM Set your servername/instancename here
set __sqlServerNameAndInstance=MyServerName\MyInstanceName
REM Create the database
"%__sqlCmdLocation%" -i .\DatabaseCreate.sql -b -S "%__sqlServerNameAndInstance%" -E -o ".\ZZZ_DatabaseCreateOutput.txt" -v DBName="MyFirstCommandLineDB"
REM Create the multiple Schemas
"%__sqlCmdLocation%" -i .\SchemasCreate.sql -b -S "%__sqlServerNameAndInstance%" -E -o ".\ZZZ_SchemasCreate_01.txt" -v DBName="MyFirstCommandLineDB" SchemaName="Schema01"
"%__sqlCmdLocation%" -i .\SchemasCreate.sql -b -S "%__sqlServerNameAndInstance%" -E -o ".\ZZZ_SchemasCreate_02.txt" -v DBName="MyFirstCommandLineDB" SchemaName="Schema02"
"%__sqlCmdLocation%" -i .\SchemasCreate.sql -b -S "%__sqlServerNameAndInstance%" -E -o ".\ZZZ_SchemasCreate_03.txt" -v DBName="MyFirstCommandLineDB" SchemaName="Schema03"
REM Create the DDL (tables)
"%__sqlCmdLocation%" -i .\OrganizationDDL.sql -b -S "%__sqlServerNameAndInstance%" -E -o ".\ZZZ_OrganizationDDL_01.txt" -v DBName="MyFirstCommandLineDB" MySchemaVariable="Schema01" MyUniqueNumber="01" DBUSERNAME="public"
"%__sqlCmdLocation%" -i .\OrganizationDDL.sql -b -S "%__sqlServerNameAndInstance%" -E -o ".\ZZZ_OrganizationDDL_02.txt" -v DBName="MyFirstCommandLineDB" MySchemaVariable="Schema02" MyUniqueNumber="02" DBUSERNAME="public"
"%__sqlCmdLocation%" -i .\OrganizationDDL.sql -b -S "%__sqlServerNameAndInstance%" -E -o ".\ZZZ_OrganizationDDL_03.txt" -v DBName="MyFirstCommandLineDB" MySchemaVariable="Schema03" MyUniqueNumber="03" DBUSERNAME="public"
REM Create some stored procedures against the multiple schemas
"%__sqlCmdLocation%" -i .\TSQL_USP_UDF_TRG.sql -b -S "%__sqlServerNameAndInstance%" -E -o ".\ZZZ_TSQL_USP_UDF_TRG_01.txt" -v DBName="MyFirstCommandLineDB" MySchemaVariable="Schema01" MyUniqueNumber="01" DBUSERNAME="public"
"%__sqlCmdLocation%" -i .\TSQL_USP_UDF_TRG.sql -b -S "%__sqlServerNameAndInstance%" -E -o ".\ZZZ_TSQL_USP_UDF_TRG_02.txt" -v DBName="MyFirstCommandLineDB" MySchemaVariable="Schema02" MyUniqueNumber="02" DBUSERNAME="public"
"%__sqlCmdLocation%" -i .\TSQL_USP_UDF_TRG.sql -b -S "%__sqlServerNameAndInstance%" -E -o ".\ZZZ_TSQL_USP_UDF_TRG_03.txt" -v DBName="MyFirstCommandLineDB" MySchemaVariable="Schema03" MyUniqueNumber="03" DBUSERNAME="public"
set __sqlCmdLocation=
set __sqlServerNameAndInstance=
|||||||||||||||||||DatabaseCreate.sql|||||||||||||||||||
Use [master];
GO
if exists (select * from sysdatabases where name='$(DBName)')
BEGIN
DROP DATABASE [$(DBName)];
END
GO
Create Database $(DBName)
GO
|||||||||||||||||||SchemasCreate.sql|||||||||||||||||||
Use [$(DBName)]
GO
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = '$(SchemaName)')
BEGIN
-- The schema must be run in its own batch!
EXEC( 'CREATE SCHEMA $(SchemaName)' );
END
IF EXISTS (SELECT 1 FROM sys.schemas WHERE name = '$(SchemaName)')
BEGIN
PRINT 'SCHEMA $(SchemaName) Exists!' ;
END
ELSE
BEGIN
PRINT 'Oh My : SCHEMA $(SchemaName) does not exist.' ;
END
GO
|||||||||||||||||||OrganizationDDL.sql|||||||||||||||||||
Use [$(DBName)]
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[$(MySchemaVariable)].[Employee$(MyUniqueNumber)]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
DROP TABLE [$(MySchemaVariable)].[Employee$(MyUniqueNumber)]
END
GO
CREATE TABLE [$(MySchemaVariable)].[Employee$(MyUniqueNumber)]
(
EmployeeUUID [UNIQUEIDENTIFIER] NOT NULL DEFAULT NEWSEQUENTIALID() ,
SSN varchar(11) ,
LastName varchar(24) ,
FirstName varchar(24) ,
DateOfBirth smalldatetime
)
ALTER TABLE [$(MySchemaVariable)].[Employee$(MyUniqueNumber)] ADD CONSTRAINT PK_Employee$(MyUniqueNumber)
PRIMARY KEY NONCLUSTERED (EmployeeUUID)
ALTER TABLE [$(MySchemaVariable)].[Employee$(MyUniqueNumber)] ADD CONSTRAINT CK_Employee$(MyUniqueNumber)_SSN_Unique
UNIQUE (SSN)
GRANT SELECT , INSERT, UPDATE, DELETE ON [$(MySchemaVariable)].[Employee$(MyUniqueNumber)] TO $(DBUSERNAME)
GO
PRINT 'Select * from [$(MySchemaVariable)].[Employee$(MyUniqueNumber)]'
Select * from [$(MySchemaVariable)].[Employee$(MyUniqueNumber)]
|||||||||||||||||||TSQL_USP_UDF_TRG.sql|||||||||||||||||||
Use [$(DBName)]
GO
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[$(MySchemaVariable)].[uspEmployeeGetAll]') AND type in (N'P', N'PC'))
DROP PROCEDURE [$(MySchemaVariable)].[uspEmployeeGetAll]
GO
CREATE PROCEDURE [$(MySchemaVariable)].[uspEmployeeGetAll]
AS
SET NOCOUNT ON
SELECT
EmployeeUUID ,
SSN ,
LastName ,
FirstName ,
DateOfBirth
FROM
[$(MySchemaVariable)].[Employee$(MyUniqueNumber)] e
SET NOCOUNT OFF
GO
GRANT EXECUTE ON $(MySchemaVariable).[uspEmployeeGetAll] TO $(DBUSERNAME)
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[$(MySchemaVariable)].[uspEmployeeGetAll]') AND type in (N'P', N'PC'))
PRINT '[$(MySchemaVariable)].[uspEmployeeGetAll] has been created!'
GO
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[$(MySchemaVariable)].[uspEmployeeGetByUUID]') AND type in (N'P', N'PC'))
DROP PROCEDURE [$(MySchemaVariable)].[uspEmployeeGetByUUID]
GO
/*
declare #EmployeeUUID uniqueidentifier
select #EmployeeUUID = NEWID()
exec [$(MySchemaVariable)].[uspEmployeeGetByUUID] #EmployeeUUID
*/
CREATE PROCEDURE [$(MySchemaVariable)].[uspEmployeeGetByUUID]
#EmployeeUUID uniqueidentifier
AS
SET NOCOUNT ON
SELECT
EmployeeUUID ,
SSN ,
LastName ,
FirstName ,
DateOfBirth
FROM
[$(MySchemaVariable)].[Employee$(MyUniqueNumber)] e
WHERE
e.EmployeeUUID = #EmployeeUUID
SET NOCOUNT OFF
GO
GRANT EXECUTE ON $(MySchemaVariable).[uspEmployeeGetByUUID] TO $(DBUSERNAME)
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[$(MySchemaVariable)].[uspEmployeeGetByUUID]') AND type in (N'P', N'PC'))
PRINT '[$(MySchemaVariable)].[uspEmployeeGetByUUID] has been created!'
GO
=============== END FILES and FILE CONTENTS======================
Ok.
At the end of this exercise.... you should have something like this.
Three Tables: (inside the same database)
[Schema01].[Employee01] ,
[Schema02].[Employee02] ,
[Schema03].[Employee03]
And stored procedure similar to the below one.
(Note, the schema name of the stored procedure AND the table it pulls from.)
ALTER PROCEDURE [Schema01].[uspEmployeeGetAll]
AS
SET NOCOUNT ON
SELECT
EmployeeUUID ,
SSN ,
LastName ,
FirstName ,
DateOfBirth
FROM
[Schema01].[Employee01] e
IMHO.
Using sqlcmd.exe with variables is the BEST way to ensure perfect repeatability amongst different environments.
Thoughts from another person:
http://blogs.msdn.com/tomholl/archive/2008/04/29/thoughts-on-being-a-solution-architect.aspx
Minimize the amount of code the developers need to write
Developers are paid to write code, and they are generally excellent at it. However once a developer is assigned a swag of requirements or stories they need to get down to work on those specific requirements, and it's not easy for them to keep up with what everyone else is doing in any level of detail.
This can include discovering synergies between different requirements or opportunities for macro-level code reuse and refactoring. A big part of the architect's job is to pick up on these opportunities as they arise and ensure that developers aren't reinventing the wheel in their own worlds.
Ideally this should result in patterns, components and frameworks that allow the developers to get their requirements done with less code, by concentrating on those parts that are unique.
EXTRA:
http://www.yaldex.com/sql_server_tutorial_3/ch06lev1sec5.html
That is how you develop the scripts.
But don't forget to comment out the variable settings (inside the .sql files) because the variables inside the contents of the files take precedence over the variables sent-in via the command line.
Please vote on this issue!
http://connect.microsoft.com/sqlserver/feedback/details/382007/in-sqlcmd