Posts
83
Comments
600
Trackbacks
40
July 2006 Entries
T-SQL HTML? Parser

EDIT:  Ok, so as is pointed out in the comments below SQL Server comes with a very powerful XML Parser already OPENXML and sp_xml_preparedocument.  I posted a code snipet in the comments I got from BOL so you can see how it works.  While my routine operaes in a different manner, it seems to have been an exercise in futility...but it was fun writing it...annd hey maybe it will come in hany.  Who knows.

A poster over at SQLTeam asked a question on how to “read“ xml data from a string.  Now I had always toyed with the idea of parsing XML data so it could be loaded in to a normalized database.  We had already implemented here in prouction, the delivery of data to a Java front in XML format (for which the developers were very happy), but we never did the reverse.  Now this code below assumes that the xml data will not be malformed (i.e. there is no checking) and that the “elements“ of the xml are 1 per tag.  They all do not have to be there, so nulls would be inserted, it can have more or different tags, but they will get ignored, and if more than 1 “element“ tag type exists, the last one wins.  To modify this for more or different tags, you will only have to modify the IF/ELSE IF code block, and the dynamic sql component.  Happy Coding.

USE Northwind
GO

CREATE TABLE myTable99(fname char(20), lname char(30), phone char(20))
GO


DECLARE @xml varchar(8000), @data varchar(8000), @tag varchar(255), @sql varchar(8000)
, @fname char(20), @lname char(30), @phone char(20)
SET @xml = '<fname>Brett</fname><lname>Kaiser</lname><phone>555-1234<phone>'
SELECT @tag = '', @data = ''

WHILE LEN(@xml) <> LEN(@tag+@data+@tag)+3
  BEGIN
 SELECT @tag=SUBSTRING(@xml,CHARINDEX('<',@xml), CHARINDEX('>',@xml))
 SELECT @data = SUBSTRING(@xml,LEN(@tag)+1,CHARINDEX('<',@xml,LEN(@tag))-LEN(@tag)-1)
 
      IF @tag = 'fname'
  SELECT @fname = @data
 ELSE IF @tag = 'lanme'
  SELECT @lname = @data
 ELSE IF @tag = 'phone'
  SELECT @phone = @data
 
 SELECT @xml = SUBSTRING(@xml,LEN(@tag+@data+@tag)+2,LEN(@xml)-LEN(@tag+@data+@tag)+2)
 
 SELECT @xml,@fname,@data,@tag,LEN(@xml),LEN(@tag+@data+@tag)+2
  END

SELECT @tag=SUBSTRING(@xml,CHARINDEX('<',@xml), CHARINDEX('>',@xml))
SELECT @data = SUBSTRING(@xml,LEN(@tag)+1,CHARINDEX('<',@xml,LEN(@tag))-LEN(@tag)-1)

     IF @tag = ''
 SELECT @fname = @data
ELSE IF @tag = ''
 SELECT @lname = @data
ELSE IF @tag = ''
 SELECT @phone = @data

SELECT @sql = 'INSERT INTO myTable99(fname,lname,phone) '
  + 'SELECT ''' + RTRIM(@fname) + ''''
  + ',' + ''''  + RTRIM(@lname) + ''''
  + ',' + ''''  + RTRIM(@phone) + ''''
SELECT @sql

EXEC(@sql)

SELECT * FROM myTable99
GO

DROP TABLE myTable99
GO

posted @ Thursday, July 27, 2006 2:29 PM | Feedback (6)
Generate Fixed width Format Cards (New Version)

Thought I lost this...so I figured I better post it.  It will create format cards for all tables in the database.

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

drop procedure [dbo].[isp_GenFormatCards]

GO

CREATE PROC isp_GenFormatCards

AS

DECLARE FormatCard CURSOR FOR

SELECT FORMAT_CARD, TABLE_NAME, TABLE_SCHEMA FROM (

/*

SELECT '--' + TABLE_NAME AS FORMAT_CARD

, TABLE_NAME, null AS COLUMN_NAME, 0 AS SQLGroup, 1 AS RowGrouping

FROM INFORMATION_SCHEMA.Tables

WHERE TABLE_TYPE = 'BASE TABLE'

UNION ALL

*/

SELECT '7.0' AS FORMAT_CARD

, TABLE_NAME, TABLE_SCHEMA, null AS COLUMN_NAME, 1 AS SQLGroup, 1 AS RowGrouping

FROM INFORMATION_SCHEMA.Tables

WHERE TABLE_TYPE = 'BASE TABLE'

UNION ALL

SELECT CONVERT(varchar(5),MAX(ORDINAL_POSITION)) AS FORMAT_CARD

, c.TABLE_NAME, c.TABLE_SCHEMA, null AS COLUMN_NAME, 2 AS SQLGroup, 1 AS RowGrouping

FROM INFORMATION_SCHEMA.Columns c

INNER JOIN INFORMATION_SCHEMA.Tables t

ON c.TABLE_NAME = t.TABLE_NAME

AND c.TABLE_SCHEMA = t.TABLE_SCHEMA

AND TABLE_TYPE = 'BASE TABLE'

GROUP BY c.TABLE_NAME, c.TABLE_SCHEMA

UNION ALL

SELECT CONVERT(varchar(3),ORDINAL_POSITION)+CHAR(9)+'SQLCHAR'+CHAR(9)+'0'+CHAR(9)

+ CONVERT(varchar(5),

CASE WHEN DATA_TYPE IN ('char','varchar','nchar','nvarchar') THEN CHARACTER_MAXIMUM_LENGTH

WHEN DATA_TYPE = 'int' THEN 14

WHEN DATA_TYPE = 'smallint' THEN 7

WHEN DATA_TYPE = 'tinyint' THEN 3

WHEN DATA_TYPE = 'bit' THEN 1

WHEN DATA_TYPE IN ('text','image') THEN 0

ELSE 26

END)

+ CHAR(9)+'""'+CHAR(9)+CONVERT(varchar(3),ORDINAL_POSITION)+CHAR(9)+COLUMN_NAME AS FORMAT_CARD

, c.TABLE_NAME, c.TABLE_SCHEMA, null AS COLUMN_NAME, 3 AS SQLGroup, ORDINAL_POSITION AS RowGrouping

FROM INFORMATION_SCHEMA.Columns c

INNER JOIN INFORMATION_SCHEMA.Tables t

ON c.TABLE_NAME = t.TABLE_NAME

AND c.table_schema = t.table_schema

AND TABLE_TYPE = 'BASE TABLE'

WHERE ORDINAL_POSITION < (SELECT MAX(ORDINAL_POSITION)

FROM INFORMATION_SCHEMA.Columns i

WHERE i.TABLE_NAME = c.TABLE_NAME)

UNION ALL

SELECT CONVERT(varchar(3),ORDINAL_POSITION)+CHAR(9)+'SQLCHAR'+CHAR(9)+'0'+CHAR(9)+CONVERT(VARCHAR(5),

CASE WHEN DATA_TYPE IN ('char','varchar','nchar','nvarchar') THEN CHARACTER_MAXIMUM_LENGTH

WHEN DATA_TYPE = 'int' THEN 14

WHEN DATA_TYPE = 'smallint' THEN 7

WHEN DATA_TYPE = 'tinyint' THEN 3

WHEN DATA_TYPE = 'bit' THEN 1

WHEN DATA_TYPE IN ('text','image') THEN 0

ELSE 26

END)

+ char(9)+'"\r\n"'+char(9)+CONVERT(varchar(3),ORDINAL_POSITION)+CHAR(9)+COLUMN_NAME AS FORMAT_CARD

, c.TABLE_NAME, c.TABLE_SCHEMA, null AS COLUMN_NAME, 4 AS SQLGroup, 1 AS RowGrouping

FROM INFORMATION_SCHEMA.Columns c

INNER JOIN INFORMATION_SCHEMA.Tables t

ON c.TABLE_NAME = t.TABLE_NAME

AND c.TABLE_SCHEMA = t.TABLE_SCHEMA

AND TABLE_TYPE = 'BASE TABLE'

WHERE ORDINAL_POSITION = (SELECT MAX(ORDINAL_POSITION)

FROM INFORMATION_SCHEMA.Columns i

WHERE i.TABLE_NAME = c.TABLE_NAME)

)AS XXX

ORDER BY TABLE_NAME, COLUMN_NAME, SQLGroup, RowGrouping

DECLARE @Card varchar(200), @TABLE_NAME sysname, @TABLE_SCHEMA sysname, @cmd varchar(200), @x char(2), @Command_String varchar(8000)

, @TABLE_NAME_OLD sysname, @TABLE_SCHEMA_OLD sysname

SELECT @x = '> ', @TABLE_NAME_OLD = '', @TABLE_SCHEMA_OLD = ''

OPEN FormatCard

FETCH NEXT FROM FormatCard INTO @Card, @TABLE_NAME, @TABLE_SCHEMA

WHILE @@FETCH_STATUS = 0

BEGIN

SELECT @x = '>>'

IF @TABLE_SCHEMA+@TABLE_NAME <> @TABLE_SCHEMA_OLD+@TABLE_NAME_OLD

BEGIN

SELECT @TABLE_SCHEMA_OLD = @TABLE_SCHEMA

, @TABLE_NAME_OLD = @TABLE_NAME

, @x = '> '

END

SET @cmd = 'echo ' + @Card + ' '+ @x +' d:\Data\Tax\Format\'+@TABLE_SCHEMA+'_'+@TABLE_NAME+'.fmt'

SET @Command_string = 'EXEC master..xp_cmdshell ''' + @cmd + ''', NO_OUTPUT'

PRINT @Command_String

Exec(@Command_String)

FETCH NEXT FROM FormatCard INTO @Card, @TABLE_NAME, @TABLE_SCHEMA

END

CLOSE FormatCard

DEALLOCATE FormatCard

GO

 

--master..xp_cmdshell 'dir d:\Data\Tax\Format\*.*'

 

posted @ Thursday, July 06, 2006 2:18 PM | Feedback (2)