Showing posts with label sql query. Show all posts
Showing posts with label sql query. Show all posts

Tuesday, October 27, 2020

SQL Server from container - Getting started

Background

Historically not only installing SQL servers, but most of the software had difficulties. The container technology such as Docker magically solved this by packaging software as installed VM like images called docker images. It is easy as downloading the image and start using the software. 
There are a lot of ways to get it working for us if we want to get SQL instance up and running using containers.

Why SQL Server from a container?

Let us see the benefits of running from containers

Running with minimal efforts

No need to spend time installing and configuring. Below single command will get us started provided the Docker is preinstalled. 
This is really useful if we just need to test something out.

Tuesday, February 3, 2015

Dynamic SQL View using CONTEX_INFO

SQL Server supports creating views and I hope all knows what is a view. According to wiki its just a result set of query on data. Users can access it just like another table but it doesn't contain its own data like table. If we google for different between view and table we can get ton of links.

Below is a normal view definition.

CREATE VIEW CreditCards 
AS 
  (SELECT * 
   FROM   adventureworks2012.sales.creditcard 
   WHERE  cardtype = 'Vista')

In our day to day life most of the views we are creating has a static 'where' clause. Here we are
going to see how that part can be dynamic.

Create view by getting values from CONTEXT_INFO

CONTEXT_INFO gives us option to store values in the context of a session. It can be more compared to a static variable in programming. Here we are going to see how a view can be created which is affected by CONTEXT_INFO value.

Below is a sample view which is consuming the CONTEXT_INFO

CREATE VIEW creditcards 
AS 
  (SELECT * 
   FROM   adventureworks2012.sales.creditcard 
   WHERE  CardType = CONVERT(VARCHAR(25), Context_info())) 

If somebody call this view without setting the CONTEXT_INFO it will return the view which matches the where condition(CardType) with NULL. Else it returns proper data set.

Setting the CONTEXT_INFO

If we have already a view defined we can set the CONTEXT_INFO to our own values and select the view. The view will return proper values.

DECLARE @contextInfo VARBINARY(128) 

SET @contextInfo = CONVERT(VARBINARY(128), 'Vista') 
SET context_info @contextInfo 

SELECT * 
FROM   adventureworks2012.dbo.creditcards

The above query will return all the Sales.CreditCard with CardType='Vista'

One advantage is we can set this CONTEXT_INFO from code. More precisely from central data access before executing any other query. This way we can control centrally, what the tracks are getting from this view if they go via common data access.

http://jasondentler.com/blog/2010/01/exploiting-context_info-for-fun-and-audit/

Tuesday, March 25, 2014

If statement in SQLCMD

SQLCMD is a nice utility to automate the SQL scripts execution.I became the fan of it years ago when I first used it for automating database creation and version upgrade of databases. The past sql automations using sqlcmd.exe were relatively simple. Most of those were using tokens and those tokens will be replaced with actual values when the execution starts. The values for tokens will be supplied by initiating programs and those programs may be of .bat, .vbs or .ps1 files at the most it will be invoked from the installers.

Recently we came to a situation where a branching is required in SQLCMD scripting. Basically we need to change the value of the token at runtime based no a database SELECT query. At that moment I realized that sqlcmd doesn't have branching statements. Team's initial decision to mitigate it was to call the database from the initiator programs.But those will make the .bat files really heavy or may need to write another PowerShell script or exe to do the job and get the value for sqlcmd token.

But a tight google exercise unveiled the below link which explains how to imitate the branching in sqlcmd. Its nothing but creating dynamic .sql file based on query result and executing the same from its creator sql file. I don't think I need to replicate the details again. So just open the link and have fun.


Monday, September 9, 2013

SQL Query to find number of table rows stored in different partitions

Sometime if we are analysing production applications, we may need to check why some queries are taking more time. There are some case where all the data may be going to same database file which is against the partition strategy of the database. Below is the query which gets the details about how the table rows are distributed in partitions.


DECLARE @TableName sysname = 'Users';
SELECT p.partition_number, fg.name as FileGroup, p.rows
FROM sys.partitions p
    INNER JOIN sys.allocation_units au
    ON au.container_id = p.hobt_id
    INNER JOIN sys.filegroups fg
    ON fg.data_space_id = au.data_space_id
WHERE p.object_id = OBJECT_ID(@TableName)


We can directly evaluate the partition function as below to know what will be value of partition for a given value.This will also help us to determine which rows went to which partition. But the above is more handy to use.


$Partition.<partition name>(value)

Happy debugging.

Note: The credits for this query goes to my team mate who don't have a blog as of now. May be this will inspire him to start his blog :)

Monday, April 8, 2013

Is my SQL query running inside transaction scope?

Just another tip I got during inspecting a query written for a SSIS package. ie from the same incident which I explained in my last post about SQL. There was some part of SQL stored procedure which is not supposed to run in transaction. Since we don’t have transaction suppression support in SQL Server, the alternative took was as follows.

  • Find out whether the stored procedure is running in transaction.
  •  If so throw error. Since this SSIS package is supposed to be called from multiple places we cannot assume that it will not be called without transaction.

How to check for presence of transaction inside SQL SP

Its simple as checking the return value of XACT_STATE() function anywhere in SQL.The code snippet is given below for reference.
IF XACT_STATE() <> 0
BEGIN
    DECLARE @ProcName sysname = OBJECT_NAME(@@PROCID);
    RAISERROR('Stored procedure "%s" cannot be executed in a transaction.', 16, 1, @ProcName)
    RETURN;
END;

Putting it in a SP.

CREATE PROCEDURE dbo.spWillNotRunInTransaction 
AS
BEGIN
IF XACT_STATE() <> 0
BEGIN
    DECLARE @ProcName sysname = OBJECT_NAME(@@PROCID);
    RAISERROR('Stored procedure "%s" cannot be executed in a transaction.', 16, 1, @ProcName)
    RETURN;
END;
SELECT 'I am Independent...'
END
GO

Real time application

One of the real time use I could see is to simulate the .net model transaction suppression as mentioned below inside any stored procedure.


using (TransactionScope txScope =
           new TransactionScope(TransactionScopeOption.Suppress))
    {
        // Code indluding DB queries
        txScope.Complete();
    }



A link I obtained which explains about the unavailability of transaction suppression in SQL Server and how to tackle the situation by alternatives.
http://blogs.msdn.com/b/sqlprogrammability/archive/2008/08/22/how-to-create-an-autonomous-transaction-in-sql-server-2008.aspx

Monday, April 1, 2013

SQL query to get the SP name inside stored procedure.

Recently I had to scratch a SSIS package which was developed by Microsoft consultant. Got some interesting mechanisms while inspecting his stored procedures. Among those, the most noticed one was the technique to get the name of the stored procedure inside the same SP.If we see from the procedure execution point of view this is the current executing SP.
create PROCEDURE usp_WhatIsMyName
AS
BEGIN
    DECLARE @ProcName sysname = OBJECT_NAME(@@PROCID);
    select @ProcName --Returns usp_WhatIsMyName    
END
GO



This seems more like reflection in .Net where we can program the meta data. You may explore more on SQL meta data programming here.





Monday, February 25, 2013

SQL Server - FileStream content length using len and datalength

Basically there are some differences between len and datalength functions which almost all SQL developers may know. len() returns the no of characters by trimming the right side and datalength() returns the no of bytes used to store the data structure in the table.
I would like to add one more scenario to this comparison which is nothing but finding length of FileStream content. If you are new to SQL FileStream please refer this article. The scenario we were encountering was so simple. We had to list out all the files which are empty. To be more on business side, need to delete all the zero byte files in file stream storage table.
Below is the table def
CREATE TABLE [DocumentContent](
    [DocumentContentID] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
    [FileStreamContent] [varbinary](max) FILESTREAM  NULL,
 CONSTRAINT [PK_DocumentContent] PRIMARY KEY NONCLUSTERED 
(
    [DocumentContentID] ASC
))
The initial query used to determine the list of blank files is
select DocumentContentID 
from DocumentContent 
where len(FileStreamContent) <=1
This works without errors but the time taken to execute is really huge and directly proportional to the no of documents in the table also the size of the documents. Sometimes exceeds 30 seconds and started getting timeouts and eventually deadlocks. So modified as follows.
select DocumentContentID 
from DocumentContent 
where datalength(FileStreamContent) <=1
It rocks. Now the query takes normal time even if the table has many rows.

Tuesday, March 6, 2012

Moving ASP.Net Membership tables to production

Recently we were migrating our development database from local to Azure production db. The database has both application specific tables and aspnet membership tables.As usual the person who moved ignored all the development data by generating the table creation script alone with application specific seed data.

The system uses Azure ACS to have federated authentication from 3 identity providers. Google,Yahoo and our own custom identity provider using claims. The standard providers such as google and yahoo worked perfectly but the custom identity provider didn't. The error message shown was

The 'System.Web.Security.SqlMembershipProvider' requires a database schema compatible with schema version '1'. However, the current database schema is not compatible with this version. You may need to either install a compatible schema with aspnet_regsql.exe (available in the framework installation directory), or upgrade the provider to a newer version.

This clearly says we are missing something in the AspNet membership schema level. Not at all any seed data. But actually the issue is with seed data.ie we need to enable the features in the asp.net membership database. When we enable the features aspnet membership uses a table called aspnet_SchemaVersions to store the settings. This schema is confused with table schema in the error message. If you want to have more details you can try running the below query on a working aspnetdb.mdf.

SELECT feature,
       compatibleschemaversion,
       iscurrentversion
FROM   aspnet_schemaversions 


This is not our focus. Our focus is to get the issue resolved. Its simple we need to register the features into the asp net membership database which is ported to Azure. Open the SSMS and connect to Azure database and run the below queries.

EXEC [dbo].Aspnet_registerschemaversion
  N'Common',
  N'1',
  1,
  1

EXEC [dbo].Aspnet_registerschemaversion
  N'Role Manager',
  N'1',
  1,
  1

EXEC [dbo].Aspnet_registerschemaversion
  N'Membership',
  N'1',
  1,
  1 


If you are getting any error executing this sps make sure you have all the aspnet membership related stored procedures in the database. If not available run the membership related scripts which are available in your machine. You can find the scripts here in the location.

[InstallDrive]:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallCommon.sql

If you don't want to take chance of running the scripts one by one use the tool aspnet_regsql

Wednesday, August 3, 2011

Collation and the temp tables

It’s a hack which I am going to describe in this post for the people who are working in tight delivery schedules. Hope everybody knows what is collation in SQL Server and how it cause issues if we use database objects in different collations in a query. Also note the task involved in changing an existing SQL Server instance to a different collation and how to change collation of system databases such as temp database or any other user database.

We were using SQL_Latin1_General_CP1_CI_AS collation till couple of months back and recently moved to Latin1_General_100_CI_AS_KS_WS collation. We created new database in Latin1_General_100_CI_AS_KS_WS and it worked in all the development machines without any issue .So we changed the testing servers to Latin1_General_100_CI_AS_KS_WS collation and it performed well. After some load testing we had to modify one SP which introduced temp tables. As it is related to load testing we first applied in the test server and it rocked. But when we take the same sp to development machines the a problem raised because we didn’t change the sql server instances of our development machines to Latin1_General_100_CI_AS_KS_WS which is a good time consuming process. That means the temp database is in different collation compared to our project database.

For example consider a simple scenario.We created a Address database in the Latin1_General_100_CI_AS_KS_WS collation where our sql server instance is in SQL_Latin1_General_CP1_CI_AS .We have a Person table (Id,Name) and Address Table (Id,PersonId,Address) which has person id as foreign key and we need to select details of some persons based on a particular person name list.Earlier we had a ‘in’ keyword based implementation and that we changed to temp table based implementation where the temp table is a table which has one column and it will be joined with the Address table to get the details. Ok its time to see some sql.

CREATE TABLE [dbo].[Person](
[Id] [int] NOT NULL,
[Name] [nvarchar](255) NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
)



CREATE TABLE [dbo].[Address](
[Id] [int] NULL,
[PersonId] [int] NULL,
[Address] [nvarchar](max) NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Address] WITH CHECK ADD CONSTRAINT [FK_Address_Person] FOREIGN KEY([PersonId])
REFERENCES [dbo].[Person] ([Id])

Here is the modified query to use the table variables which uses temp db.

IF NOT OBJECT_ID('tempdb..#Selected') IS NULL
DROP TABLE #Selected;
CREATE TABLE #Selected
(
Name nvarchar(255)
);
--Logic to fill the #Selected table
select #Selected.Name,[Address].[Address]
from #Selected join Person
on #Selected.name = Person.Name
join [Address]
on Person.Id =[Address].PersonId;


The error msg was “Cannot resolve the collation conflict between "Latin1_General_100_CI_AS_KS_WS" and "SQL_Latin1_General_CP1_CI_AS" in the equal to operation.”. This means the temp DB is still in SQL_Latin1_General_CP1_CI_AS collation and our DB is in Latin1_General_100_CI_AS_KS_WS collation which doesn’t allow us to do a comparison on strings.So as a hack or quick work around in development environment, we modified the query as follows which specifies the collation on the comparison.
IF NOT OBJECT_ID('tempdb..#Selected') IS NULL
DROP TABLE #Selected;
CREATE TABLE #Selected
(
Name nvarchar(255)
);
--Logic to fill the #Selected table
select #Selected.Name,[Address].[Address]
from #Selected join Person
on #Selected.name collate Latin1_General_100_CI_AS_KS_WS= Person.Name collate Latin1_General_100_CI_AS_KS_WS
join [Address]
on Person.Id =[Address].PersonId;


Happy scripting…

Thursday, July 28, 2011

Conditional insert query without duplicates

This is just a sql puzzle which raised during a long wait for the QA results on a build day.The puzzle seems simple.

  1. Need to insert the records with out duplicates.
  2. The query should consider all the fields.
  3. The query should be single line.ie single statement of query execution.

At first it feels simple as a simple where query. But when we start writing we realize that can we write a where clause in a insert query? Simply speaking how can we write a conditional insert query in sql.After we play with the sql server and queries we automatically come to the below query.

INSERT INTO Person (Name , EMail,Id) 
select 'joy', 'joymon@gmail.com',1
WHERE (
SELECT COUNT(*)
FROM Person
WHERE Name = 'joy' and email='joymon@gmail.com' and id=1) = 0;


The table can be created using.

CREATE TABLE [dbo].[Person](
[Name] [nchar](50) NULL,
[Id] int NOT NULL,
[EMail] [nchar](50) NULL)

Tuesday, June 14, 2011

Setting specific permissions on database objects for a DB user

From the days I am learning RDBMS ,I am hearing that its secured and we can set permissions at the DB object level.When I talk to my fellow DBAs they tell me that they can control so many things to stop hacking.They can restrict an application from executing queries and limit to only stored procedures,delete permission can be revoked on certain tables for the application etc…Since I have not much worked in a real production environment, I didn’t get a chance to try all these.As you know in the development environment developer is the king and he will be having all the permissions.
But last week I got a good opportunity to play with these permission settings.I had to grant update and select permission for a SQL database user on a particular view.Initially we did using the SQL Server Management Studio.It is very easy.Below are the steps.
  1. Navigate to <Your Database>->Security->Users and double click on the user to whom you need to grant or revoke permission.
  2. On the Database user window select the securables page.
  3. There are 2 portions at the right side.Top section is to select securables and below section for the Permissions on the selected securable.
  4. Add your securable using the search window.The search window can be poped up using the search button.
  5. You can add a securable in 3 modes.Specific database object,all object of specific type or all objects in a schema.
  6. Once you add the securable using the search window, the bottom pane will show you what are the permissions you can set on those db objects.
Very easy. Isn’t it? This will work out only if you are delivering your database as a backup.If you are planning to deliver the scripts, you can get the corresponding scripts on clicking the script button at the top of the Database user window.
Below is the Database user window where you can set the permissions visually.
This is the script generated when clicked on the button”Script Action to new query window”

use [AddressBook]
GO
GRANT SELECT ON [dbo].[PersonView] TO [joymon]
GO
use [AddressBook]
GO
GRANT UPDATE ON [dbo].[PersonView] TO [joymon]
GO

Friday, June 10, 2011

Querying all tables in a database using sp_foreachtable

Last week one of my colleague was struggling to write a sql script.After some time he came to me.His requirement was simple, he need to truncate all the tables in the DB.He wrote a script.But it was throwing exception because of foreign key relation ships.My first answer was to run that script for 10 or 20 times so that the child tables will get deleted in initial runs and in primary key tables will get deleted in last runs.A real hack!!isn’t it? I suggested this because he need to just clear a database for one time.

But after some time I thought of solving it properly.For that I didn’t try writing a new script or correcting his script.Just googled and got the below link.
http://stackoverflow.com/questions/155246/how-do-you-truncate-all-tables-in-a-database-using-tsql

It says 2 lines of code as follows.

-- disable all constraints
EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'

-- delete data in all tables
EXEC sp_MSForEachTable 'DELETE FROM ?'


Done.I again enforced the concept of modern programming especially in .Net and SQL server.ie “If you think your problem might be faced by somebody else, google it before even attempting”.


Also I would like to tell about the undocumented procedure sp_msforeachtable.Its very useful when you need to execute same operation in all the database tables.More details can be found in this link.Now a smart programmer you might have though whether there is anything for looping all the databases in the sql server instance.Yes its there.the name is sp_foreachdb.


Oh that is great.Everything related to db objects are available as for each?Unfortunately NO.But you can create your own foreach by following this article.Yes you can create your own  sp_foreachview,sp_foreachsp etc…I don’t think developers including sql developers need this very frequently.But the DBAs surely need this.



Happy scripting.

Sunday, June 5, 2011

SQL OpenRowSet

In simple words OpenRowSet is to fetch data from other sources which are not linked to the sql server in which a query is executing. When we say other data source it can be another sql server instance which is not linked to our sql server instance.

For example if you want to know the details of available databases in another sql server (local\sqlexpress) from your local instance of sql server, you can use the below query to execute

SELECT  *
FROM OpenRowSet ('SQLOLEDB',
'Server=(local)\sqlexpress;TRUSTED_CONNECTION=YES;',
'select * from sys.sysdatabases')


But when you execute this most probably you will receive an error as follows


Msg 15281, Level 16, State 1, Line 1

SQL Server blocked access to STATEMENT 'OpenRowset/OpenDatasource' of component 'Ad Hoc Distributed Queries' because this component is turned off as part of the security configuration for this server. A system administrator can enable the use of 'Ad Hoc Distributed Queries' by using sp_configure. For more information about enabling 'Ad Hoc Distributed Queries', see "Surface Area Configuration" in SQL Server Books Online.

What should we do now?

As usual google and find out the answer.Its only about enabling ad hoc distributed queries as follows


sp_configure 'Ad Hoc Distributed Queries', 1;
RECONFIGURE;

Now run the query again.You will see the result.ie you have queried another independent data source from your sql server.You can even query non databases such as excel,xml etc…

This is the mechanism  if you want to communicate between 2 sql databases which are residing in 2 different server instances without using linked servers.Interesting.Isn’t it.

Note : If the fmtonly is on it will return only the metadata.If you want to get the real data ,make sure fmtonly is off using the below statement in the server where you are running the above sql.

set fmtonly off 

Monday, May 30, 2011

Composite foreign key and order of columns

A simple database related thing which everybody knows.But I would like to post because this took around 4 hrs in our team.Let me come to the scenario. We have a database which has some primary and foreign keys.Its like a normal DB. Now we are doing some enhancements into it which brought a new column to all the primary keys .ie Composite primary key.

This introduces changes in all the other tables which refer using foreign keys.Since there are a number of tables in the database and all the table creation scripts were checked into TFS, we assigned some people to change the foreign key references.They were really new to project and they did their job in less time.We didn’t even run the scripts.But problems started when we run the changed table creation scripts.The error was

“There are no primary or candidate keys in the referenced table 'dbo.master' that match the referencing column list in the foreign key 'FK_Detail_Master'.”

For more details see the below scripts.

create table [master] (
Column1 int,
ColumnNew int
primary key(Column1,ColumnNew)
)
CREATE TABLE [dbo].[Detail](
Column1 [int] NULL,
ColumnNew [int] NULL,
[Column2] [nchar](10) NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Detail] WITH CHECK ADD CONSTRAINT [FK_Detail_Master] FOREIGN KEY([Column1], [ColumnNew])
REFERENCES [dbo].[master] ( [ColumnNew],[Column1])
GO
ALTER TABLE [dbo].[Detail] CHECK CONSTRAINT [FK_Detail_Master]
GO

In the first look its little difficult to identity the issue.But the issue is simple.The order of fields specified is wrong.The Column1 should come first.ie as follows.

ALTER TABLE [dbo].[Detail]  WITH CHECK ADD  CONSTRAINT [FK_Detail_Master] FOREIGN KEY([Column1], [ColumnNew])
REFERENCES [dbo].[master] ([Column1], [ColumnNew])

It was a typo and may be overconfidence.But it costs a lot. We consulted with Dimitri Furman a Microsoft consultant for database and he confirmed the behavior.

Thursday, April 21, 2011

Welcome to SQLCMD

Last couple of weeks I was mainly working in the backend side.Its nothing but SQL server 2008.We had to develop a bunch of scripts which will help the production DBAs to accomplish their tasks with less effort.Since the production environment is unknown and will vary to country to country we cannot put dbo.<table name> in any of our scripts.So we decided to put some tokens in the scripts like #schema#,#DB# etc…the DBA needs to replace these tokens in his environment before running the scripts.
Things went fine till the scripts were reviewed by Microsoft consultant Dimitri Furman .He suggested to use SQLCMD variables.
What is this SQLCMD variables? Do we really need to use that? But after having a script file of 100MB we automatically preferred the sqlcmd mode because SQL Server Management Studio is not suitable for executing such a big sql file.It will definitely crash.

Reasons why we selected SQLCMD
  • We have more files which needs to share the variables.Replacing in all the files is tedious.
  • We have large files which cannot be executed in SSMS.

SQLCMD is the command prompt type interface to execute sql queries.You can start the shell using the executable located in the below location.

<drive>:\Program Files\Microsoft SQL Server\90\Tools\Binn\SQLCMD.EXE

In the first look there is no change.But when we come to authoring sql files there can be changes.Main advantage is you can have scripting variables which will replace their values at run time both in the command mode and in the sql files.You can compare this to classic ASP or PHP programming which replaces the server script before sending to the browser.

Ok Lets see what is this scripting variable by looking at an example.

:setvar PersonName Joy
:setvar email joymon@gmail.com
INSERT INTO Person ([Name] ,[Id] ,[EMail])
VALUES('$(PersonName)', newId(), '$(email)')
GO


PersonName & email are variables and their current values are Joy & joymon@gmail.com respectively.When we refer them using the $() they will get replaced with the values.So here the values got replaced between the single quotes ‘’ and the query run smoothly.
Another advantage is we can call another script file from this using the :r keyword.See the example below.

r: "c:\queries\SQLQuery2.sql"


If we set a variable in one file and that file is calling another file the variables will be available in the second sql script also.If we took the above example,the variable $(PersonName) can be used in SQLQuery2.sql as well.There are lot many advantages, if you explore the possibilities of SQLCMD.Refer the below links for more details.

http://msdn.microsoft.com/en-us/library/ms188714.aspx

http://www.sqlbook.com/SQL-Server/SQLCMD-command-line-utility-13.aspx
Running the sql files with SQLCMD variables in SSMS
You can even run the sql files with SQLCMD variables in SSMS.For that change the query mode to SQLCMD.See the below screenshot.

Monday, March 21, 2011

SQL server ownership chaining

Now a days it becomes a habit to blog, if I learn something.Otherwise I am not feeling it completed.After a long time recently I got a big chance to learn some database related things due to the project which I am doing for my current company.Let me start with SQL server ownership chaining.

What is Database ownership chain?

We all know that what is database object.Everything we create in database is a database object eg:stored procedures,tables ,views etc…When we invoke or access one database object there are chances that it may access another object.This sequence is called the ownership chain.

To understand the scenario better lets take one example.There is a Order table and Order_Jan2011 view.To access the data from the view we have a StoredProcedure usp_GetOrders .When we access or call the sp that sp internally uses the view and that view uses the table.This is ownership chains.If all these objects are owned by one user and the identity which calls the sp  is the same user,there is nothing special.But what if these objects are owned by different users and the user accessing is somebody else? (User here refers to the database user.)

Bypassing security check based on ownership

Lets assume that there are 2 users DBUser and the AppUser.DBUser owns all the DB objects such as tables, views and SPs, where the AppUser has access to only the SPs.When the AppUser calls the SP to retrieve some data the database allows it because the SP and Table used by that are owned by single user that is DBUser.

Lets take one example to understand it clearly.Order Table ,Orders_Jan2011 & usp_GetOrders are owned by the DBUser and the AppUser has access to the SP.

User Relation DBObject
DBUser Owns Order ,Orders_Jan2011,usp_GetOrders
AppUser Has Access usp_GetOrders

When the AppUser calls the usp_GetOrders which calls the view it works.ie the data has retrieved from Orders_Jan2011even though the AppUser dont have permission on Orders_Jan2011.

Try out yourself

Get ready with SQLServer Management Studio (SSMS.exe) to execute the below queries.There are mainly 2 phases in creation.

Create The Users with required permission

create user DBUser without login
Exec sp_addrolemember @RoleName = 'db_owner', @MemberName = 'DBuser'
create user AppUser without login


We use login less users.Hope everybody knows who is login less user.Make the DBUser as db_owner to get the table,view & SP creation permission.

Create DBObjects in the context of DBUser

execute as user = 'DBUser'

--Create Table and insert 2 sample rows----
create table [Order] (Id int,OrderDate date,Details varchar(20))
insert into [Order] values (1,'1/1/2011','5 Laptops')
insert into [Order] values (2,'2/2/2011','2 Desktops')

---Create view that holds orders for the month Jan2011
go
create view Orders_Jan2011
as
select * from [Order] where YEAR(OrderDate)=2011 and MONTH(OrderDate)=1

--Create SP to get the orders and give permission to AppUser
go
create proc usp_GetOrders
as
--Parameterize and add Logic to call the correct view
select * from Orders_Jan2011
grant execute on usp_GetOrders to AppUser
revert

-----Checking the permissions in the context of AppUser------
execute as user = 'AppUser'
go
exec usp_GetOrders
--Executing the below queries will result in error --
--select * from [Order]
--select * from [Orders_Jan2011]
revert


Inserted 2 rows into the Order table.Now creation is over check accessing the DBObjects in the context of AppUser.

execute as user = 'AppUser'
exec usp_GetOrders
--Executing the below queries will result in error --
select * from [Order]
select * from [Orders_Jan2011]
revert


As said earlier the first line ie the SP call will work.Rest will result in error because AppUser don’t have access to those objects.Interesting thing here is sp internally uses the same view and table.

Hope everybody knows DB user impersonation.ie execute as user.The full script can be downloaded from here.

Is this good or bad

It depends own your scenario.There are support for cross database ownership chains.So choose it carefully.For more details see below link.

http://msdn.microsoft.com/en-us/library/ms188676.aspx

Wednesday, October 13, 2010

Reading and writing files in StoredProcedure

I don’t know why I didn’t thought about reading a text file from a stored procedure until I came across a requirement in SSRS.First I searched for something like usp_OpenFile and usp_ReadFile as usual.But no results.After that I realized that I can interact with system from SQL Server only through the Ole Automation.

It was another new thing to me.I have never used Ole Automation through SQL Server.It is not enabled in SQL server by default.We need to enable through the statement sp_configure.

First I tried to see the status of Ole Automation using the query

EXEC sp_configure 'Ole Automation Procedures';
GO


But this returned error saying that this is an advanced option.Then I turned on the advanced options by the below query


sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO


After this I turned on Ole Automation.


sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO


Now the environment is ready for Ole Automation.Just need to execute the SQL which opens and reads a file using COM objects.


DECLARE 
@strPath VARCHAR(255),
@objFileSystem int,
@objTextStream int,
@strRead Varchar(8000),
@strCommand varchar(1000),
@HRESULT int,
@YesOrNo INT
--Initialize variables
select @strPath='c:\temp\test.txt'
select @strRead=''

--Creating the COM File System Object'
EXECUTE @HRESULT = sp_OACreate '
Scripting.FileSystemObject' , @objFileSystem OUT
--HRESULT will be 0 on success
if @HRESULT=0 select @strCommand=@strPath
--Open file
if @HRESULT=0 execute @HRESULT = sp_OAMethod @objFileSystem , '
OpenTextFile', @objTextStream OUT, @strCommand,1,false,0
--Checking for EOF
if @HRESULT=0 execute @HRESULT = sp_OAGetProperty @objTextStream, '
AtEndOfStream', @YesOrNo OUTPUT
--Reading file
IF @YesOrNo=0 and @HRESULT=0 execute @HRESULT = sp_OAMethod @objTextStream, '
ReadAll', @strRead OUTPUT
--Displays the read text.
select @strRead

-- Closing the file "'

if @HRESULT=0 execute @HRESULT = sp_OAMethod @objTextStream, 'Close'
EXECUTE sp_OADestroy @objTextStream



Its not easy if you are not from the COM world.It’s VB equivalent code can be found here in msdn.



You can use the same Ole Automation to write into file as well. Make it as function by returning the variable @strRead.If you just want to run this, copy above code  into a query window of SQL Server Management Studio and press F5.I am not sure whether this will work in other databases except SQL server 2008.



Happy scripting…

Thursday, February 11, 2010

Dynamic sql queries in stored procedures

This is an old concept which I studied recently.The whole idea is to create a query in stored procedures and execute it.
Some times we cannot predict the table name or the criteria which should be used to retrieve or update the data in the sql query.Normally people constructs the query in the code itself and executes that query.But that exposes threat of SQL injection.
For example if we need to write a common method to select all the records from tables ie select * from <table name> we normally write a method with a signature which accepts the table as string and constructs the query and executes it.But there is another option which allows us to create the same query in the SP itself and execute the same.See the below sql.

Declare @SQL VarChar(1000)
declare @TableName varchar(50)

select @TableName = 'Employees'
SELECT @SQL = 'SELECT * FROM '
SELECT @SQL = @SQL + @TableName

Exec ( @SQL)


Hope the code is self explanatory and help you to avoid sql statements from your C# or VB code.

Sunday, January 17, 2010

Finding out which sps are in deadlock in SQL server

When my current Silverlight 3 project went into QA environment, I got one more chance to met my old friend.Yes It’s deadlock.But unfortunately we were not able to reproduce it in the dev environment.There started the problem.
But after a big battle in my dev machine I was able to reproduce the deadlock.Steps were simple.I just need to do the normal operations in the application at lightening speed.
Then we knew its a problem with the WCF service calls from the client to server.There were 2 calls going from client to server while saving where it is supposed to be one by according to the design of the application.But application is in QA.So we tried to resolve that by introducing some mechanisms in the DB.To continue that we needed the information about the SPs which are in deadlock.
Since our application implements the transaction from code and that transaction contains so many sp calls one by one it was very difficult to figure out which sp is in trouble.If we try debug mode there won’t be any deadlock.Finally our DBA given me 2 methods to find out the sps.
The below one give the details about the things happening inside the sql server including the SPID.

sp_who2

Execute the above command in SQL Server Management Studio on your DB.Once you get the SPID use that to find out exactly what is deadlocked in the below method.

dbcc inputbuffer (<SPID>)
I know for a DBA this is not a big thing.But for a developer I think this will help him a lot.

Monday, December 8, 2008

Bulk insert into SQL server database table

The need
This comes into role when we need to insert a bulk amount of record into a table.This probably won't be coming from the user but through a text file which has defined field and record terminators.Usually if we have some pre collected data.
Implementation
The bulk insert query in sql helps us to implement this with out a parsing program.
The syntax and details can be found here
Example
We have a table called 'TestTable' in the database 'TestDB' with 2 fields 'ID' and 'Name'.
The data text file contains values which got delimeters as follows
,- separates fields
;\n -separates records
----------------
1,Joy;
2,George;
3,Hai;
4,Hello;
-----------------
Then the query is
--------------------------------
BULK INSERT TestDB.dbo.[TestTable]
FROM 'd:\test.txt'
WITH
(
FIELDTERMINATOR = ','
ROWTERMINATOR = ';\n'
)
---------------------------------