Category Archives: SQL Server

Home / SQL Server
48 Posts

Using setvar in T-SQL
Set the values of the two SQLCMD variables.

In this example, the script will only run the shrink if the ‘foo’ database has at least 100 MB to potentially free.

The script runs a shrink on each file of the database until the reduction value drops to zero.

Note: We use the “Simple” recovery mode for non-production databases, and ‘Full’ for those in production. This may affect how much the transaction log size can be reduced, specifically, the time since the last SQL backup may affect the trans-log’s shrinkability when the database is set to use ‘Full’ recovery mode.

Here’s the same thing as a stored procedure.

  • Store hierachical organization data
  • All tables in a multi-tenant database would have a [OrganizationName] field.
  • The Organization table stores the hierarchical relationships for each organization.
  • SQL Server 2008+ supports the hierarchyID data type (not used here), which would make some of the hierarchical manipulations easier. I needed to support SQL Server 2005 as well, so I didn’t have the pleasure.

[C#] version of [dbo].[spSetContext]

Using uniqueidentifiers (Guids) as primary/foreign keys in SQL Server has its advantages and disadvantages. There are a lot of good discussions of uniqueidentifiers vs. integers as keys out there. We use uniqueidentifiers and the purpose of this example is to address a problem that some encounter using them with large and active databases.

One problem is that primary keys are typically clustered indexes (they are stored in sort order), so if the key for a new record isn’t sort-wise at the end of the index, then the server must move some number of records down to free a slot for the new key. In an extreme case, the server performance can degrade because it’s spending too much time churning the indexes.

Uniqueidentifiers are longer keys (than integers), requiring a bit more work from the server to sort, but the real issue is that uniqueidentifiers generated with newid() are random and therefore not guaranteed to fall at the end of the index. This can be a problem for large tables that experience frequent inserts.

SQL Server exposes the newsequentialid() function that guarantees that 1) a uniqueidentifier is sort-wise larger than the previously generated uniqueidentifier for that SQL instance, so the server can append to the end of the index and avoid the churn, and 2) it retains the uniqueness characteristics that make uniqueidentifiers desirable. The problem with newsequentialid() is that it’s not entirely convenient to use. SQL Server 2005 thru 2008 (and likely 2012) require that the function only be used as a default value for a column.

So while you can do this (SQL 2008 example)…

[OK]
declare @id uniqueidentifier = newid();

This won’t work…
[NO!]
declare @id uniqueidentifier = newsequentialid();

So, if newsequentialid() can only be used as a default for a column and therefore you can only set it when inserting a new record and *not* including that field in the insert statement, then how can you get the value for that column in the newly inserted record?! Sometimes you need it and sometimes you don’t. The example shows how to get the value for those times when you need it. Here’s the table definition, look at the use of newsequentialguid() in the default constraint in the last statement.

Insert a record like the statement below, and SQL Server sets the default values for the [Id] and [CreateDateTime] fields. The [CreateDateTime] receives a default value of the current SQL Server time. The [Id] receives a default value of a new sequential uniqueidentifier. This works!

insert [MyTable]([Namespace]) values ('MyNamespace');

Insert a record like the statement below, and SQL Server sets the default value for the [CreateDateTime] field and you’re supplying the value for the [Id] field.
This solves the first problem (you know the value of [Id]), but creates another problem… the value for [Id] isn’t a sequential uniqueidentifier.

Insert a record like the statement below, and SQL Server sets the default values for the [Id] and [CreateDateTime] fields (good so far) and the new record’s [Id] can be retrieved by using a table variable

Now you’ve got the best of both worlds! Here’s a stored procedure that sort of side-steps the issue with newsequentialid().
Even though a stored procedure isn’t always convenient, it works.

Wouldn’t it be great to turn this stored procedure into a function?! Yes it would, but it won’t work because of SQL’s side-effecting rules.
If you try something like this…
[NO!]

… you’re rewarded for you efforts with the following message

A C# SQL CLR Solution
Here’s an alternate method, using a C# CLR assembly. This is a “Visual C# SQL CLR Database Project For SQL Server 2005-2008″, these project types have some limitations in terms of what libraries they can reference, they’re restricted to using .Net Framework 3.5 SP1, and they induce registration and versioning headaches outside of those with regular T-SQL schema statements.

I put some info at the end regarding registration of the DLL with SQL Server. It’s a little different with 2005 and 2008, and depending on what you’re doing, you may have to deal with assembly trust issues. If you have the energy and patience to get over the initial hump, then a CLR assembly solution just might be the thing for you.

The C#
The SeqGuid class implements the behavior and is called by the Common class, which is called by a SQL database object. The Common class is the one to which SQL objects are pointed (more on that below).

T-SQL CLR Assembly Registration (arcane incantations)

If that worked, then create database objects that call the CLR function. You should see the assembly in the Programmability->Assemblies under your database in SQL Server Management Studio. Keep in mind that your case may require more or less work for registration. There’s usually at least one wrench in the gears to remove

If all went to plan, the new C# function should be callable from T-SQL
select [dbo].[fNewSequentialGuid]() --as a regular function that returns a scalar
or
select [Id] from [dbo].[tfGetNewSequentialGuid]() --as a table-valued function that returns a single-column, single-row table

Note: In cases where a CLR function is to be called between databases, or even instances (requires a linked server to be defined), you may have to wrap the SQL object
for it to be usable. I don’t know why, and there may be another really easy configuration solution for this, but I never got down to the brass tacks of the issue.

 

 

A Unix timestamp is defined as the number of seconds elapsed between January 1, 1970 00:00:00 and a given date/time expressed in Universal Coordinated Time.
A timestamp can be generated up to the date 2038-1-19 3:14:7 before overflowing a 32-bit integer.
http://en.wikipedia.org/wiki/Unix_time

An alternative, encoding a DateTime into a BigInt and back again.

Using setvar in T-SQL

There are many more female names in the census data from which this dataset was generated, so statistically the resultset is likely to be lop-sided. If this matters, then extra steps should be taken to balance the M to F ratio.

random

“Random” SQL database backup (random.zip)