Click here to Skip to main content
15,886,840 members
Articles / Database Development / SQL Server

Generating Insert or Update statements from table data using SQL Server

Rate me:
Please Sign up or sign in to vote.
4.69/5 (26 votes)
13 Nov 2007CPOL8 min read 314.1K   3.9K   52   55
Writing a SQL script to generate insert or update scripts for a table full of data.

Source Code Output

Introduction

Shifting data around is a requirement for every developer and DBA. Whether it is building (or rebuilding!) a database, migrating data for releases, or just creating test data, I at least always seem to be opening a new query page and typing in 'insert into ....'. I know that SQL Server 2005 has great little widgets for creating insert statements based off the table, but what I have always needed was a way to generate an update or insert statement based on data in an existing table in a different database. Sometimes, a DTS / BCP import/export job is too much work when there is only one or two rows, or maybe you can't get a file anywhere near the server because of security restrictions. Maybe you just like doing things the hard way.

What you need is a T-Script which will read the contents of a table, then create update / insert statements for that data to go into the same table in a different server and database. This can be run wherever you have a query window, and you don't need to create a Stored Procedure or install any programs.

Background

I've always had little scripts written for specific tables, but on request from a friend, I decided to get serious and create a one-size-fits-all SQL generator which will generate a line of SQL for each row in a source table, which, when run on the target database, will perfectly replicate the data. I know there are tools around to do this, but this is quick and very easy. It also will generate either for a specific row of text, or simply for all rows in the source table. I think it is a very useful little script to have in the 'My SQL Helpers' folder.

Using the code

The first port of call for a project like this is the system tables. I've always loved the system tables, which are one of those weird circumstances where the structure of the product you are using is described by metadata within the product. Like Reflection and other self-describing metadata, you can get a bit chicken-and-egg if you think about it for too long.

The first thing you need to do is get a list of the columns within the target table and the data type of each of those columns. This is done with a pretty simple piece of SQL:

SQL
SELECT so.name, sc.name, st.name, sc.length
, Case when sc.status = 0x80 then 'Y' else 'N' END as IsIdent
, ColOrder
FROM sysobjects so
INNER JOIN syscolumns sc
  ON so.id= sc.id 
INNER JOIN systypes st
  ON sc.xtype = st.xusertype 
WHERE so.Name = 'SourceTableName'
ORDER BY ColOrder

This will give you the list of columns within a source table, in the same order they are in the database. This is the basic structure needed to get the data out. The tricky column with the Case statement checks the Status binary column and generates a Y/N depending on whether or not the column is an identity column - which we will come to later.

The problem with getting the information out is that we are working in looping sets - which is difficult to do in SQL Server (well, pre .NET anyway). In order to collate the results needed, a temporary table will be created. This temporary table will contain the actual output of the script. Another temporary table is created as a staging point for the data which is in each column.

SQL
create table #output (Line varChar(4000), LineOrder int)
-- Holds the output for the script

create table #ColumnValues (ColName varChar(250), ColOrder int, RowNumber int
                           ,ColValue varchar(4000), ColType varchar(50)) 
 -- Holds the values for each column/row combination

Working out the algorithm

The basic algorithm is:

for each column in the source table

  if the column is not an identity column

    insert into the #ColumnValues table the column name 
           and the value from the source table
  end if
end for


for each row in the #ColumnValues table
   while each column in the table belonged 
   to the same row in the source table
   concatenate the update/insert statement 
   together into a string variable

   end while

   at the end of each column set for a row

   if an insert statement desired

     create the insert statement specific text

   else
    create the update statement specific text

   end if
end for


select all rows from the #Output table

This basic algorithm has some complicated parts when translated into T-SQL - the most conceptually difficult is selecting the values from a particular column in a table. The problem is that you need dynamic SQL - no problem there - but you need to store the result into some type of variable. You can't use locally declared T-SQL @ variables because they are not in the scope of the dynamic SQL. This is why a temporary table is used instead. This can be used in the dynamic SQL, which looks like this:

SQL
exec ('insert into #ColumnValues (ColName, ColOrder, ColValue, ColType)

select ''' + @colName + ''', ' + @ColOrder + '
      , Convert(nvarchar(4000),' + @colName + ') , ''' + @colType +''' 
from ' + @tabName + ' order by ' + @SortCol + ' ' + '
declare @counter int
set @counter = 0 ' + '
update #ColumnValues Set @Counter = RowNumber = @Counter + (' + @numCols + ' * 10)
where ColName = ''' + @colName + '''' )

This rather scary looking piece of code does a couple of things. The @colName variable is taken from the cursor loop, and is simply the name of the column in the source table (as is @colType and @tabName). The code works one column at a time across the table - like learning to read - left to right, down to the next row and on and on... The insert statement takes the value read from the specific column of the source table and inserts the value read from the source table into the temp table (#columnValues). The next line declares a counter and then incrementally assigns the RowNumber of the source table - this is to keep all the columns of the same row together - otherwise, the results would be all over the place, with the values in different columns matched with the wrong primary keys - a bit like a board game accidentally bumped and all the pieces in the wrong place. The last update statement uses the very oblique Set @value = Column = @Value + number syntax - a bit of a hidden secret of SQL Server which allows you to update a running counter for each row in a table. You can either try and work out how it works, or accept that it does and move on.

The row counter is then used a bit later on when creating the insert/update statement from the values in the #ColumnValues table. It is used as a loop switch so the code knows when the first column finishes and the next one ends. This is because the structure of the original table:

row1 : col1 col2 col3 col4 
row2 : col1 col2 col3 col4

is now represented in a table as:

row1 col1
row1 col2
row1 col3
row1 col4
row2 col1
row2 col2
etc....

The row counter (@RowNumber) is checked after each column in a post-loop check, to determine whether or not we have switched rows - i.e., from row1 to row2. At each row switch reading from the table, the insert/update statement is finished off and a new one is started. Each time an insert/update statement is finished off, it is inserted into the results table. When the script is finished, all of the statements are read from the temporary table, and the result will give you a nice list of insert statements which can then be executed into the server/database of your choice (providing, of course, that the exact same table definition exists in that database).

To run the script, simply load it up in Query Editor or SQL Server Manager. Edit the @tab variable to the name of the source table, and type in 'INSERT' or 'UPDATE' into the @StatementType variable. If you wish to do an update statement or wish to do a single-row insert statement, put in the value of the Primary Key column for the table (currently, this only works with a single column primary key) and the name of the column which is the primary key.

Source Code Example

The above example shows the script ready to run an all - rows set of insert statements for a table called 'PaymentStatusTest'.

This is the structure of the 'PaymentStatusTest' table:

Example Table Column list

Execute the script, and then copy out the results from the query results window into the location of your choice. It helps to run Query Editor as 'text' output.

Points of interest

This script can be easily expanded to take in more complex situations, such as generating a list of update statements for a table (although a delete all/insert might be better?), or for dealing with multiple primary keys, or for partial matching across primary keys. I also considered making the script detect the primary key automatically, but this adds a lot of complexity for very little benefit.

Anyone using SQL Server on a frequent basis should learn the in's and out's of the metadata built into the system tables - there is virtually nothing that can't be accomplished with a bit of tinkering, some lateral thinking, and clever script. You could also turn this into a Stored Procedure, but I prefer the instant edit and continue style of SQL Scripts.

Updates

  • 5/4/2007: Added in a second script to the download source, which puts in an extra step that collates the insert/update statements and writes them out so that there is one SQL statement per line of output. This is more useful when generating a large amount of statements for an entire table. Also added in support for varchar, char, and text fields, as per the feedback left.
  • 13/11/2007: I've fixed a couple of bugs which I found myself and were reported in the comments section. These include: ability to specify table owner, the last row being appended to the end of the second last row, not handling ' characters in the data. I've also added the features of allowing for insert statements to tables with identity columns, and put the ability to specify a 'where' clause to generate the insert/update statements for a subset of data in a table. I've also put in a small (commented out) section that will generate a progress report so that you know the script is still working for very large tables. Just uncomment the section and it will report every 5000 rows. I once ran it for 3 hours straight - thankfully, I have no DBA to report to! Thanks to everyone who has given me feedback and helped to make a better script.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Product Manager DNN Corp
Australia Australia
Bruce Chapman is the Product Manager for Cloud Services at DNN. He’s been an active member of the DNN Community since 2006 as a contributor, vendor and now employee of DNN Corp.

You can read his blog at http://dnnsoftware.com/blog or follow him on Twitter @brucerchapman

Comments and Discussions

 
QuestionWhere clause is empty when creating update statement..please help.. Pin
Member 141492475-Mar-19 0:10
Member 141492475-Mar-19 0:10 
QuestionError: Msg 137, Level 15, State 2, Line 1 Must declare the scalar variable "@colName". Pin
SharadSangle7-Aug-15 1:38
SharadSangle7-Aug-15 1:38 
QuestionHow could i create insert script using where condition instead of Primary key filter ? Pin
MohanDass171-Jul-13 1:31
MohanDass171-Jul-13 1:31 
QuestionYou are the best ! Pin
enseieh30-Dec-12 20:27
enseieh30-Dec-12 20:27 
Questionissues with smalldatetime field Pin
Frederick Jacob25-Oct-12 23:04
Frederick Jacob25-Oct-12 23:04 
AnswerRe: issues with smalldatetime field Pin
kuke14-Nov-12 18:45
kuke14-Nov-12 18:45 
SuggestionFew updates Pin
Andy Furnival18-Apr-12 3:31
Andy Furnival18-Apr-12 3:31 
This is a great script which over time I've improved upon to suit my needs, hopefully it will benefit others too. Some updates weren't done by me so I can't give credit

Added ordering in the columns to values selection prior to statement generation. Sometimes some crazy ordering goes on which means the generated statements don't match the original source data

Added new Data Type support
Added support for table schema (owner)
Added support for where clause
Added support to ignore the identity column

Bruce, I'm happy to send you this file if you want to include it as a download in your post.

Regards
Andy

SQL
/*
  SQL Server Row Script Creator
  Bruce Chapman Aug 2006
  iFinity.com.au

  This script will generate script to insert/update from a source table in one database to an 
  identical destination table in another database or server.  It can be run for inserts or updates,
  and can be run for a single row in insert and update mode, or all rows in a table for insert mode.

  This script is copyright to Bruce Chapman.  Please feel free to use it, modify it and pass it on, 
  on the condition that this copyright message is maintained in any copied or distributed version, 
  and that the original author be attributed for the work.
  
*/
declare @tab varchar(50)
       ,@pk1Val varChar(100)
	   ,@pk1Name varChar(50)
	   ,@qt char(1)
	   ,@StatementType varChar(10)
	   ,@tableWhereClause varchar(255)
	   ,@ignoreIdentityCol bit
	   ,@owner varchar(20)
set nocount on
/*
 Instructions:
 1) open script and connect to the source database
 2) Change the  variable values to change the output options for the script below (@tab, @statementtype etc)
 3) If you want a subset of the records, put the 'where' clause in as a straight 'where col = value'
 4) execute the script (best to use text output)
 5) copy the script output into a script window, and run on the destination table.
 

@Tab = the name of the source table
@pk1Val = if selecting a single row or doing an update statement, the value of the primary key for that row
@pk1Name = if inserting a single row or doing an update statement, the name of the column for the primary key
@StatementType = either 'INSERT' to create an insert statement or 'UPDATE' for an Update statement
@ignoreIdentityCol = either 1 or 0.  1 means ignore the fact that the source/dest column is an identity column and 
                     preserve the identity values from the source table on the insert statements.
@owner = table owner (for dbo use 'dbo')
*/
select @tab = 'myTable', @pk1Val = '', @pk1Name = '', @StatementType = 'UPDATE', @ignoreIdentityCol = 0, @owner = 'dbo'
/* next line is the table where clause so the data can be selected from the source table*/
/* if you don't want any where clause, just leave it empty => '', but don't comment out the line */
select @tableWhereClause = ''


------------------DO NOT EDIT BELOW THIS LINE -------------------------
-----------------------------------------------------------------------
-----------------------------------------------------------------------
declare @tabName varchar(50)
      , @colName varchar(50)
      , @ColType varchar(50) 
      , @collength varChar(50)
	  , @colOrder int
	  , @IsIdent char(1)
	  , @wasIdent bit
	

create table #output (Line varChar(max), LineOrder int, RowNumber int)
create table #ColumnValues (id int identity(1,1) primary key, ColName varChar(250), ColOrder int, RowNumber int, ColValue varchar(max), ColType varchar(50))

declare @out varchar(max)
       ,@lineCounter int
	   ,@ColValue varchar(max)
	   ,@sortCol varchar(50)

--/* get the ordering column */
select  @sortCol = sc.name
from sys.objects so
inner join sys.columns sc
on so.object_id=  sc.object_id
inner join systypes st on sc.system_type_id = st.xusertype 
inner join sys.schemas ss ON so.schema_id = ss.schema_id
where so.name = @tab  and ss.name = @owner
 and ((sc.is_identity = 1) OR (sc.column_id = 1 and not sc.is_identity = 0 ))
 
 print @sortCol --debug code
 
/* put in the repeating values based on the columns*/
declare objCurs CURSOR FOR 
select so.name, sc.name, st.name, sc.max_length, Case when sc.is_identity = 1 then 'Y' else 'N' END as IsIdent, column_id
from sys.objects so
inner join sys.columns sc
on so.object_id=  sc.object_id
inner join systypes st on sc.system_type_id = st.xusertype 
inner join sys.schemas ss ON so.schema_id = ss.schema_id
where ss.name = @owner and so.name = @tab and sc.name <>'timestamp'


DECLARE @counter int, @numCols int, @RowNumber int, @LastRowNumber int, @maxRowNumber int, @maxColOrder int

select @numCols = count(sc.column_id) 
from sys.schemas ss
inner join sys.objects so  ON so.schema_id = ss.schema_id
inner join sys.columns sc on so.object_id=  sc.object_id
where ss.name = @owner and so.name = @tab and sc.name <>'timestamp'

print @numCols  --debug code

open objCurs
Fetch from objCurs
into @tabName, @colName, @ColType, @collength, @IsIdent, @colOrder

while @@fetch_status = 0
begin
	SET @counter = 0
	/* get the value from the table */
	if @IsIdent = 'N' or @ignoreIdentityCol = 1
	BEGIN
	
		/* increase better type handling by inserting more case statments, handling different data types */
		if datalength(@pk1Name) = 0 or datalength(@pk1Val) = 0
		begin
			/* getting all rows in the table */
			
			
			exec ('insert into #ColumnValues (ColName, ColOrder, ColValue, ColType) 
					select  ''' + @colName + ''', ' + @colOrder + ', Convert(nvarchar(max),' + @colName + ') , ''' + @ColType + ''' from ' + @owner +'.'+ @tabName + ' ' + @tableWhereClause + ' order by ' + @sortCol + ' ' +
				  ' declare @counter int set @counter = 0 ' +
				  ' update #ColumnValues Set @counter = RowNumber = @counter + (' + @numCols + ' * 10) where ColName = ''' + @colName + '''' )
		end
		else
		begin
		
			exec ('insert into #ColumnValues (RowNumber, ColName, ColORder, ColValue, ColType)
					select 0, ''' + @colName + ''', ' + @colOrder + ', Convert(nvarchar(max),' + @colName + ') , ''' + @ColType + ''' from ' + @owner +'.'+ @tabName + 
				  ' where ' + @pk1Name + ' = ' + @pk1Val + ' order by ' + @sortCol  ) 
		end 


	end /* if @isIdent = 'n' */
	if @IsIdent = 'Y'
		set @wasIdent = 1
	
	Fetch Next from objCurs
	into @tabName, @colName, @ColType, @collength, @IsIdent, @colOrder
end 


select @maxRowNumber = Max(RowNumber) from #ColumnValues --keep highest row number so we know when we are finished
select @maxColOrder = max(ColOrder) from #ColumnValues where RowNumber = @maxRowNumber

/* next cursor for outputting the results from the retval table into the output table */
declare ColVal_Curs  cursor for
select ColName , ColOrder , RowNumber , ColValue , ColType 
from #ColumnValues
order by RowNumber, ColOrder
declare @curRowNum int, @curLineNum int
open ColVal_Curs

--set the last row number to the first in the table, so post loop checking works
select @LastRowNumber = min(RowNumber) from #ColumnValues 
set @lineCounter = @LastRowNumber --initialise at the first row

fetch from ColVal_Curs into
@colName, @colOrder, @RowNumber, @ColValue, @ColType

while @@Fetch_status = 0
BEGIN /* cursor loop */

		/* get the quote type to enclose the value from the column type */
		select @qt = case @ColType
					 when 'nvarchar' then ''''
					 when 'nchar' then ''''
					 when 'varchar' then ''''
					 when 'char' then ''''
					 when 'datetime' then ''''
					 when 'ntext' then ''''
					 when 'xml' then ''''
					 else ''  
					 end 


		
		/* replace any quotes with double quotes */
		if not @ColValue is null 
			SET @ColValue = replace(@ColValue, '''', '''''')
		else
			/* remove the quote value if the value is null, because we won't insert it */
			if @qt = ''''
				set @qt = ''

		if @RowNumber = @lineCounter
			select @out = case @StatementType
							when  'UPDATE' THEN 'Update ' + @owner + '.'+ @tab + ' SET '
							when  'INSERT' then 'INSERT INTO ' + @owner + '.'+ @tab + ' ('
						  end 
		begin
			if @StatementType = 'UPDATE' 
			BEGIN 
				select @out = @out + @colName + ' = ' + @qt + COALESCE(@ColValue, 'NULL') + @qt + ',' -- + @ColType 
				insert into #output (Line, LineOrder)
				values (@out, @lineCounter)

				if @pk1Val = ''
					if @pk1Name = @colName
						select @pk1Val =  @qt + @ColValue + @qt

			end 
			if @StatementType = 'INSERT' 
			BEGIN 
				/* put comma in */
				if @lineCounter > @RowNumber --not first line in set of values for row
					select @out = @out + ','
				
				/*put in the name of the column */
				insert into #output (Line, LineOrder)
				values (@out + @colName
					  , @lineCounter)

				if @lineCounter > @RowNumber --not first line in set of values for row 
					select @out = ','
				else
					select @out = ''
				/* put in the value of the column */
				insert into #output (Line, LineOrder)
				values (@out + @qt + COALESCE(@ColValue, 'NULL') + @qt 
					  , @lineCounter + 10 + @numCols)
			
			END 
		end  /*not @ColValue is null */
	select @lineCounter = @lineCounter + 1
	set @out = ''
/* keep the current counters for further processing after the fetch*/
set @curRowNum = @RowNumber
set @curLineNum = @lineCounter -1 

/* If it is a long-running process, then uncomment the following section
   to get a progress report.  The count will go to number of columns * number of rows 
   On a 422,000 row table with 10 columns, it took 3 hours to create
   the output script, but it did finish OK.  Having a progress report
   stops you from thinking it is busted and cancelling the execution.
*/
/*
  if ((@curLineNum % 5000) = 0) OR (@curLIneNum = 1)
	select @curLineNum, GetDate()
*/

/* get the next record*/
	fetch from ColVal_Curs into
	@colName, @colOrder, @RowNumber, @ColValue, @ColType
--select @ColOrder, @MaxColOrder, @@Fetch_Status  --debug code
	if (@RowNumber > @LastRowNumber) or (@RowNumber = @maxRowNumber and @maxColOrder = @colOrder and @@FEtch_Status = -1)
	BEGIN
	/* this bit of processing is done whenever the set of columsn in a row changes to the next row of the original table*/
	/* ie we are building a record to insert, and the PK changes because we are at the next record */
		/* remove the last comma from the last line */
		declare @lastLine int
		if @StatementType = 'UPDATE'
		begin
			/*remove last comma*/
			update #output
			set Line = left(Line,datalength(Line)-1)
			where LineOrder = @curLineNum

			/* insert a 'where' clause */
				insert into #output (Line, LineOrder)
				select ' WHERE ' + @pk1Name + ' = ' + @pk1Val, Max(LineOrder) + 1 from #output

		end
		if @StatementType = 'INSERT'
		BEGIN
			/* put in a 'values' statement between the column names and the column values */
			insert into #output (Line, LineOrder)
			values (') VALUES (', @curRowNum + @numCols + 5)
			/* close off the lot */
			insert into #output (Line, LineOrder)
			select ')', Max(LineOrder) + 1 from #output
		END 
		set @LastRowNumber = @RowNumber
		set @lineCounter = @RowNumber  /* reset linecounter for next set */
		update #output
		set RowNumber = @curRowNum
		where RowNumber is null


	End /* if RowNumber > last row number */

end /* cursor loop */

close objCurs
deallocate objCurs

close ColVal_Curs
deallocate ColVal_Curs


/* the following is an extra loop over the original code to output the code as one statement per row */
create table #combineOutput (RowNumber int, line varchar(max))

if @ignoreIdentityCol = 1 and @wasIdent = 1
	insert into #combineOutput (RowNumber, line)
	values (-1000, 'set identity_insert ' + @tabName + ' on')

/* get the statements out from the list*/
declare @output varchar(max), @codeLine varchar(max), @thisRowNum int, @lastRowNum int
select @output = ''
declare line_curs cursor for 
select Line, RowNumber  from #output order by RowNumber, LineOrder

open line_curs
fetch from line_curs into @codeLine, @thisRowNum
select @lastRowNum = @thisRowNum
while @@fetch_status = 0
begin
	if @thisRowNum > @lastRowNum
	BEGIN
		/* insert a row into the aggregate table if a new row number */
		insert into #combineOutput (RowNumber, line) values (@RowNumber, @output)
		set @output = ''
	END 
	select @output = @output + @codeLine + ' '
	select @lastRowNum = @thisRowNum
	fetch from line_curs into @codeLine, @thisRowNum
end
/* the last row needs to be inserted */
insert into #combineOutput (RowNumber, line) values (@RowNumber, @output)

close line_curs
deallocate line_curs

if @ignoreIdentityCol = 1 and @wasIdent = 1
	insert into #combineOutput (RowNumber, line)
	values (10000000, 'set identity_insert ' + @tabName + ' off')

select line as [/*Copy and paste code from below*/] from #combineOutput order by RowNumber

/*  bug tracking code - uncomment to diagnose problems
select distinct RowNumber from #ColumnValues order by 1
select * from #ColumnValues
order by RowNumber, ColOrder, ColName, ColValue
*/
drop table #output
drop table #combineOutput
drop table #ColumnValues
set nocount off

GeneralThanks Pin
Amol_B7-Feb-12 1:28
professionalAmol_B7-Feb-12 1:28 
NewsVery good! Pin
Claudio Barca4-Nov-11 1:42
Claudio Barca4-Nov-11 1:42 
GeneralMy vote of 5 Pin
Joshi, Rushikesh28-Sep-11 15:57
professionalJoshi, Rushikesh28-Sep-11 15:57 
GeneralMy vote of 5 Pin
andalmeida15-Sep-10 15:41
andalmeida15-Sep-10 15:41 
GeneralPerfect!!! Pin
robertschoenstein12-Nov-09 7:07
professionalrobertschoenstein12-Nov-09 7:07 
GeneralExactly What I Needed!!! Pin
kungFuCrab16-Sep-09 9:27
kungFuCrab16-Sep-09 9:27 
GeneralExcellent Work...Thanks a lot.. Pin
Ibru Kutti1-Jul-09 20:09
Ibru Kutti1-Jul-09 20:09 
GeneralGreat Stuff Pin
Sporgod23-Feb-09 9:57
Sporgod23-Feb-09 9:57 
GeneralRe: Great Stuff Pin
Mahin Gupta28-Mar-09 1:19
Mahin Gupta28-Mar-09 1:19 
QuestionBinary and varbinary datatyped values not visible properly Pin
venkat7be28-Dec-08 21:43
venkat7be28-Dec-08 21:43 
GeneralNeed modification - does not handle [percent] Pin
Greg Leepart25-Nov-08 11:49
Greg Leepart25-Nov-08 11:49 
GeneralRe: Need modification - does not handle [percent] Pin
Bruce Chapman DNN4-Dec-08 13:06
professionalBruce Chapman DNN4-Dec-08 13:06 
QuestionRows chopped off Pin
Richard Karstrom1-Oct-08 10:07
Richard Karstrom1-Oct-08 10:07 
AnswerRe: Rows chopped off Pin
Bruce Chapman DNN1-Oct-08 19:13
professionalBruce Chapman DNN1-Oct-08 19:13 
GeneralRe: Rows chopped off Pin
Richard Karstrom2-Oct-08 7:00
Richard Karstrom2-Oct-08 7:00 
Generalbit more control [modified] Pin
meaningoflights30-Aug-08 15:11
meaningoflights30-Aug-08 15:11 
Generalmessage Pin
AshwiniatCode14-May-08 4:40
AshwiniatCode14-May-08 4:40 
GeneralPerformance and timestamp issue + suggestion Pin
mgroetan22-Apr-08 1:04
mgroetan22-Apr-08 1:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.