A Cunning Blog
The wily musings of a software developer

Converting CSV data to tabular form

Tuesday, 19 August 2008 15:11 by gary

I recently found myself needing to pass a non-fixed sized set of Ids from an application to a stored procedure. A standard approach is to pass this data as a character string, and then split it again within the stored procedure.

I've done this in the past, but on this occasion I couldn't quickly locate my old code, so gave in and wrote it again, afterall it's only a few lines. So for future reference I have reproduced it here:

CREATE FUNCTION [dbo].[udfSplitCsv] (@data varchar(5000))
    RETURNS @T TABLE (Id int)
AS
/*
 Takes a CSV string parameter and returns the data as a table of integers.
*/
BEGIN
     DECLARE @start int
     DECLARE @pos int
     DECLARE @part varchar(500)
     DECLARE @id int

     IF right(rtrim(@data),1) <> ',' SET @data = @data  + ','

    SET @start = 1
    SET @pos = charindex(',', @data, @start)

    WHILE @pos <> 0
    BEGIN
          SET @part = substring(@data, @start, @pos - @start)
          INSERT INTO @T VALUES (@part)
          SET @start = @pos + 1
          SET @pos = charindex(',', @data, @start)
    END

    RETURN
END

The resulting table data can be included in queries, for example, using Northwind:

select OrderId, CompanyName, Country from Orders As O
inner join Customers As C
   On O.CustomerID = C.CustomerID
inner join dbo.udfSplitCsv('10643,10692,10702,10926,10308') As I
   On I.Id = O.OrderId
Tags:   , ,
Categories:   SQL Server
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

Extension Methods

Tuesday, 6 May 2008 15:11 by gary
 

While writing a LINQ query, I really wanted to be able to combine instances of a string column. Of course the standard Sum methods are only designed for the numeric types. This was the prompt I finally needed to try my hand at writing an extension method.  

So let's start with an easy example.

using System;
using System.Text;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace CunningPlan
{
    /// <summary>
    /// Extension methods.
    /// </summary>
    public static class ExtensionLibrary
    {

        /// <summary>
        /// Returns the left most characters from a string.
        /// If the requested length is longer than the source string,
        /// or if it is less than zero,
        /// then the source string is returned unchanged.
        /// </summary>
        /// <param name="source">The original string</param>
        /// <param name="length">The number of characters required.</param>
        /// <returns>The 'N' left most characters from the source string.</returns>
        public static string Left(this string source, int length)
        {
            return (length <= source.Length && length > 0)
                   ? source.Substring(0, length) : source;
        }

        /// <summary>
        /// Tests the supplied string to see if it can be
        /// parsed as an integer
        /// </summary>
        /// <param name="source">String to check</param>
        /// <returns>True if an integer value.</returns>
        public static bool IsInteger(this string source)
        {
            int result = 0;
            return int.TryParse(source, out result);
        }
    }
}

Things to note are that the containing class, and the methods have to be static. Next notice how the this keyword is used, the source parameters in the above two examples give the methods a handle on the object instance upon which they will be executed. The use of the this keyword in this context, is akin to when writing a class indexer. You can now write code like:

    List<string> counties = new List<string>()
         { "Berkshire", "Hampshire", "Surrey" };

    string countySum = counties.Sum();

We now have the means to add methods to any classes we like, even sealed ones. That's easy enough, so how do I now extend LINQ to have a Sum() method for strings? Well, all we need to do is follow the same approach as before. This time the source object will be defined as an IEnumerable string collection. The first example below takes the supplied collection, and builds a single concatenated string, using the specified delimiter. The second simple overloaded method, gives us a csv answer.

    /// <summary>
    /// Returns a string summation/concatentaion.
    /// Where the source is empty, a blank string is returned.
    /// </summary>
    /// <param name="source">The set of strings to be 'summed'.</param>
    /// <param name="delimiter">The delimiter to be used.</param>
    /// <returns>The combined string, otherwise empty.</returns>
    public static string Sum(this IEnumerable<string> source, string delimiter)
    {
        if (source == null) return "";

        StringBuilder sb = new StringBuilder();
        int count = source.Count();
        int i = 0;

        foreach (string s in source)
        {
            sb.Append(s);
            if (++i < count) sb.Append(delimiter);
        }

        return sb.ToString();
    }

    /// <summary>
    /// Returns a string summation/concatentaion using a default comma seperator.
    /// If source is empty then a blank string is the result
    /// </summary>
    /// <param name="source">The set of strings to be 'summed'.</param>
    /// <returns>The combined string, otherwise empty.</returns>
    public static string Sum(this IEnumerable<string> source)
    {
        return Sum(source, ", ");
    }

With these methods added to the class, we can now produce summations of string collections. For example:

     List<string> counties = new List<string>()
         { "Berkshire", "Hampshire", "Surrey" };
   

    string countySum = counties.Sum(); 

But I wanted to incorporate my method in LINQ, so here's a simple example of that:     

NorthwindDataContext db = new NorthwindDataContext();   

string londonNames = (from c in db.Customers
                                         where c.City == "London"
                                         select c.CompanyName).Sum();

The answer returned being: 

"Around the Horn, B's Beverages, Consolidated Holdings, Eastern Connection, North/South, Seven Seas Imports"

Copenhagen

Tuesday, 4 March 2008 11:43 by gary

Saturday 1st March the 3.45am alarm sounds to remind me to get up, as we are off to Copenhagen from Stansted. Well while cheapflights still exist, it would be rude not to (thankyou Easyjet, just £50 each return).

Sadly Tivoli closes for the winter, and the Royal palace was hidden behind scaffolding, while the prehistoric section of the National Museum was also closed. But there was still much to see and explore. 

The new harbour area was attractive offering many bars and places to eat .. but a bit pricey, so we just a couple of drinks here before moving on.

This was also a great opportunity to experiment with my new Canon 10-22mm lens. As the sky was a lovely shade of grey I also tried a simple HDR technique. It certainly does give a different perspective.

 

Sadly the main city centre has become so cosmopolitan that you could just as easily be in London or Berlin. When I travel I like to sample some of the local atmosphere, but it seems to have been drown in a sea of theme bars, curry, burgers and pizza. 

During the afternoon, at one point we came across the protest march to mark the first aniversary of the  Jagtvej 69 (Youth House) evictions. Only time will tell if the continuing demostrations are successful.

By late afternoon, we were cold, wet & tired, so went to check into the hotel. Refreshed we headed out again for the evening, using the Metro to take us straight into the nicely lit centre.

We wandered past many a cafe or restaurant, but failed to locate any traditional food (except in the most expensive of establishments). Finally, we found what we were looking for.. just off the square by the RatHaus. So, 'Skipper labskovs' and 'Biksemad' were ordered, plus beer off course. The former being a Danish derivative of .... English (well Scouse) food. The second dish being a type of beef and potatoe hash dish. We retired that evening, suitably full.

The next morning we walked back into the city. We arrived at the Royal Palace in time for the ceremonial changing of the guard.  


Aside from the uniform colours, it was surprisingly like being outside a certain Royal Palace back home. Of course we also had to the little mermaid before returning home.

 

Tags:  
Categories:   Personal
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

Welcome

Tuesday, 4 March 2008 11:41 by Admin

Having decided it was about time I got to grips with blogging, I settled on using BlogEngine, as it's built with familiar technologies. Although a number of themes are provided, I still wanted a little personalisation. So I have created my own theme, by amending the Coffee House stylesheet and imagery.

Categories:  
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed