It was the coldest night of the year a query with a lot of columns had me in tears…

Yesterday I was working with Jason so super big thank you to him for this script.  We were writing an insert statement and it had a lot of columns.  I was getting ready to script out the table when he showed me this little bit of code.  If you enter your database name and table name it will give you all your columns with commas.  You can even toss your alias in the query so you don’t have to spend a bunch of time adding it.

Declare @DBName as varchar(100)
Declare @tablename as varchar (100)

Set @DBName = 'MyDatabaseName'
Set @tablename = 'MyTableName'

Select T.TABLE_SCHEMA, T.TABLE_NAME
, Stuff(
(
Select ', ' + C.COLUMN_NAME
From INFORMATION_SCHEMA.COLUMNS As C
Where C.TABLE_SCHEMA = T.TABLE_SCHEMA
And C.TABLE_NAME = T.TABLE_NAME
Order By C.ORDINAL_POSITION
For Xml Path('')
), 1, 2, '') As Columns
From INFORMATION_SCHEMA.TABLES As T
Where T.TABLE_CATALOG=@DBName
and T.TABLE_NAME=@tablename

I hope you enjoy it too!

Welcome to the new Deja Vu, you can populate a column from another database….

Greetings and other Salutations!
Yesterday I was working with someone new to T-SQL who needed to get data from one table in a database to another table in a different database. He was stumped and spent hours trying to find some way to do it. I was able to help him and realized this might be a common problem for people new to T-SQL.

We have two databases on our Instance SuperHero and Marvel and each database has a table Superhero.dbo.Character and Marvel.dbo.Bio.

First, prep the table you want to put data in. You won’t be using an insert statement for this task because in our scenario we already have data in our table. To prep my table I am adding a column at the end of my table and allowing it to have nulls.

Character
CharacterID, Name, Universe, RealName(This is our new column that is null)
1, Spider-man, Marvel,
2, Batman, DC,
3, Iron Man, Marvel,

Bio
BioID, Name, CharacterID, RealName(This is where we will update our new column from)
1, Spider-man, 1, Peter Parker
2, Iron Man, 3, Tony Stark

Next, we join across databases. As you can see these two tables would join on CharacterID so:

 
SELECT C.CharacterID, C.Name, C.Universe, C.RealName, B.BioID, B.Name, B.CharacterID, B.RealName
FROM Superhero.dbo.Character C
INNER JOIN Marvel.dbo.Bio B ON C.CharacterID = B.CharacterID

The “INNER JOIN” also acts as my where clause so that it will only update records that match in both. Please always build and test your SELECT statement first to make sure it is going to update what you expect.
Now we build our update:

 
UPDATE dbo.Character
SET RealName = B.RealName
FROM Superhero.dbo.Character C
INNER JOIN Marvel.dbo.Bio B ON C.CharacterID = B.CharacterID

Be sure you are running on the Superhero database for your update.
Who knew bringing super heroes together would only take a query?

They’ll never take my body from your side, Love don’t die from partitioning…

New dress for Christmas

New dress for Christmas

So this week there was this small fire around running out of partitions.  Because I had to learn how all of it works really fast, I need to write it down before I forget.  I was getting a range doesn’t exist error so here is what I did:

I already had my file groups created.  If you don’t do that before you move on.

Find what partition schemes and functions you have in your database:

SELECT * FROM sys.partition_schemes

SELECT * FROM sys.partition_functions

(Hint: the fanout is the last range so that can help you identify which one is failing.)

Next, see what your current ranges look like:

SELECT sprv.value AS [Value], sprv.boundary_id AS [ID]
FROM sys.partition_functions AS spf
INNER JOIN sys.partition_range_values sprv ON sprv.function_id = spf.function_id
WHERE (spf.name = N'PartitionFunctionName')
ORDER BY [ID] ASC

Now we are going to split out our partitions one at a time.  Even if you need to add 5 or more ranges, this is an easy step to do one at a time.  Also, you can only split a range into to pieces at a time, so just run the whole query for each range you want to add.

ALTER PARTITION SCHEME [PartitionScheme] NEXT USED [YourFileGroup]

ALTER PARTITION FUNCTION [PartitionFunction]() SPLIT RANGE (N'NewRange')

This should get you back on track.

Happy Trails!

They said “If you don’t let it out, You’re going to let it eat you away” – CHARINDEX with SUBSTRING

Greetings and other Awesome Salutations,
It has been a while because I am learning oodles of new stuff. There are a few things that I don’t want to forget so here goes.

CHARINDEX is a super easy way to get the starting location of something within a string. For example, I was looking for the last half of Superhero names. My column is SuperheroName in the Comics Table and pretend there are dashes in their names, please just for this example – I know there aren’t really dashes please continue to love me with my flaws.
So…
SELECT TOP 4 SuperheroName
FROM Comics

Results:
Bat-man
Bat-girl
Super-man
Super-girl

Now the magic, CHARINDEX will give you the location of the character you specify.

SELECT TOP 4 CHARINDEX('-', SuperheroName)
FROM Comics

Results:
4
4
6
6

How cool is that?!! But I want to pull back everything after the “-” character, which means I have to get tricky because CHARINDEX will only give me the location number of where it is within the string. SUBSTRING will save the day (Tada!). SUBSTRING is really cool. I am going to pass it ColumnName, Starting Position (using CHARINDEX), Ending Position (using LEN and the column name that will get me the length of that column on that row). So it looks like this:

SELECT TOP 4 SUBSTRING(SuperheroName,CHARINDEX('-',SuperheroName), LEN(SuperheroName))
FROM Comics

Results:
-man
-girl
-man
-girl

But that still isn’t quite what I want…so I am going to add 1 to the Starting point position number (this will allow me to skip over the character I am using):

SELECT TOP 4 SUBSTRING(SuperheroName,CHARINDEX('-',SuperheroName)+1, LEN(SuperheroName))
FROM Comics

Results:
man
girl
man
girl

Oh but wait, there is more! I think it is really silly to have the dashes in the first place so check this out:
SELECT TOP 4
SUBSTRING(SuperheroName,1,CHARINDEX('-',SuperheroName)-1) + SUBSTRING(SuperheroName,CHARINDEX('-',SuperheroName)+1, LEN(SuperheroName))
FROM Comics

Results:
Batman
Batgirl
Superman
Supergirl

Holy Rusted Metal Batman! What did we do? This time in my substring I used the first position and then the CHARINDEX -1 to tell me what was right before the dash. Then I combined them! With these super powers combined…well awesome things happen.

Enjoy!

You must not know about me, I can kill connections in a minute

It is still snowy and cold outside so short post today about killing connections.  I love this quick little script and can’t remember where I got it from, so huge Thank You to the person that created it.  I use it when I need to restore a database that still has active connections.  This will first print a list of the connections it wants to kill for the database in the where clause, if you uncomment the “EXEC” part, you will get the fastest connection killer you have ever used. 

DECLARE @SQL VARCHAR(8000)

SELECT @SQL=COALESCE(@SQL,'')+'Kill '+CAST(spid AS VARCHAR(10))+ '; '
FROM sys.sysprocesses
WHERE DBID=DB_ID('DatabaseName')

PRINT @SQL
--EXEC(@SQL) /*Replace the print statement with exec to execute*/

Enjoy and Have a Magical Day!

Everybody leaves so why wouldn’t you…Changing Schemas with version upgrades

A few months ago I was upgrading from SQL2000 to SQL2005 (it is a slow step in the right direction). The schema had been a user schema and I needed it changed back to the “dbo” schema so it would work with the new software. I first tried recreating the tables and realize it could take me all day. Then I tried the Export data feature. This would also have worked, but again was really time-consuming. Luckily, someone sent me this little script:

exec sp_MSforeachtable "ALTER SCHEMA dbo TRANSFER ? PRINT '? modified' "
Run this on the database you need to fix the schema on and you have just saved yourself a bunch of work.

I’m looking at you through the glass…mirror failover

Happy Holidays to the Kingdom! I know many will be going on vacation so I wanted to do an easy post that wouldn’t break anyone’s brain. Also, I am having problems with my brain and have been having tests done so mirroring just seemed to fit today. When it first appeared, I didn’t see much use for it, but now that I use it often, I love it. So Fail over that magic mirror. This script assumes the default configuration port of 5022.

You can check your endpoints this way:

select @@SERVERNAME, * from sys.endpoints
go

Here is how you would create an endpoint if it didn’t already exist.

select @@SERVERNAME, * from sys.endpoints
go
CREATE ENDPOINT Mirroring
STATE=STARTED
AS TCP (LISTENER_PORT=5022)
FOR DATABASE_MIRRORING (ROLE=PARTNER)
go

This is how you would fail over or fail back to a database.

:connect
ALTER DATABASE SET PARTNER FAILOVER

Finally, if you want to bring a previously mirrored database online this is super simple.

Restore Database With Recovery;

Love your magic mirror and it will love you too! Happy Holidays to all!

Someone says “You’re in the wrong place master, you better leave”

Moving system databases. Whenever I have brought this up with a co-worker they seem to get a bit freaked out and want to avoid moving them.  I used to be the same, but happily now I am comfortable moving them around.

Let me first tell you why I want to move them.  I like to have my Data files on the D: drive, Log files on the E: drive, Backup files on the F: and my Tempdb files on the G: Drive.  These are all SAN drives.  This method keeps me consistent for all my servers and I am able to quickly know where to find everything I need.  I am also able to easily identify which drive my problem is on.  But my favorite reason is that in the past (three separate times), I have lost the OS to my SQL Server.  Because I had master, model, and msdb on the D: drive, after a quick re-install of SQL and the correct patch, I was able to re-point to master and everything came up beautifully without further recovery.  I had over 70 databases on one of these instances, and this method prevented me from having to restore each one along with log files. It was a wonderful surprise the first time it worked.

There are performance reasons for splitting out your files on to different drives, but we can get into that later because it requires its own post.

This step comes before I split out my tempdb files, so I am only moving one. You could easily add more lines of code to allow you to move more tempdb files.

So let’s get to the code and you will see how easy it is to do.  You will never fear moving the system databases again. This code is set up for SQL2008, but is easily modified for whatever version you are using.  Just set it up to match the folder structure.


--Check to see where your files are now.

SELECT *
FROM sys.master_files

--Move your files
USE master
GO

ALTER DATABASE model
MODIFY FILE (NAME = modeldev, FILENAME = 'D:\MSSQL10.MSSQLSERVER\MSSQL\DATA\model.mdf');
GO

ALTER DATABASE model
MODIFY FILE (NAME = modellog, FILENAME = 'E:\MSSQL10.MSSQLSERVER\MSSQL\DATA\modellog.ldf');
GO

ALTER DATABASE msdb
MODIFY FILE (NAME = MSDBData, FILENAME = 'D:\MSSQL10.MSSQLSERVER\MSSQL\DATA\MSDBData.mdf');
GO

ALTER DATABASE msdb
MODIFY FILE (NAME = MSDBLog, FILENAME = 'E:\MSSQL10.MSSQLSERVER\MSSQL\DATA\MSDBLog.ldf');
GO

ALTER DATABASE  tempdb
MODIFY FILE (NAME = tempdev, FILENAME = 'G:\MSSQL10.MSSQLSERVER\MSSQL\DATA\tempdb.mdf');
GO

ALTER DATABASE tempdb
MODIFY FILE (NAME = templog, FILENAME = 'G:\MSSQL10.MSSQLSERVER\MSSQL\DATA\templog.ldf');
GO

Stop the SQL Server and physically copy over the files. Restart the SQL Server and verify they moved your files moved.

SELECT *
FROM sys.master_files

Now here is the next part of the magic.  Go to the SQL Server Configuration Manager, right click on your SQL Server and go to Advanced.  There is a line for Start-up Parameters.  You will also need to modify this string to match your version, but I simply paste this in:

-dD:\MSSQL10.MSSQLSERVER\MSSQL\DATA\master.mdf;-eC:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Log\ERRORLOG;-lE:\MSSQL10.MSSQLSERVER\MSSQL\DATA\mastlog.ldf

Then I stop my SQL Server, copy my master files to the right locations and start up SQL Server again.  It is so easy.  Test it out a few times until you are comfortable and then it will be like you are moving them around with a magic wand.

You’ve got to move it, move it!

I have been rushing all week trying to get new development environments upgraded to 2012 while leaving the old environments online. Everyone wants it done now and I wanted to share a few things that are making my job easier.
This first one is a script that makes copying logins across servers so easy. I found this online and feel terrible that I can’t properly accredit it to the person that wrote it. (If you wrote it, let me know and I will update this)

 

USE master
GO
IF OBJECT_ID (‘sp_hexadecimal’) IS NOT NULL
DROP PROCEDURE sp_hexadecimal
GO
CREATE PROCEDURE sp_hexadecimal
@binvalue varbinary(256),
@hexvalue varchar (514) OUTPUT
AS
DECLARE @charvalue varchar (514)
DECLARE @i int
DECLARE @length int
DECLARE @hexstring char(16)
SELECT @charvalue = ‘0x’
SELECT @i = 1
SELECT @length = DATALENGTH (@binvalue)
SELECT @hexstring = ‘0123456789ABCDEF’
WHILE (@i <= @length)
BEGIN
DECLARE @tempint int
DECLARE @firstint int
DECLARE @secondint int
SELECT @tempint = CONVERT(int, SUBSTRING(@binvalue,@i,1))
SELECT @firstint = FLOOR(@tempint/16)
SELECT @secondint = @tempint – (@firstint*16)
SELECT @charvalue = @charvalue +
SUBSTRING(@hexstring, @firstint+1, 1) +
SUBSTRING(@hexstring, @secondint+1, 1)
SELECT @i = @i + 1
END

SELECT @hexvalue = @charvalue
GO

IF OBJECT_ID (‘sp_help_revlogin’) IS NOT NULL
DROP PROCEDURE sp_help_revlogin
GO
CREATE PROCEDURE sp_help_revlogin @login_name sysname = NULL AS
DECLARE @name sysname
DECLARE @type varchar (1)
DECLARE @hasaccess int
DECLARE @denylogin int
DECLARE @is_disabled int
DECLARE @PWD_varbinary varbinary (256)
DECLARE @PWD_string varchar (514)
DECLARE @SID_varbinary varbinary (85)
DECLARE @SID_string varchar (514)
DECLARE @tmpstr varchar (1024)
DECLARE @is_policy_checked varchar (3)
DECLARE @is_expiration_checked varchar (3)

DECLARE @defaultdb sysname

IF (@login_name IS NULL)
DECLARE login_curs CURSOR FOR

SELECT p.sid, p.name, p.type, p.is_disabled, p.default_database_name, l.hasaccess, l.denylogin FROM
sys.server_principals p LEFT JOIN sys.syslogins l
ON ( l.name = p.name ) WHERE p.type IN ( ‘S’, ‘G’, ‘U’ ) AND p.name <> ‘sa’
ELSE
DECLARE login_curs CURSOR FOR
SELECT p.sid, p.name, p.type, p.is_disabled, p.default_database_name, l.hasaccess, l.denylogin FROM
sys.server_principals p LEFT JOIN sys.syslogins l
ON ( l.name = p.name ) WHERE p.type IN ( ‘S’, ‘G’, ‘U’ ) AND p.name = @login_name
OPEN login_curs

FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin
IF (@@fetch_status = -1)
BEGIN
PRINT ‘No login(s) found.’
CLOSE login_curs
DEALLOCATE login_curs
RETURN -1
END
SET @tmpstr = ‘/* sp_help_revlogin script ‘
PRINT @tmpstr
SET @tmpstr = ‘** Generated ‘ + CONVERT (varchar, GETDATE()) + ‘ on ‘ + @@SERVERNAME + ‘ */’
PRINT @tmpstr
PRINT ”
WHILE (@@fetch_status <> -1)
BEGIN
IF (@@fetch_status <> -2)
BEGIN
PRINT ”
SET @tmpstr = ‘– Login: ‘ + @name
PRINT @tmpstr
IF (@type IN ( ‘G’, ‘U’))
BEGIN — NT authenticated account/group

SET @tmpstr = ‘CREATE LOGIN ‘ + QUOTENAME( @name ) + ‘ FROM WINDOWS WITH DEFAULT_DATABASE = [‘ + @defaultdb + ‘]’
END
ELSE BEGIN — SQL Server authentication
— obtain password and sid
SET @PWD_varbinary = CAST( LOGINPROPERTY( @name, ‘PasswordHash’ ) AS varbinary (256) )
EXEC sp_hexadecimal @PWD_varbinary, @PWD_string OUT
EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT

— obtain password policy state
SELECT @is_policy_checked = CASE is_policy_checked WHEN 1 THEN ‘ON’ WHEN 0 THEN ‘OFF’ ELSE NULL END FROM sys.sql_logins WHERE name = @name
SELECT @is_expiration_checked = CASE is_expiration_checked WHEN 1 THEN ‘ON’ WHEN 0 THEN ‘OFF’ ELSE NULL END FROM sys.sql_logins WHERE name = @name

SET @tmpstr = ‘CREATE LOGIN ‘ + QUOTENAME( @name ) + ‘ WITH PASSWORD = ‘ + @PWD_string + ‘ HASHED, SID = ‘ + @SID_string + ‘, DEFAULT_DATABASE = [‘ + @defaultdb + ‘]’

IF ( @is_policy_checked IS NOT NULL )
BEGIN
SET @tmpstr = @tmpstr + ‘, CHECK_POLICY = ‘ + @is_policy_checked
END
IF ( @is_expiration_checked IS NOT NULL )
BEGIN
SET @tmpstr = @tmpstr + ‘, CHECK_EXPIRATION = ‘ + @is_expiration_checked
END
END
IF (@denylogin = 1)
BEGIN — login is denied access
SET @tmpstr = @tmpstr + ‘; DENY CONNECT SQL TO ‘ + QUOTENAME( @name )
END
ELSE IF (@hasaccess = 0)
BEGIN — login exists but does not have access
SET @tmpstr = @tmpstr + ‘; REVOKE CONNECT SQL TO ‘ + QUOTENAME( @name )
END
IF (@is_disabled = 1)
BEGIN — login is disabled
SET @tmpstr = @tmpstr + ‘; ALTER LOGIN ‘ + QUOTENAME( @name ) + ‘ DISABLE’
END
PRINT @tmpstr
END

FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin
END
CLOSE login_curs
DEALLOCATE login_curs
RETURN 0
GO

EXEC sp_help_revlogin

 

This next one is awesome too. When you have copied a database to a new server and have SQL logins that you want to sync up really quick, this script is awesome. Run it on each database that has that login.

ALTER USER [LoginName]
WITH LOGIN = [LoginName]

I hope this will save you some time and helps you get to the ball too!

Have a magical day!

Biting – Bits and Bytes

A few weeks ago I found myself talking with a network engineer.  We were discussing why my data being transferred over a network was slow.  It was a small database and I didn’t understand why if we have a 1 gigabit connection, my 1 gigabyte database was slow moving over it.  I am still working this concept in my head and would love feedback of how to help me understand it better.

A bit is one binary digit of 0 or 1.  One kilo-bit (kb) is 1000 bits, One Megabit(Mb) is 1,000,000 bits and One Gigabit (Gb) is 1,000,000,000 bits. Bits are always represented as b whereas Bytes are represented as B.  Bits focus on the data being moved over the wire between two telecommunication devices and are moved as binary.  Usually the speed is measured in seconds for example 8kbps means you moved 8000 bits or 8 kilo-bits in a second between two telecommunication points. Moving 8000 binary digits in a second isn’t too bad…right?  So why is my stuff moving slow.  Isn’t that close to moving  an 8KB SQL page?  No, let’s keep going.

One Byte is equal to 8 bits.  One Kilobytes (KB) is 1024 bytes or 8192 bits. One Megabyte (MB) is 1,048,576 bytes or 8,388,608 bits and for fun, lets do Gigabytes.  One Gigabyte (GB) is 1,073,741,824 bytes or 8,589,934,592 bits.  This is a lot of math and there are wonderful calculators around to help you compute your current and desired throughput.

On to our next interesting fact: To go over the wire, your Bytes are being transferred into bits and then back up to Bytes on the other end.  So if your connection is 8kbps (remember that is kilo-bits per second) you are only moving about 1000 Bytes per second.  Let’s look at my gigabit connection. If I am moving one gigabit per second (1gbps) then I am only moving (I am rounding) about 120 Megabytes (MB) per second. That is a big difference that what I thought I should be moving.

I know there are a lot of cool ways to move data faster, but this is a concept that every DBA should keep at the back of their mind even if it is just to perform a party trick to make your network engineer friends feel included.

Happy Biting!