views:

87

answers:

6

Sorry for the poor question wording I wasn't sure how to describe this. I want to iterate through every row in a table and while doing so, extract a column, parse the varchar that is in it and depending on what it finds insert rows into another table. Something along the lines of this:

DECLARE @string varchar(max);
foreach row in (select * from Table) {
    set @string = row[column];
    while (len(@string) > 0) {
        -- Do all the parsing in here

        if (found what was looking for)
            insert into Table2 values(row[column2], row[column3]);
    }
}

It would be really nice for this to be a stored procedure so for it to be done in SQL. I'm just not too sure on how to approach it. Thanks.

Edit:

This is basically the functionality I was hoping for:

Table 1   |
id_number | text    |
1           Hello, test 532. Yay oh and test 111   
2           test 932.
3           This is a test 315 of stuff test 555.
4           haflksdhfal test 311 sadjhfalsd
5           Yay.

I want to go through this table and parse all of the text columns to look for instances of 'test #' where # is a number. When it finds something inside of the text in that format it will insert that value into another table like:

Table 2   |
id_number | number
1           532
1           111
2           932
3           315
3           555
4           311
+1  A: 

The feature you are looking for is called a CURSOR - here is an article on how to use them.

They are considered bad for performance and difficult to use correctly.

Rethink your problem and restate it so it can be solved in a set based operation.

Look at using table variables or sub queries for your complex condition.

Oded
Oh thanks! I am a bit new to writing more advanced SQL statements other than some relatively intermediate stored procedures.
Bob L
Hmm, okay. So you think there is a better way to do this without cursors?
Bob L
@Bob L - I urge you to think about solutions that don't require cursors. Temp tables and sub-queries can help with difficult where conditions. Lookup both terms.
Oded
Okay thanks for the suggestions.
Bob L
@Oded - The problem is it would be nice to do it as Mark Byers mentioned however the parsing is hard. I want to check through a paragraph stored in the column like:Hello, test 521, test 431, end.And insert into a different table the 521 and 431. From what I see about cursors this may be the only solution.
Bob L
@Bob L - use a table variable. You can insert ids and data into it, parse and update it and use the results. As @Mark Byers said, you are stuck thinking procedurally instead of set based.
Oded
A: 

You're after a cursor - see the MSDN docs here. Note that cursors should be avoided wherever possible - there are very few places that they're appropriate and can result in slow inefficient code - you're usually better off trying a set-based solution.

Will A
+4  A: 

You are thinking procedurally instead of set based. You can probably write the whole thing as a single query:

INSERT INTO target_table (column list)
SELECT (column list)
FROM source_table
WHERE (parse your column) = (some criterion)

It is much easier to write, and probably a lot faster too.

If your parsing function is complicated, you can use put it into a user defined function instead of embedding it directly into the query.

Mark Byers
The parsing criteria is a bit too advanced and can contain many different things so the where part would not work but thanks for the suggestion.
Bob L
@Bob L: At face value, what you want is a cursor. But SQL is SET based, and depending on the parsing criteria - more than capable of working within Mark's answer. I find a very persistent issue with people thinking they're in procedural/OO programming land, and what them struggle to kludge together something that works... while it performs horribly. Details, even if abstracted, are good for us to help you in your goal. Maybe you do only need a cursor - I'd like to know more about your needs before I vote for someone's answer.
OMG Ponies
I see what you mean. I added some information about what I am trying to achieve.
Bob L
OMG Ponies
@OMG Ponies - As you see from the edit it's a bit more complicated than a 1-1 insert this if somethings true. This is why I don't know how to approach it.
Bob L
@OMG Ponies - Alright thanks for all the help, greatly appreciated.
Bob L
OMG Ponies
@OMG Ponies - hahaha yeah this is getting A LOT more complicated than I was hoping :P I do appreciate all the help though, people are very thorough.
Bob L
A: 

To do this as you request, with iteration you can do it using a Cursor, using your sample information below is how a cursor is laid-out. You put your row-by-row process where my comment is.

DECLARE @CurrentRecord VARCHAR(MAX)

DECLARE db_cursor CURSOR FOR  
SELECT Column
FROM Table 

OPEN db_cursor   
FETCH NEXT FROM db_cursor INTO @CurrentRecord

WHILE @@FETCH_STATUS = 0   
BEGIN   
       --Your stuff here

       FETCH NEXT FROM db_cursor INTO @name   
END   

CLOSE db_cursor   
DEALLOCATE db_cursor

However, depending on what you are doing, and if this is something that you do on a regular basis. I would recommend seeing if you can extract the parsing out to a User Defined Function, then you could make it set based, and not use a cursor. As a cursor should be a "last ditch" effort.

Mitchel Sellers
+3  A: 

In SQL Server 2008 you can do this

WITH testTable AS
(
SELECT 1 AS id_number, N'Hello, test 532. Yay oh and test 111' AS txt UNION ALL
SELECT 2, N'test 932.' UNION ALL
SELECT 3, N'This is a test 315 of stuff test 555.' UNION ALL
SELECT 4, N'haflksdhfal test 311 sadjhfalsd' UNION ALL
SELECT 5, N'Yay.'
)

SELECT id_number,display_term
FROM testTable
CROSS APPLY sys.dm_fts_parser('"' + REPLACE(txt,'"','""') + '"', 1033, 0,0)
WHERE TXT IS NOT NULL and 
  display_term NOT LIKE '%[^0-9]%' /*Or use LIKE '[0-9][0-9][0-9]' to only get 3 
                                     digit numbers*/

Returns

id_number   display_term
----------- ------------------------------
1           532
1           111
2           932
3           315
3           555
4           311
Martin Smith
I see, I mentioned in a comment above that, the example I gave was the most forward one, where there can be much more inside the text like:'Hello 31 this is a test ver412 of manliness.' or 'Test-135 yay' or '351 31 test 31 392' which would just be 31.
Bob L
Okay this is actually much closer to what I am trying to accomplish however, I think I can work the rest of the criteria out and edit what you've shown (I guess just by chaining OR's to try and cover a variety of possibilities. Thanks!
Bob L
@Bob - I think ver412 would trip it up for sure (if the desired result is that the 412 should be extracted?). I think @gbn's should cope with that fine though.
Martin Smith
Hmmm looking at his response I am not sure how it would cope with all the variants of data input. I think this one will suffice, having it be able to wade through wrong input to try and make sense out of it would have been nice but if the input is wrong I think I will just let it stay as wrong. Thanks again for your suggestion.
Bob L
+2  A: 

Something like this is you always have "Test (number)". It works on SQL Server 2005+

DECLARE @Table1 TABLE (id_number int, textcol nvarchar(MAX))

INSERT @Table1 VALUES (1, 'Hello, test 532. Yay oh and test 111')
INSERT @Table1 VALUES (2, 'test 932.')
INSERT @Table1 VALUES (3, 'This is a test 315 of stuff test 555.')
INSERT @Table1 VALUES (4, 'haflksdhfal test 311 sadjhfalsd')
INSERT @Table1 VALUES (5, 'Yay.')


;WITH cte AS
(
    SELECT TOP 9999 CAST(ROW_NUMBER() OVER (ORDER BY c1.OBJECT_ID) AS varchar(6)) AS TestNum
    FROM sys.columns c1 CROSS JOIN sys.columns c2
)
SELECT id_number, TestNum FROM
    cte
    JOIN
    @Table1 ON PATINDEX('%Test ' + TestNum + '[^0-9]%', textcol) > 0
                    OR textcol LIKE '%Test ' + TestNum
ORDER BY
    id_number
gbn