Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
label
Posting Yak Master
197 Posts |
Posted - 2004-03-08 : 10:38:35
|
Here's the problem: 1. Someone gives me a partnumber. That partnumber could look like this: "MGPM-32-SW92-X90"2. I need to return a patternCode that corresponds with that Partnumber. That patternCode may look like this "2139"3. I have a search_table that narrows down which patternCode it might be from 2000 to about 2-7 possible pattern codes. Once I have those Possible matches, I go to step 4.4. In the database, I have a couple of tables that are relevant. Table 1:sdb_pattern_blockRevelant ColumnsPattern_Code - It's what I'm looking for. Block_ID - for each block_index that's a part of a pattern_code, there's a unique block_id assigned to it.Block_Index - the order in which each block_id comes in the stringIn this table, some relevant results for a single pattern code might be: Pattern BlockId Blockindex2139 11253 02139 11259 12139 11258 22139 11252 32139 11257 42139 11256 52139 11255 62139 11254 7 Table 2:sdb_block_valuerelevant columns: Block_Id (links to sdb_pattern_block.block_id)Value_Code (is part of the part number string Value_Index (is the order in which the value comes inside it's block_index)Some relevant data with the block_index thrown in from the sdb_pattern_block table for a single pattern Code would like this this.BlockID Blockindex ValueCode Valueindex11253 0 MGPM 011259 1 12 011259 1 16 111259 1 20 211259 1 25 311259 1 32 411259 1 40 511259 1 50 611259 1 63 711259 1 80 811259 1 100 911258 2 011258 2 N 111258 2 TF 211252 3 - 011257 4 10 011257 4 20 111257 4 25 211257 4 30 311257 4 40 411257 4 50 511257 4 75 611257 4 100 711257 4 125 811257 4 150 911257 4 175 1011257 4 200 1111256 5 011256 5 - 111255 6 011255 6 Y59A 111255 6 Y59AL 211255 6 Y59AZ 311255 6 Y59B 411255 6 Y59BL 511255 6 Y59BZ 611255 6 Y69A 711255 6 Y69AL 811255 6 Y69AZ 911255 6 Y69B 1011255 6 Y69BL 1111255 6 Y69BZ 1211255 6 Y7BAL 1311255 6 Y7BAZ 1411255 6 Y7BW 1511255 6 Y7BWL 1611255 6 Y7BWV 1711255 6 Y7BWVL 1811255 6 Y7BWVZ 1911255 6 Y7BWZ 2011255 6 Y7NW 2111255 6 Y7NWL 2211255 6 Y7NWV 2311255 6 Y7NWVL 2411255 6 Y7NWVZ 2511255 6 Y7NWZ 2611255 6 Y7P 2711255 6 Y7PL 2811255 6 Y7PV 2911255 6 Y7PVL 3011255 6 Y7PVZ 3111255 6 Y7PW 3211255 6 Y7PWL 3311255 6 Y7PWV 3411255 6 Y7PWVL 3511255 6 Y7PWVZ 3611255 6 Y7PWZ 3711255 6 Y7PZ 3811255 6 Z73 3911255 6 Z73L 4011255 6 Z73Z 4111255 6 Z76 4211255 6 Z76L 4311255 6 Z80 4411255 6 Z80L 4511254 7 3 011254 7 4 111254 7 211254 7 S 3 As you can see there are multiple possible values for most block_ids/indexes. The sql for that is: SELECT a.block_id, block_index, value_code, value_indexFROM sdb_block_value ajoin sdb_pattern_block bon a.block_id=b.block_id and pattern_code in ('2139')order by block_index, value_indexNow, I have no idea when someone enters a partnumber which part of the string corresponds with which index in a given pattern code. So, the only way I can think to solve this problem is this: 1. Grab all data for possible pattern code matches. 2. Compare all of the values in the first block_index from the first pattern_code and see if any of the values matches with the partnumber. Psuedo code would be: select @curPartNumber=@curPartNumber + value_code from #temp where pattern_code=@curpattern and block_index=@curIndex and value_index=@curVindexif @curPartNumber=substring(@partnumber, 0, len(@curPartNumber)) begin set @isMatch_Value=1 end 3. If that matches, move up to the next block_index in the current patternCode and add to the @curPartNumber string the possible values in that index. If any of them match, continue. If none match, move to the next pattern code and start over. 4. Eventually, by adding one value at a time I should find a part number where all of the possible values will be in order and correspond with one of the patterncodes data I've got returned. If there's any way to perform this type of a search without Cursors, please let me know. My current SQL looks like this: CREATE PROCEDURE dbo.ap_get_pattern_from_partnumber @partnumber varchar(50)ASBegin set nocount on create table #temp (pattern_code varchar(6), block_index int, value_code varchar(20), value_index int) create table #temp2 (pattern_code varchar(6))insert into #temp SELECT pattern_code, block_index, value_code, value_index FROM sdb_block_value a join sdb_pattern_block b on a.block_id=b.block_id and pattern_code in ('2139', '2170', '2172', '2186') order by block_index, value_index--Grab distinct pattern codesDeclare cursID cursor for select distinct(pattern_code) from #temp Declare @curPattern varchar(6), @isMatch_Value bit, @isMatch_Block bit, @isMatch_Pattern bit, @curPartNumber varchar(50)set @isMatch_Value=0set @isMatch_Block=0set @isMatch_Pattern=0--Begin First Loopopen cursID fetch next from cursid into @curPatternwhile (@@fetch_status<>-1) Begin Declare Cursid2 cursor for select block_index from #temp where pattern_code=@curPattern Declare @curIndex int, @curmatch varchar, @minlength int set @curmatch='' set @minlength=0 --Begin Second Loop open cursid2 fetch next from cursid2 into @curIndex while (@@fetch_status<>-1) Begin Declare cursid3 cursor for select value_index from #temp where pattern_code=@curPattern and block_index=@curIndex Declare @curvIndex int --Begin Third loop Open cursid3 fetch next from cursid3 into @curVindex while (@@fetch_status<>-1) Begin select @minlength=len(value_code) from #temp where pattern_code=@curPattern and block_index=@curIndex and value_index select @curPartNumber=@curPartNumber + value_code from #temp where pattern_code=@curpattern and block_index=@curIndex and value_index=@curVindex if @curPartNumber=substring(@partnumber, 0, len(@curPartNumber)) begin set @isMatch_Value=1 end if @isMatch_value=1 Begin set @isMatch_value=0 fetch next from cursid3 into @curVindex set @isMatch_Block=1 end else begin set @isMatch_value=0 set @isMatch_Block=0 set @curPartNumber='' end end deallocate cursid3 if @isMatch_block=1 Begin set @isMatch_Pattern=1 fetch next from cursid2 into @curIndex end else Begin set @isMatch_pattern=0 set @isMatch_block=0 end end deallocate cursid2 if @isMatch_Pattern=1 begin insert into #temp2 select @curPattern end fetch next from cursid into @curPatternend deallocate cursidEnd |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2004-03-08 : 11:06:37
|
| >> Do I need cursors or not?No.(Without even reading the reast of the question).==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
 |
|
|
ehorn
Master Smack Fu Yak Hacker
1632 Posts |
Posted - 2004-03-08 : 11:08:51
|
| [code]--Create Tally Tablecreate table numbers ( n int)declare @n int; set @n = 0while @n <=1000begin insert into numbers select @n set @n = @n + 1endGOdeclare @part_no varchar(30)set @part_no = 'MGPM-32-SW92-X90'select *from( --parse the partnumber select NullIf(SubString('-' + @part_no + '-' , n , CharIndex('-' , '-' + @part_no + '-' , n) - n) , '') AS block from numbers where n <= Len('-' + @part_no + '-') AND SubString('-' + @part_no + '-' , n - 1, 1) = '-' ) djoin sdb_block_value bv on bv.value_code = d.blockjoin sdb_pattern_block pb on pb.block_id = bv.block_id and pb.pattern_code in ('2139')[/code] |
 |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2004-03-08 : 11:27:20
|
quote: Originally posted by nr >> Do I need cursors or not?No.(Without even reading the reast of the question).==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy.
That's because Nigel is clairvoyant Who is claire by the way?Brett8-) |
 |
|
|
label
Posting Yak Master
197 Posts |
Posted - 2004-03-08 : 11:38:06
|
quote: Originally posted by nr >> Do I need cursors or not?No.(Without even reading the reast of the question).
While that may or may not be true, your response in no way, shape or form helps me. |
 |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2004-03-08 : 11:42:15
|
quote: Originally posted by label
quote: Originally posted by nr >> Do I need cursors or not?No.(Without even reading the reast of the question).
While that may or may not be true, your response in no way, shape or form helps me.
So take it or leave it...Didn't Jay's response give you some insight, or not?Brett8-) |
 |
|
|
label
Posting Yak Master
197 Posts |
Posted - 2004-03-08 : 12:05:08
|
quote: Originally posted by ehorn
--Create Tally Table
Ok, I created the Numbers table and ran the following sqlselect *from( --parse the partnumber select NullIf(SubString('-' + @part_no + '-' , n , CharIndex('-' , '-' + @part_no + '-' , n) - n) , '') AS block from numbers where n <= Len('-' + @part_no + '-') AND SubString('-' + @part_no + '-' , n - 1, 1) = '-' ) djoin sdb_block_value bv on bv.value_code = d.blockjoin sdb_pattern_block pb on pb.block_id = bv.block_id and pb.pattern_code in ('2139', '2186', '2170', '2172')The results I got were these:[code]200 8991 7 200 NULL 200mm 2186 8991 Stroke NULL 4 1 -1Y59AZ 8994 5 Y59AZ NULL Y59AZ--Solid State, Gen. Purpose, 3 Wire NPN, Horizontal, 5M 2186 8994 Auto Switch NULL 9 1 0200 11257 11 200 NULL 200mm 2139 11257 Stroke NULL 4 1 -1Y59AZ 11255 3 Y59AZ NULL Y59AZ--Solid State, Gen. Purpose, 3 Wire NPN, Horizontal, 5M 2139 11255 Auto Switch NULL 6 1 0200 11361 3 200 NULL 200mm 2170 11361 Stroke NULL 5 1 -1Y59AZ 11353 3 Y59AZ NULL Y59AZ--Solid State, Gen. Purpose, 3 Wire NPN, Horizontal, 5M 2170 11353 Auto Switch NULL 7 1 0200 11367 7 200 NULL 200mm 2172 11367 Stroke NULL 5 1 -1Y59AZ 11364 3 Y59AZ NULL Y59AZ--Solid State, Gen. Purpose, 3 Wire NPN, Horizontal, 5M 2172 11364 Auto Switch NULL 8 1 0What are these results telling me? I'm still not sure which pattern code is the match out of the four I started with? |
 |
|
|
label
Posting Yak Master
197 Posts |
Posted - 2004-03-08 : 12:09:01
|
quote: Originally posted by X002548So take it or leave it...Didn't Jay's response give you some insight, or not?Brett8-)
A) There's nothing to "take" or "leave" from that statement as to this point I've simply been told I don't need cursors but have been given no explanation or examples of why I don't and how to solve the problem I've described. If I really can do this without Cursors, that's wonderful, but I'm totally unaware of how to go about returning the data I want any other way. B) I've plugged Jay's code in but the results I got back didn't seem to clear up the problem. Either I don't understand the results or there's been a breakdown in communication somewhere in me describing what I want back. |
 |
|
|
ChrisFretwell
Starting Member
43 Posts |
Posted - 2004-03-08 : 12:44:31
|
| For A: Cursors are considered 'bad' in sql. In almost every situation, a non-cursor solution is available and faster. That being said, if you've ever read any of the system sps created by MS, many use cursors (go ahead look at things like sp_helpdb, sp_helpindex - although in 2000 many of the older cursor based sps now use work and temp tables and fewer cursors). The few times cursors are the most useful are when you need to look at data in order and the behaviour of a specific record depends on the values of the previous or next record. If the code is wrapped in an application, the application usually takes care of this part. To save time, can you post ddl and dml code to create a sample set of data for both your tables, an input statement and the expected return results. It will save all of us time.chrisBack on topic, you should be able to replace your cursor with a series of statements. Exactly which ones, I need more time for to look at what you want. Meantime, and so as not to repeat returning exactly what Jay returned using different code, what was returned from Jay's code that you didnt want returned? Can you take Jay's code and figure out where its not exactly what you want and modify to do what you want? |
 |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2004-03-08 : 12:59:33
|
quote: Originally posted by label
quote: Originally posted by nr >> Do I need cursors or not?No.(Without even reading the reast of the question).
While that may or may not be true, your response in no way, shape or form helps me.
Sorry - to be so terse with my response - I meant to look at the problem a follow it with a longer response but got distracted.Also didn't realise this was a continuation of the other thread where I'd already made the pertinent comment.My fault - I now have to look though the thread to see if what I was going to post is valid or already said.==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
 |
|
|
label
Posting Yak Master
197 Posts |
Posted - 2004-03-08 : 13:04:04
|
quote: Originally posted by ChrisFretwell For A: Cursors are considered 'bad' in sql. In almost every situation, a non-cursor solution is available and faster.
Right, I do understand cursors are less than desirable and I try to avoid them whenever possible. (Much like Frames in Html/.NET ) However, my skills being somewhat limited in SQL there are times when I turn to cursors because I know no other way of solving the problem. quote: To save time, can you post ddl and dml code to create a sample set of data for both your tables, an input statement and the expected return results. It will save all of us time.
I can do better than that. I've created a new database, imported the two relevant tables, zipped them up and they are less than 2 megs. I'll be happy to email them to anyone wanting to attach the database and test it out. quote: Back on topic, you should be able to replace your cursor with a series of statements. Exactly which ones, I need more time for to look at what you want. Meantime, and so as not to repeat returning exactly what Jay returned using different code, what was returned from Jay's code that you didnt want returned?
I'm just not sure what to do with the data it spit out. I want returned a sinlge Pattern Code that my partnumber belongs to. If someone types in "MGPM80-200-Y59AZ" (which is the test partnumber I'm actually using here) I want the results to be "2139". |
 |
|
|
label
Posting Yak Master
197 Posts |
Posted - 2004-03-08 : 13:08:18
|
quote: Originally posted by nrSorry - to be so terse with my response - I meant to look at the problem a follow it with a longer response but got distracted.Also didn't realise this was a continuation of the other thread where I'd already made the pertinent comment.My fault - I now have to look though the thread to see if what I was going to post is valid or already said.
No problem at all. I'm genuinely grateful for any help anyone here can give. As you can tell, SQL is obviously not my strong suit. |
 |
|
|
ehorn
Master Smack Fu Yak Hacker
1632 Posts |
Posted - 2004-03-08 : 16:08:53
|
| label,Sorry for the long delay in getting back to this. I have a few questions if you are still working to resolve this without using cursors:Given the following example: Part number = MGPM-80-200-Y59AZ1.) Is a part number "block" always seperated by a "-" ? ie this part number contains blocks 0-32.) Does sdb_pattern_block.Block_Index correlate to the position of the block in the part number? ie.match value code of "MGPN" with a value code were block_index = 0 then move onto "80" with block_index=1, etc.. until we find a pattern_code that meets all these patterns/blocks... |
 |
|
|
label
Posting Yak Master
197 Posts |
Posted - 2004-03-08 : 16:49:50
|
quote: Originally posted by ehorn label,Sorry for the long delay in getting back to this. I have a few questions if you are still working to resolve this without using cursors:
No problem on the delay. However, I solved the problem using .NET, where I'm a ton more comfortable. I simply put the results of each pattern code's data into it's own Datatable and stuck all those datatables into a Dataset, set up some simple logic and got it to work in about 30-40 lines or so instead of the 100+ of my stored proc. Thanks for everyone's suggestions and advice, they are always appreciated. |
 |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2004-03-09 : 10:43:10
|
| I think we would all be interested in your solution....Brett8-) |
 |
|
|
label
Posting Yak Master
197 Posts |
Posted - 2004-03-09 : 19:46:29
|
quote: Originally posted by X002548 I think we would all be interested in your solution....
No problem. I'll post it here tommorrow. I'm at home right now...(It's written in ASP.NET 1.1) |
 |
|
|
jsmith8858
Dr. Cross Join
7423 Posts |
Posted - 2004-03-09 : 20:30:33
|
| Label -- didn't I solve this one for you already?http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=28879why are you back to the cursor?also -- why don't you just tranform your data into a "Search table" one time, leave it like that, and then just search that table for your patterns? As part of your process, when your pattern data changes, you then just rebuld it, using a technique like the one I gave you? you shouldn't be rebulding your search data on every call ... do it only when the pattern data changes, otherwise it is a constant.- Jeff |
 |
|
|
label
Posting Yak Master
197 Posts |
Posted - 2004-03-11 : 08:10:11
|
Ok, as promised here's the .NET Function that returns a patterncode from any given partnumber Private Function get_pattern_code(ByVal partnumber As String) As String 'This section just does a very quick search that returns just the 1-8 possible canidates rather than searching through all 2000 of them '***************************************************************** Dim curSearch As String Dim dashIndex As Integer = partnumber.IndexOf("-", 0) If dashIndex = 6 Then curSearch = partnumber.Substring(0, (partnumber.IndexOf("-", 0) + 1)) ElseIf partnumber.Length <= 6 Then curSearch = partnumber Else curSearch = partnumber.Substring(0, 6) End If Dim DS As DataSet = eDB.get_search_tables(curSearch) '***************************************************************** 'If only one table was returned, that's our winner '***************************************************************** If DS.Tables.Count = 1 Then Return DS.Tables(0).TableName & "_" & DS.Tables(0).Rows(0).Item("model") End If Dim dt As DataTable Dim dr As DataRow Dim curvalue As String Dim curPattern As String = "" Dim curModel As String = "" Dim valueLength As Integer = 0 Dim curIndex As Integer = 0 Dim nextIndex As Integer = 0 Dim blockMatch As Integer = -1 Dim isReq As Boolean = True Dim wasReq As Boolean = True Dim isMatch As Boolean = False Dim goNext As Boolean = False Dim Temp_Partnumber As String = "" Dim Search_Partnumber As String = partnumber 'Loop through the datatables in memory and return Pattern Code '***************************************************************** For Each dt In DS.Tables curPattern = dt.TableName.ToString curModel = dt.Rows(0).Item("model") curIndex = 0 Temp_Partnumber = "" For Each dr In dt.Rows nextIndex = dr.Item("block_index") curvalue = dr.Item("value_code") valueLength = (Temp_Partnumber.Length + curvalue.Length) isReq = CType(dr.Item("block_isrequired"), Boolean) isMatch = False 'Make sure the length of the partnumber we're about to check is smaller/the same length as the part we're searching for '*************************************************************************************** If valueLength <= Search_Partnumber.Length Then 'If we are moving up a block do this '*************************************************************************************** If (nextIndex > curIndex) And (goNext = True Or wasReq = False) Then goNext = False curIndex = nextIndex wasReq = isReq If Search_Partnumber.Substring(0, valueLength) = Temp_Partnumber & curvalue Then Temp_Partnumber = Temp_Partnumber & curvalue isMatch = True End If If isMatch = True Then goNext = True End If ElseIf (nextIndex = curIndex) And goNext = False Then If Search_Partnumber.Substring(0, valueLength) = Temp_Partnumber & curvalue Then Temp_Partnumber = Temp_Partnumber & curvalue isMatch = True End If If isMatch = True Then goNext = True End If End If 'Check to see if we have a final match '*************************************************************************************** If Search_Partnumber = Temp_Partnumber Then Return curPattern & "_" & curModel End If End If Next Next Return "" End FunctionThe actual code that builds the string and handles all the logic once the tables are returned as you can see is only about 20-30 lines and it returns the patterncode almost instantly everytime so all in all I'm pretty pleased. |
 |
|
|
label
Posting Yak Master
197 Posts |
Posted - 2004-03-11 : 08:27:56
|
quote: Originally posted by jsmith8858 Label -- didn't I solve this one for you already?http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=28879
Looking back at that thread, the problem I had was simliar but a little different than the current one I just solved. In that thread I was looking to populate a table with all the possible partnumbers that were contained in a given patterncode (which could be anywhere from 30-300 variations). The Union query you gave me returned these results:2001@ - 52001@ - 92001@ - 112001@ 10 42001@ 10 62001@ 100 62001@ A 102001@ B 102001@ C 02001@ C 72001@ D 12002 - 52002 - 82002 - 102002 10 42002 10 62002 3 122002 6 42002 B 32002 B 92002 C 02002 D 12002 D 32002 D 7 That's not the type of results I need. I was needing results like this: ABCDEFACCDEFADCDEFABDDEFACDDEFADDDEGIn other words, fully formed partnumbers representing every possible permuation of a given set of data. Currently though I'm not trying to do that. My current problem is that I need to return a single pattern code from a partnumber (which may be partial). It's kind of the inverse of the problem I had before. Someone feeds my a partnumber (which is what we were trying to build the last time around from a patterncode) and I return which Patterncode that partnumber belongs to keeping the following in mind. 1. The values have to be in the proper order according to the blockindexs of a pattern. 2. Some blockindexs are required, others are not. 3. In some blockindexes you may have values that might match the current block and the next block so once a block finds a match, it cannot match on another value from that block again. The code I posted is able to navigate through those blocks and in real time determine if the current value being evaluated matches all of those criteria or not. quote: why are you back to the cursor?
Mostly out of ignorance of a better solution. SQL is not my first language. .NET is and so I sometimes find myself turning to less than ideal solutions in SQL when I can't figure out any other way to do it. quote: also -- why don't you just tranform your data into a "Search table" one time, leave it like that, and then just search that table for your patterns?
Because the resulting search table would be well over 2 billion records from all pattern codes. Besides, storing every variation of a fully formed partnumber from every pattern code would seem to be a very ineffecient method of housing the data when I can currently house all the possible permuations of all the pattern codes in a mere 13,396 rows. I see no reason to try and express every potential of those permuations when I can by my code above, analyze the values where they are and return what I need without searching through a megatable of all the possible partnumbers. Also, these partnumbers are always changing so I'd be rerunning that query to populate the table all the time. quote: you shouldn't be rebulding your search data on every call ... do it only when the pattern data changes, otherwise it is a constant.
The way I'm doing it now is that I'm only getting the basic, unassembled block values for a select few pattern codes and evaluating their potentials dynamically without ever having to express every possible permutation of a partnumber. I hope that helps clear up some of my thinking. If I'm not understanding some of your questions or points, please feel free to question or challenge my logic as I always enjoy improving my skills and learning more. Thanks. |
 |
|
|
|
|
|
|
|