Category: Uncategorized

  • XMethods

    A cool web site listing free-to-access web serivces available on the Internet: xMethods.com

  • App_Offline.htm

    Cracking informational post from Scott Guthrie – and I can’t believe I’d never heard of this before!!

    Original post from Scott: http://weblogs.asp.net/scottgu/archive/2005/10/06/426755.aspx:

    Basically, if you place a file with this name in the root of a web application directory, ASP.NET 2.0 will shut-down the application, unload the application domain from the server, and stop processing any new incoming requests for that application. ASP.NET will also then respond to all requests for dynamic pages in the application by sending back the content of the app_offline.htm file (for example: you might want to have a “site under construction” or “down for maintenance” message).

    This provides a convenient way to take down your application while you are making big changes or copying in lots of new page functionality (and you want to avoid the annoying problem of people hitting and activating your site in the middle of a content update). It can also be a useful way to immediately unlock and unload a SQL Express or Access database whose .mdf or .mdb data files are residing in the /app_data directory.

    Once you remove the app_offline.htm file, the next request into the application will cause ASP.NET to load the application and app-domain again, and life will continue along as normal.

    And also worthy of note is that the returned content must be greater than 512kb, to get over an annoying anomoly within IE6. Simply flesh out the content of the file to greater than 512kb (use comments for example).

  • VSS Versioning, Merging and Branching

    When creating a new version of software in VSS there is a nifty feature called Branching that exposes some cool merging capabilities for retro-fixing issues.

    Firstly, share the files:
    Drag and drop the files from VSS UI into the new project folder:

    The files will appear with a little shortcut icon to show they are shared:

    Then Branch them
    Branching will only work on individual files, not folders and recursive items. To see all files and folders in a project in on go use the Wildcard search,, and choose all Subfolders optio

    After selecting the files, click the Branch buttonFinally, merge changes
    Change a file in the original source, and the differences can be easily merged into any of the branches that sprout from the original code. Select the altered file in VSS, right click and choose Merge Branches:

    The pop up window shows you all shared versions of the original file that will allow the changes to be merged into:

    Click Merge and a window will show the old version, the new version and assist with copying the changes across.

  • Compare contents of two tables.

    SET QUOTED_IDENTIFIER ON 
    GO
    SET ANSI_NULLS ON
    GO

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sp_CompareTables]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
    drop procedure [dbo].[sp_CompareTables]
    GO

    CREATE PROCEDURE sp_CompareTables
    @table1 sysname,
    @table2 sysname,
    @ColumnList varchar(8000) = '*',
    @Summary bit = 0,
    @Detail bit = 1,
    @TableNameHeader varchar(30) = '[Table Name]',
    @CounterHeader varchar(30) = '[Counter]',
    @rc int = null out
    AS
    ------------------------------------------------------------------------------
    --Compare the contents of two tables
    --@table1 and @table2 are the table names
    --@ColumnList is the list of column names, by default all columns will be compared
    --@Summary - set this to 1 it you want summary information
    --@Detail - set this to 1 (the default) if you want the details of the differences
    --@TableNameHeader - this is used as the column heading the a column that contains the table name
    --@CounterHeader - this is used as the column heading the a column that contains a row count
    --(this is used when there may be multiple identical rows
    --@rc - the number of rows that are different
    --Note: this SP can "live" in the master DB
    ------------------------------------------------------------------------------
    DECLARE @err integer,
    @SQL1 varchar(8000),
    @SQL2 varchar(8000),
    @SQL3 varchar(8000),
    @SQL4 varchar(8000),
    @SQLTop varchar(8000),
    @SQLBot varchar(8000),
    @SQLTop2 varchar(8000),
    @SQLBot2 varchar(8000),
    @ColumnGrouping varchar(8000),
    @indexlist varchar(8000)

    SET NOCOUNT ON

    -- a bit of validation first
    IF object_id(@table1) IS NULL
    BEGIN
    RAISERROR ('Table ''%s'' does not exist', 11, 1, @table1) WITH NOWAIT
    RETURN
    END

    IF object_id(@table2) IS NULL
    BEGIN
    RAISERROR ('Table ''%s'' does not exist', 11, 1, @table2) WITH NOWAIT
    RETURN
    END

    IF @table1 NOT LIKE '%.%'
    BEGIN
    SET @table1 = DB_NAME() + '..' + @table1
    END

    IF @table2 NOT LIKE '%.%'
    BEGIN
    SET @table2 = DB_NAME() + '..' + @table2
    END

    -- let's get a list of columns that have different collations ...
    CREATE TABLE #CollationColumns (name sysname)

    DECLARE @SQL varchar(8000)

    set @SQL = 'INSERT #CollationColumns SELECT a.name
    FROM %db1..syscolumns a
    INNER JOIN %db2..syscolumns b
    ON a.name = b.name COLLATE database_default
    WHERE a.id = object_id(''%t1'')
    AND b.id = object_id(''%t2'')
    AND a.collationid b.collationid'
    SET @SQL = replace(@SQL, '%db1', PARSENAME(@table1, 3))
    SET @SQL = replace(@SQL, '%db2', PARSENAME(@table2, 3))
    SET @SQL = replace(@SQL, '%t1', @table1)
    SET @SQL = replace(@SQL, '%t2', @table2)

    EXEC (@SQL)

    -- If the first table is in the current database
    -- we can look to see if there is a unique index
    IF PARSENAME(@table1, 3) = DB_NAME()
    BEGIN
    SET @indexlist = NULL

    SELECT @indexlist = COALESCE(@indexlist + ', ', '') + '[' + c.name + ']'
    FROM syscolumns c
    INNER JOIN sysindexkeys k ON c.colid = k.colid
    AND k.id = OBJECT_ID(@table1)
    AND c.id = k.id
    INNER JOIN sysindexes i ON i.id = k.id
    AND i.indid = k.indid
    WHERE i.indid = ( SELECT TOP 1 i.indid -- get the first unique index (favouring the clustered one)
    FROM sysindexes
    WHERE id = OBJECT_ID(@table1)
    AND INDEXPROPERTY(i.id,i.name, 'IsUnique') = 1
    AND INDEXPROPERTY(i.id,i.name, 'IsStatistics') = 0
    ORDER BY INDEXPROPERTY(i.id,i.name, 'IsClustered') DESC)
    ORDER BY k.keyno
    END

    IF @indexlist IS NULL AND @Summary = 1
    BEGIN
    RAISERROR ('Summary is not availabe as table ''%s'' has no unique index', 10, 1, @table1) WITH NOWAIT
    SET @Summary = 0
    END

    -- Let's generate a list of columns ...
    IF @ColumnList = '*' or @ColumnList = ''
    BEGIN
    -- we can only do this in the current database (this could be enhanced though)
    IF PARSENAME(@table1, 3) DB_NAME()
    BEGIN
    RAISERROR ('Table ''%s'' is not in the current database', 11, 1, @table1) WITH NOWAIT
    RETURN
    END
    SET @ColumnList = NULL
    SET @ColumnGrouping = NULL
    -- get a comma delimited list
    -- convert text and netxt to varchar(8000)
    -- convert image to binary
    SELECT @ColumnList = COALESCE(@ColumnList + ', ', '') + CASE
    WHEN systypes.name IN ( 'text' ,'ntext')
    THEN 'CONVERT(VARCHAR(8000),' + '[' + syscolumns.name + ']' + ') AS '
    WHEN systypes.name ='image'
    THEN 'CONVERT(BINARY,' + '[' + syscolumns.name + ']' + ') AS '
    ELSE ''
    END
    + '[' + syscolumns.name + ']'
    -- if the column has different collation the just use a database default
    + CASE WHEN syscolumns.name IN (SELECT name COLLATE database_default FROM #CollationColumns)
    THEN ' collate database_default AS [' + syscolumns.name + ']'
    ELSE ''
    END
    FROM syscolumns INNER JOIN systypes ON syscolumns.xusertype = systypes.xusertype
    WHERE ID = object_id(@table1)
    ORDER BY colid

    -- we need a similar list of columns for the GROUP BY clause
    SELECT @ColumnGrouping = COALESCE(@ColumnGrouping + ', ', '') + CASE
    WHEN systypes.name in ( 'text' ,'ntext')
    THEN 'convert(varchar(8000),' + '[' + syscolumns.name + ']' + ')'
    WHEN systypes.name = 'image'
    THEN 'convert(binary,' + '[' + syscolumns.name + ']' + ')'
    ELSE '[' + syscolumns.name + ']'
    END
    FROM syscolumns
    INNER JOIN systypes on syscolumns.xusertype = systypes.xusertype
    WHERE id = object_id(@table1)
    ORDER BY colid
    END
    ELSE
    BEGIN
    SET @ColumnGrouping = @ColumnList
    END

    DECLARE @Counter1 varchar(8000)
    DECLARE @Counter2 varchar(8000)

    -- if we have a unique index then we don't need a row count.
    IF @indexlist IS NULL
    BEGIN
    SET @Counter1 = 'COUNT (*) AS ' + @CounterHeader + ', '
    SET @Counter2 = @CounterHeader + ', '
    END
    ELSE
    BEGIN
    SET @Counter1 = ''
    SET @Counter2 = ''
    END

    -- here's the wizzy SQL (I will explain it sometime)
    SET @SQL1 = 'SELECT ' + @Counter1 + '''' + @table1 + ''' AS ' + @TableNameHeader + ', ' + @ColumnList + ' FROM ' + @Table1 + char(13)
    SET @SQL2 = ' GROUP BY ' + @ColumnGrouping + char(13)
    SET @SQL3 = ' UNION ALL SELECT ' + @Counter1 + '''' + @table2 + ''' AS ' + @TableNameHeader + ', ' + @ColumnList + ' FROM ' + @Table2 + char(13)
    SET @SQL4 = ' GROUP BY ' + @ColumnGrouping + char(13)
    SET @SQLTop = 'SELECT ' + @Counter2 + ' Max(' + @TableNameHeader + ') AS ' + @TableNameHeader + ', ' + @ColumnList + ' FROM (' + char(13)
    SET @SQLBot = ') A ' + CHAR(13) + ' GROUP BY ' + @Counter2 + @ColumnGrouping + CHAR(13) + ' HAVING COUNT(*) 2'
    SET @SQLTop2 = 'SELECT ' + @indexlist +
    ' , CASE COUNT(*) when 2 ' +
    ' THEN ''Different'' ' +
    ' ELSE ''Only in '' + max(' + @TableNameHeader + ') ' +
    ' END AS [Details] ' +
    ' FROM ( '
    SET @SQLBot2 = ') B GROUP BY ' + @indexlist

    -- now output the details
    IF @Detail = 1
    BEGIN
    EXEC (@SQLTop + @SQL1 + @SQL2 + @SQL3 + @SQL4 + @SQLBot)
    SET @rc = @@ROWCOUNT
    END

    IF @Summary = 1
    BEGIN
    EXEC (@SQLTop2 + @SQLTop + @SQL1 + @SQL2 + @SQL3 + @SQL4 + @SQLBot + @SQLBot2)
    SET @rc = @@ROWCOUNT
    END

    IF @rc = 0
    BEGIN
    RAISERROR ('Tables ''%s'' and ''%s'' are the same', 10, 1, @table1, @table2) WITH NOWAIT
    END
    ELSE
    BEGIN
    RAISERROR ('Tables ''%s'' and ''%s'' contain %d ''different'' rows', 10, 1, @table1, @table2, @rc) WITH NOWAIT
    END


    SET NOCOUNT OFF
    GO
    SET QUOTED_IDENTIFIER OFF
    GO
    SET ANSI_NULLS ON
    GO

  • Finding missing numbers in a sequence

    From http://www.sqlservercentral.com/articles/Datetime+Manipulation/61822/

    Find Missing Numbers

    It is obvious that, to find missing numbers, we need to have a table or resultset which contains all the numbers. Then we can apply a NOT IN clause and identify the missing numbers.

    If you are wondering, why I needed missing numbers, here is the reason. In one of my applications, there is an entity that we call coordinator. Each coordinator has a 4 digit numeric code. The code starts at 1000 and ends at 9999. (There is no chance that we will have more than 9000 coordinators at any point of time, so a 4 digit code is sufficient). When the user creates a new coordinator, the system automatically generates a new coordinator number. However, the user can still edit it. The system will allow the user to edit the coordinator number (during a new entry) as long as it does not produce a duplicate code.

    With the above functionality, we needed a way to reuse un-used/missing numbers. When we create a new coordinator, we need to find the lowest unused coordinator code. For this purpose we needed a way to identify the missing numbers.

    As mentioned earlier in this article, I did not want to keep a temp table. I want to generate the numbers on the fly. There are several ways to do this. I like to use a CTE to do this.

    In one of my previous articles, I had presented a way to generate a sequence of numbers by using a CTE. It was fast. But a faster code fragment was posted by Kathi Kellenberger in the discussion forum. It was taken from Itzik Ben-Gan’s book “Inside Microsoft SQL Server 2005 T-SQL Querying”. Here is the code fragment which generates 1 million records in the fraction of a second. [code]

    WITH
    L0 AS (SELECT 1 AS C UNION ALL SELECT 1), --2 rows
    L1 AS (SELECT 1 AS C FROM L0 AS A, L0 AS B),--4 rows
    L2 AS (SELECT 1 AS C FROM L1 AS A, L1 AS B),--16 rows
    L3 AS (SELECT 1 AS C FROM L2 AS A, L2 AS B),--256 rows
    L4 AS (SELECT 1 AS C FROM L3 AS A, L3 AS B),--65536 rows
    L5 AS (SELECT 1 AS C FROM L4 AS A, L4 AS B),--4294967296 rows
    num AS (SELECT ROW_NUMBER() OVER(ORDER BY C) AS N FROM L5)
    SELECT N FROM NUM WHERE N <= 1000000;

    This code is VERY VERY fast and I find it to be the best candidate for generating a sequence of numbers on the fly. I wanted to re-use this code and hence I created a function that takes a Minimum and Maximum value and returns a resultset containing sequence numbers within the given range. [code]

    CREATE FUNCTION dbo.GetNumbers
    (
    @Start BIGINT,
    @End BIGINT
    )
    RETURNS @ret TABLE(Number BIGINT)
    AS
    BEGIN
    WITH
    L0 AS (SELECT 1 AS C UNION ALL SELECT 1), --2 rows
    L1 AS (SELECT 1 AS C FROM L0 AS A, L0 AS B),--4 rows
    L2 AS (SELECT 1 AS C FROM L1 AS A, L1 AS B),--16 rows
    L3 AS (SELECT 1 AS C FROM L2 AS A, L2 AS B),--256 rows
    L4 AS (SELECT 1 AS C FROM L3 AS A, L3 AS B),--65536 rows
    L5 AS (SELECT 1 AS C FROM L4 AS A, L4 AS B),--4294967296 rows
    num AS (SELECT ROW_NUMBER() OVER(ORDER BY C) AS N FROM L5)

    INSERT INTO @ret(Number)
    SELECT N FROM NUM WHERE N BETWEEN @Start AND @End
    RETURN
    END

    Once we have the function to generate the sequence number, we can easily write the code to identify the missing numbers. [code]

        1 SELECT MIN(Number)

        2 FROM dbo.GetNumbers(1000, 9999)

        3 WHERE Number NOT IN (SELECT CoordinatorID FROM Coordinators)

    Find Missing Dates

    I guess the requirement to find missing dates must be more common than the missing number requirement I mentioned above. To find the missing dates (Dates at which no sales took place, Dates at which a given employ was absent etc) we need to have a table or resultset which contains all the dates within a given range.

    The following example shows how to generate a sequence of dates using the same logic we discussed earlier. [code]

    --Generate a sequence of all the dates for the month of October, 2007

    SELECT
    CAST('2007-10-01' AS DATETIME) + Number-1
    FROM dbo.GetNumbers(1, 30)
    --Generate a sequence of all the dates for year 2007

    SELECT
    CAST('2007-01-01' AS DATETIME) + Number-1
    FROM dbo.GetNumbers(1, 365)

    Once we have a sequence of dates, we can easily apply a NOT IN clause and find the missing dates based on the specific requirement.

  • Are you sitting comfortably?

    …Then we shall begin…

    Blogs are brilliant. There are a ton of brilliant contributors out there that make learning new technologies so simple. So i guess that it’s high time that I stop leeching so much information and start giving something back too.. I don’t expect too much interaction, this is more about logging my thoughts and findings, and if someone else can benefit from that, then great!

    So this blog is going to be about anything I wan (it’s mine after all)… expect information on .NET coding, Silverlight, WCF, ASP.NET (MVC, jQuery, Dynamic Data etc), Photography and so on.

    ..the name… well it appeared to be one of only a few that remained..damn bloggers…

  • Debugging Replication Errors

    use distribution
    --------------------------------------------------------------------------------
    select top 100 e.*, * from MSrepl_commands c inner join MSrepl_errors e on c.xact_seqno =e.xact_seqno order by e.id desc
    --------------------------------------------------------------------------------
    exec sp_replmonitorhelpsubscription @publisher=NULL, @publication_type=0
    --------------------------------------------------------------------------------
    exec sp_helpdistpublisher
    --------------------------------------------------------------------------------
    exec distribution..sp_replmonitorsubscriptionpendingcmds @publisher=pubservername, @subscriber=subservername, @publisher_db='pubdbname', @subscriber_db='subdbname', @publication='pubname', @subscription_type=0
    --------------------------------------------------------------------------------
    exec sp_replqueuemonitor @publisher = pubservername, @publisherdb = 'pubdbname', @publication = 'pubname', @tranid = NULL, @queuetype = 0
    --------------------------------------------------------------------------------
    exec sp_replshowcmds
  • Dropping Replication

    when struggling to drop a publication or subscription from the API, try one of these:

    use [SysTest_1]

    exec sp_dropsubscription @ignore_distributor =1,@publication = N'all', @subscriber=N'all',@article = N'all'

    exec sp_droppublication @publication = N'all',@ignore_distributor =1

    exec sp_removedbreplication 'systest_1'
  • Trusted Logins

    Trusted logins with IIS and IE6.

    Tools | Internet Options | Security Tab | Intranet Zone | Security Levels | Custom Level

    Scroll to the bottom of the list and make sure that User Authentication | Logon is set appropriately.