Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

About this user

Will Rickards http://willrickards.net/

« Newer Snippets
Older Snippets »
Showing 1-2 of 2 total  RSS 

Splitting an integer list in TSQL

Revised: 2006-02-23 - fixed various bugs by using new algorithm
Often times I have a list of integers I need to pass to the database to get worked on. Such as checkboxes on a web page or some other list. I needed some TSQL that would take a text string and split it by a separator, in this case a comma. The following is the result of that need.
The way I normally use it is in a stored procedure like the one below with several text type arguments. Sometimes I use a variation designed to split a list of strings separated by a special character sequence. Image two lists, one of the ids and one of the data. You parse the first list to get a table of the ids and you parse the second list to get the data and insert/update as appropriate.

IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[uspSplitIntegerList]') AND OBJECTPROPERTY(id, N'IsProcedure') = 1)
   DROP PROCEDURE [dbo].[uspSplitIntegerList]
GO
                                      
SET QUOTED_IDENTIFIER ON 
GO
SET ANSI_NULLS ON 
GO


/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-- uspSplitIntegerList
--
-- Description:
--		splits a comma separated list of integers and returns the integer list
--
-- Arguments:
--		@list_integers					- list of integers
--
-- Notes:
-- 02/22/2006 - WSR : use DATALENGTH instead of LEN throughout because LEN doesn't count trailing blanks
--
-- History:
-- 02/22/2006 - WSR : revised algorithm to account for items crossing 8000 character boundary
--
CREATE PROCEDURE uspSplitIntegerList
	@list_integers			text
AS

SET NOCOUNT ON

DECLARE @InputLen			integer			-- input text length
DECLARE @TextPos			integer			-- current position within input text
DECLARE @Chunk				varchar(8000)	-- chunk within input text
DECLARE @ChunkPos			integer			-- current position within chunk
DECLARE @DelimPos			integer			-- position of delimiter
DECLARE @ChunkLen			integer			-- chunk length
DECLARE @DelimLen			integer			-- delimiter length
DECLARE @Delimiter      varchar(3)		-- delimiter
DECLARE @ItemBegPos		integer			-- item starting position in text
DECLARE @ItemOrder		integer			-- item order in list

-- create table to hold list items
-- actually their positions because we may want to scrub this list eliminating bad entries before substring is applied
CREATE TABLE #list_items ( item_order integer, item_begpos integer, item_endpos integer )

-- process list
IF @list_integers IS NOT NULL
   BEGIN

	-- initialize
   -- notice that this loop assumes a delimiter length of 1
   -- if the delimiter is longer we have to deal with stuff like delimiters straddling the chunk boundaries
   SET @InputLen = DATALENGTH(@list_integers)
   SET @TextPos = 1
	SET @Delimiter = ','
	SET @DelimLen = DATALENGTH(@Delimiter)
   SET @ItemBegPos = 1
   SET @ItemOrder = 1
   SET @ChunkLen = 1

   -- cycle through input processing chunks
   WHILE @TextPos <= @InputLen AND @ChunkLen <> 0
      BEGIN

      -- get current chunk
      SET @Chunk = SUBSTRING(@list_integers, @TextPos, 8000)

      -- setup initial variable values
      SET @ChunkPos = 1
      SET @ChunkLen = DATALENGTH(@Chunk)
      SET @DelimPos = CHARINDEX(@Delimiter, @Chunk, @ChunkPos)

      -- loop over the chunk, until the last delimiter
      WHILE @ChunkPos <= @ChunkLen AND @DelimPos <> 0
         BEGIN

			-- insert position
         INSERT INTO #list_items (item_order, item_begpos, item_endpos)
         VALUES (@ItemOrder, @ItemBegPos, (@TextPos + @DelimPos - 1) - 1)
         
         -- adjust positions
         SET @ItemOrder = @ItemOrder + 1
         SET @ItemBegPos = (@TextPos + @DelimPos - 1) + @DelimLen
         SET @ChunkPos = @DelimPos + @DelimLen
      
         -- find next delimiter      
         SET @DelimPos = CHARINDEX(@Delimiter, @Chunk, @ChunkPos)

         END

      -- adjust positions
      SET @TextPos = @TextPos + @ChunkLen

      END

	-- handle last item
   IF @ItemBegPos <= @InputLen
      BEGIN

      -- insert position
      INSERT INTO #list_items (item_order, item_begpos, item_endpos)
      VALUES (@ItemOrder, @ItemBegPos, @InputLen)

      END

	-- delete the bad items
   DELETE FROM #list_items
   WHERE item_endpos < item_begpos

   -- return list items
	SELECT CAST(SUBSTRING(@list_integers, item_begpos, (item_endpos - item_begpos + 1)) AS integer) AS item_integer, item_order, item_begpos, item_endpos
   FROM #list_items
   WHERE ISNUMERIC(SUBSTRING(@list_integers, item_begpos, (item_endpos - item_begpos + 1))) = 1
   ORDER BY item_order

   END

DROP TABLE #list_items

RETURN

/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

GO
SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

Javascript IntegerBoxControl

In input forms on web pages you often have to validate input as an integer or more precisely a positive integer greater than zero. Here is a control implementation of sorts.

// Integer Box Control
// 
// Notes
// To create an integer box control, call the SetupIntegerBoxControl function.
// It should be passed an input element with type of text.
// The onchange event of the input element will invoke the validation function.
// The validation function ensures only positive integer data is entered.
//
// History
// 09/08/2005 - WSR : created based on dateboxcontrol

// hooks functionality up to given textbox
function SetupIntegerBoxControl( ctlIntegerBox )
   {

   // if a valid object was given
   if (ctlIntegerBox)
      {

      // validate current contents
      IntegerBoxControl_Validate( ctlIntegerBox );

      // hook up event handlers
      ctlIntegerBox.onchange = function () { IntegerBoxControl_Validate(this); };
      
      }

   }


// validates the input
function IntegerBoxControl_Validate( ctlIntegerBox )
   {

   // parse the input as an integer
   var intValue = parseInt(ctlIntegerBox.value, 10);

   // if this is not an integer
   if (isNaN(intValue))
      {

      // clear text box
      ctlIntegerBox.value = '';

      }
   // if this is an integer
   else
      {
   
      switch (true)
         {
         case (intValue == 0) :

            // clear text box
            ctlIntegerBox.value = '';

            break;
         case (intValue > 0) :

            // put the parsed integer value in the text box
            ctlIntegerBox.value = intValue.toString();

            break;
         case (intValue < 0) :

            // put the positive parsed integer value in the text box
            ctlIntegerBox.value = (-1 * intValue).toString();

            break;
         }
      
      }

   }


I forgot to mention before how to hook it up in code.
I usually add an attribute bvr-datatype="integer" to the input element. bvr stands for behaviour. I hook up the control in the onload event. Here is a recent example.
// set window load event handler
window.onload = window_load;

// ----------------------------------------------------------------------------
// window_load
// Description: event handler for window load event
// Arguments: none
// Dependencies:
//    SetupDateBoxControl (dateboxcontrol.js)
//    SetupIntegerBoxControl (integerboxcontrol.js)
//    frmSearch_submit
//    cmdRequesting_click
//    txtRequesting_change
//    frmRecent_submit
//
function window_load()
   {

   // get input elements in document
   var arrInputs = document.getElementsByTagName('INPUT');

   // cycle through input elements
   for ( var i = 0; i < arrInputs.length; i++ ) 
      {

      // if this is a datebox control
      if ( 'date' == arrInputs[i].getAttribute('bvr-datatype') && 'text' == arrInputs[i].getAttribute('type') )
         {

         // setup the control
         SetupDateBoxControl( arrInputs[i] );

         }

      // if this is a integerbox control
      if ( 'integer' == arrInputs[i].getAttribute('bvr-datatype') && 'text' == arrInputs[i].getAttribute('type') )
         {

         // setup the control
         SetupIntegerBoxControl( arrInputs[i] );

         }

      }

   // get reference to search form
   var elForm = document.getElementById('frmSearch');
   if (elForm)
      {

      // set submit event handler
      elForm.onsubmit = frmSearch_submit;

      // set cmdTimekeeperLookup click event handler
      var elToWire = document.getElementById('cmdTimekeeperLookup');
      if (elToWire)
         {

         elToWire.onclick = cmdRequesting_click;
         elToWire.textbox = document.getElementById('txtRequestingTimekeeper');

         // set textbox change events
         if (elToWire.textbox)
            {

            elToWire.textbox.onchange = txtRequesting_change;
            elToWire.textbox.onblur = txtRequesting_change;
            elToWire.textbox.label = document.getElementById('lblTimekeeperName');

            if ( typeof window.strRequesting == 'undefined' )
               window.strRequesting = ''; 

            }

         }

      }

   // get reference to recent form
   elForm = document.getElementById('frmRecent');
   if (elForm)
      {

      // set submit event handler
      elForm.onsubmit = frmRecent_submit;

      }

   }
//
// window_load
// ----------------------------------------------------------------------------
« Newer Snippets
Older Snippets »
Showing 1-2 of 2 total  RSS