Author Archives: nakulvachhrajani

Unknown's avatar

About nakulvachhrajani

Nakul Vachhrajani is a SQL Server MCTS, TOGAF certified Technical Architect with Capgemini having a total IT experience of more than 16 years. Nakul is an active blogger, and has been a guest columnist for SQLAuthority.com and SQLServerCentral.com. Nakul presented a webcast on the “Underappreciated Features of Microsoft SQL Server” at the Microsoft Virtual Tech Days Exclusive Webcast series (May 02-06, 2011) on May 06, 2011. He is also the author of a research paper on Database upgrade methodologies, which was published in a CSI journal, published nationwide. In addition to his passion about SQL Server, Nakul also contributes to the academia out of personal interest. He visits various colleges and universities as an external faculty to judge project activities being carried out by the students. Disclaimer: The opinions expressed herein are his own personal opinions and do not represent his employer’s view in anyway.

#0317 – SQL Server – A confession – Why you should not work on multiple tasks when writing a deployment script?


Delivery timelines and working till late in the evening – we have all been through these situations. This post is a true story – a confession about an incident that happened with me a couple of days ago. I was busy preparing a deployment script with a large number of stored procedures when I was distracted by a phone call reasonably late in the day. When I returned back to work, I made an error in the script that I was writing. What resulted afterwards was that the late evening turned into late night at work. As strange as it may seem, but when the error was caught, I simply laughed out loud at myself.


Test Scenario


Shown below is a quick demo of the mistake that I made. The script below creates two stored procedures – dbo.proc_Add2Numbers and dbo.proc_Multiply2Numbers.


But there is something wrong. Once you have gone through the script, pause a while and see if you can figure out the error.

USE tempdb;
GO
–Create the test procedures
IF OBJECT_ID(‘dbo.proc_Add2Numbers’,’P’) IS NOT NULL
DROP PROCEDURE dbo.proc_Add2Numbers;
GO
CREATE PROCEDURE dbo.proc_Add2Numbers
@iA INT,
@iB INT
AS
BEGIN
SET NOCOUNT ON;

SELECT (@iA + @iB) AS SumAB;
END;

IF OBJECT_ID(‘dbo.proc_Multiply2Numbers’,’P’) IS NOT NULL
DROP PROCEDURE dbo.proc_Multiply2Numbers;
GO
CREATE PROCEDURE dbo.proc_Multiply2Numbers
@iA INT,
@iB INT
AS
BEGIN
SET NOCOUNT ON;

SELECT (@iA * @iB) AS MultiplyAB;
END;
GO


The Result


Let’s run the test that make my head spin that evening. What happened was that a test similar to the following ran fine for the first time:

USE tempdb;
GO
EXEC dbo.proc_Multiply2Numbers @iA = 2, @iB = 5;
GO
EXEC dbo.proc_Add2Numbers @iA = 2, @iB = 5;
GO

image


But, when I tried to run it again with a different set of parameters:

USE tempdb;
GO
EXEC dbo.proc_Multiply2Numbers @iA = 3, @iB = 6;
GO
EXEC dbo.proc_Add2Numbers @iA = 3, @iB = 6;
GO

I landed with the following error:


Msg 2812, Level 16, State 62, Line 1
Could not find stored procedure ‘dbo.proc_Multiply2Numbers’.


So, I returned the database to it’s base state and repeated the process again – same error! It had already been way beyond my normal work hours and this error did it’s part to keep in the office for an hour more!


The Root Cause


If you have already figured out the error, that’s really great – you will surely have a great day ahead! But, I was not so lucky. After an hour of scratching my head, drinking coffee and looking at the script over and over again, I finally realized by mistake:



A missing batch terminator – “GO”!


If you, like me were unable did not figure it out, look at the script again. Or better still, run the following:

USE tempdb;
GO
SELECT OBJECT_DEFINITION(OBJECT_ID(‘dbo.proc_Add2Numbers’,’P’));
GO

/***********/
/* Results */
/***********/
CREATE PROCEDURE dbo.proc_Add2Numbers
@iA INT,
@iB INT
AS
BEGIN
SET NOCOUNT ON;

SELECT (@iA + @iB) AS SumAB;
END;

–IMPORTANT: Notice the missing GO here!

IF OBJECT_ID(‘dbo.proc_Multiply2Numbers’,’P’) IS NOT NULL
DROP PROCEDURE dbo.proc_Multiply2Numbers;


As you can see from the script results above, the batch terminator “GO” was missing between the two stored procedures in the deployment script because of which the script to check for the existence of dbo.proc_Multiple2Numbers was included in the definition of dbo.proc_Add2Numbers.


When I ran the test for the first time, I executed dbo.proc_Multiply2Numbers first. When the dbo.proc_Add2Numbers was executed, it dropped the procedure dbo.proc_Multiply2Numbers which is why it was unavailable in round #2.


Lessons Reminded/Learnt


I realized two lessons on that day:



  1. Reminder: A stored procedure definition includes everything from the CREATE PROCEDURE statement to the batch terminator
  2. Lessons Learnt: Do NOT multi-task!

Until we meet next time,


Be courteous. Drive responsibly.

#0316 – SQL Server – sp_help and multi-part naming of objects – Msg 102 – Incorrect syntax near ‘.’


I was recently working on exploring a couple of tables in a database that I was troubleshooting for performance purposes. I was using the system stored procedure sp_help and all was fine until I started accessing tables with a schema other than the default – “dbo”.


As soon as I started to access tables with schemas other than “dbo”, I encountered the following error:

USE AdventureWorks2012;
GO
sp_help HumanResources.Employee;
GO

Msg 102, Level 15, State 1, Line 1
Incorrect syntax near ‘.’.


Initially I thought that it was because I had not enclosed them in square brackets to indicate object identifiers, so, I tried that with the same results:

USE AdventureWorks2012;
GO
sp_help [HumanResources].[Employee];
GO

Msg 102, Level 15, State 1, Line 1
Incorrect syntax near ‘.’.


Then, I realized that sp_help is possibly unable to handle the multi-part naming convention of SQL Server objects, which to me is quite odd. So, I enclosed the entire two-part name inside of square brackets and it worked!

USE AdventureWorks2012;
GO
sp_help [HumanResources.Employee];
GO

image


And so did this:

USE AdventureWorks2012;
GO
sp_help ‘HumanResources.Employee’;
GO

As I mentioned earlier, I find this behaviour of sp_help to be strange. I can understand why it accepts [schemaname.objectname] format, but what I can’t understand is why it can’t accept [schemaname].[objectname]. While I was able to get through the exploratory process with my newly discovered workaround, I am quite sure that many developers would be ending up with this error day in and day out.


Have you encountered this behaviour?


Further Reading:



  • An Introduction to Multi-part naming standards for Object name referencing [Link]
  • Scripts to generate and parse multi-part database object names – PARSENAME() function [Link]
  • sp_help [Books On Line Link]

Until we meet next time,


Be courteous. Drive responsibly.

#0315-SQL Server-Different ways to check for existence of an object (table/SP, etc)


I was recently reviewing the deployment scripts for a couple of products and I noticed that each team/DBA had their own style – and neither of them was incorrect. So, I sat about documenting each of those different styles for my own academic interest. I was able to document a total of 6 different ways in which various teams/DBAs and tools check for existence of a SQL Server object (table, stored procedure, etc).

These 6 different ways are shown below:

USE AdventureWorks2012;
GO

--1. The ISO compliant way
SELECT *
FROM INFORMATION_SCHEMA.TABLES AS ist
WHERE ist.TABLE_SCHEMA = 'HumanResources'
  AND ist.TABLE_NAME = 'Employee';
GO

--2. Using SQL Server Catalog Views
SELECT *
FROM sys.tables AS st
WHERE st.schema_id = SCHEMA_ID('HumanResources')
  AND st.name = 'Employee'
  AND st.is_ms_shipped = 0; --We are only looking for user objects!
GO

--3. Using SQL Server Catalog Views
SELECT *
FROM sys.objects AS so
WHERE so.type = 'U'
  AND so.schema_id = SCHEMA_ID('HumanResources')
  AND so.name = 'Employee'
  AND so.is_ms_shipped = 0; --We are only looking for user objects!
GO

--4. Using the OBJECT_ID function (The easy way)
--If the OBJECT_ID does not return a NULL value, the object exists
--For the object type value, refer http://technet.microsoft.com/en-us/library/ms190324.aspx
SELECT OBJECT_ID('HumanResources.Employee','U') AS ObjectId;
GO

--5. A Hybrid appraoch
SELECT *
FROM sys.objects AS so
WHERE so.object_id = OBJECT_ID('HumanResources.Employee','U')
  AND so.is_ms_shipped = 0; --We are only looking for user objects!
GO

--6. The SSMS way 
--   (if you have set your scripting options to check for object existence)
SELECT *
FROM sys.objects AS so
WHERE so.object_id = OBJECT_ID('HumanResources.Employee')
  AND so.type IN ('U');
GO

You can see here that we have a wide variety of methods that check for existence of an object – from ISO compliant ways to purely SQL Server specific ways.

My favourite method is method #4, using the function OBJECT_ID(). What one is your favourite?

Do note that OBJECT_ID will not work for objects which are not schema scoped, e.g. DDL triggers.

Further Reading

Until we meet next time,

Be courteous. Drive responsibly.

#0314-SQL Server-Identify records with special characters using regular expressions


One of my team mates was recently faced with an interesting problem – a few records were inserted/updated into the database via some backend data append and bulk insert tasks. These records apparently had some special characters which was causing the application to crash. While a application code fix was being developed, tested and deployed it was essential to be able to identify the bad data and clean it up as a stop-gap arrangement. The problem was that the offending characters were not available on the keyboard! (i.e. they were “special” characters). I was approached to help with this task and this is an account of a solution that I came up with.


Demo


To begin with the demo, let us assume that we have a table with a text column that has both – “bad” and “good” data. To simulate the bad data, I am using special characters from the ASCII table which are not generally visible on the console (e.g. a vertical tab and others). Characters like Space and Horizontal tabs are quite normal in almost all documents and are therefore considered to be valid characters for the purposes of this demo.


Once the table has been created and test data created, we go about the task of identifying the offending records. To do so, we simply build a lookup table which would help us create a string of “bad” characters which can be used as part of a regular expression.


That’s it! Once the regular expression is ready, it’s a matter of writing a simple SELECT statement to identify the records matching the expression.


The complete script, with the output is shown below:

USE tempdb;
GO
–Create the test table
IF OBJECT_ID(‘tempdb..#hiddenCharacterValues’,’U’) IS NOT NULL
DROP TABLE #hiddenCharacterValues;
GO

CREATE TABLE #hiddenCharacterValues
(RecordId INT IDENTITY(1,1),
RecordValue VARCHAR(25)
);
GO

–Insert some test data into the table
INSERT INTO #hiddenCharacterValues
(RecordValue)
VALUES (‘StandardSpace’ + CHAR(32)), –Good
(‘GroupSeparator’ + CHAR(29)), –Bad
(‘HorizontalTab’ + CHAR(9)), –Good
(‘VerticalTab’ + CHAR(11)), –Bad
(‘ExtendedASCII’ + CHAR(176)); –Bad
GO

–Build a comma separated list of known “bad characters”
DECLARE @regExString VARCHAR(MAX);
DECLARE @invalidCharLookUp TABLE (InvalidChars VARCHAR(2));
INSERT INTO @invalidCharLookUp (InvalidChars)
VALUES (CHAR(11)),
(CHAR(29)),
(CHAR(176));

SELECT @regExString = COALESCE(@regExString,”)
+ iclu.InvalidChars
FROM @invalidCharLookUp AS iclu;

–Finally select records which contain these characters
SELECT hcv.RecordId,
hcv.RecordValue
FROM #hiddenCharacterValues AS hcv
WHERE hcv.RecordValue LIKE ‘%[‘ + @regExString + ‘]%’;
GO


image


Now that the records are identified, they can either be manually updated or deleted (as required by the business).


Related Posts



  • Using Regular Expressions with CHECK constraints [Link]

Are there any other methods that you would use (or are using) to address such an issue? Please do let me know.


Until we meet next time,


Be courteous. Drive responsibly.

#0313 – SQL Server – sp_help returns double the field length for Unicode characters


Recently, I was asked a good question by an intern. As he was going through our database design, he noticed that the column lengths of character columns were coming out to be exactly the double of what was mentioned in our documentation. When he approached me, I asked him just one question – “What are you using to validate the column length?” As expected the answer was – “The System stored procedure – sp_help”. The question therefore is:

Why would sp_help report a column length that is double than what is expected for a string column value?

The answer lies in knowing whether a particular character column supports Unicode or not. When working with Unicode data, if the collation code page does not use double-byte characters, the underlying storage requirement is two times the string length defined when defining the column.

An Example

The AddressLine1 and AddressLine2 fields in the Person.Address table of the AdventureWorks2012 sample database are defined to be 60 characters in length (see screenshot below), but when checked using sp_help, they show the length as being 120.

image

USE AdventureWorks2012 ;
GO
SELECT  DATABASEPROPERTYEX(DB_NAME(), 'Collation') 
        AS DBCollationName ;
GO

sp_help [Person.Address] ;
GO

The results of this query are shown below, which clearly show the doubled length value.

image

The reason for this discrepancy is that sp_help does not report the number of characters, but reports on the maximum number of bytes that the column can occupy.

In this case, both the AddressLine1 and AddressLine2 columns are 60 characters in length, but because the column is a NVARCHAR column, it occupies 120 bytes which is reported by the sp_help system stored procedure.

Further Reading

Until we meet next time,

Be courteous. Drive responsibly.