SYTELINE  FORUMS
Go Back   SYTELINE FORUMS > SyteLine Technical Forums > IT & IS (Information Technology & Information Systems) > DBAs
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read
Welcome to the SYTELINE FORUMS.
You are currently viewing this forum as a guest, giving you limited access to our community. Please take a minute to register, it's fast, easy, and free! Members of Syteline Forums enjoy a lot of great features such as; the ability to post and create threads, ask questions, get or give advice, and share experiences. We invite you to join SyteLine Forums today!
DBAs For both Progress and SQL DBAs - ask, share, learn... Please be sure to mention the relevant Syteline version in your post.

Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old 11-20-2005, 09:05 AM
murphys's Avatar
murphys murphys is offline
Administrator
 
Join Date: Oct 2005
Posts: 6
murphys has disabled reputation
Default PROGRESS to T-SQL .. Making the shift.

Greetings everyone.

I'm writing this article in hopes of helping you PROGRESS gurus out there make the shift over to Microsoft's SQL Server and using T-SQL as your primary database programming language.

For the purpose of this article, we're going to "forget" that PROGRESS has a SQL-92 implementation, as I'm safe in saying that almost all of you used PROGRESS for what it is/was - a procedural (some say "imperative") 4GL.

Procedural. That's a key word. It's something that PROGRESS IS, and something that T-SQL IS NOT. T-SQL is a "declarative" langauge, and I'll explain the difference right now.

When you give a friend directions to your house, you might explain to them: "Go 2 miles south on 82nd Ave, turn right on Oak St, go 1 mile, then turn right on 64th Ave. My house # is 123, and it's on the left-side. Park on the street in front if the driveway is full."

What you've done here is procedural. You have some definitive control over the steps to accomplish the end goal of helping your friend arrive safely and efficiently to your home.

The declarative side of things can be best paralleled by when you order something off the 'net. You "declare" your shipping address, and the product just arrives. You don't need to give the FedEx driver specific instructions on finding your house - FedEx has their own internal processes and logic for figuring this stuff out. You simply issue a high-level command that is met with a result. End of story.

This is exactly how T-SQL works in comparison to PROGRESS. T-SQL produces sets of results. You work with data set-by-set instead of in PROGRESS where you may work with it record-by-record.

Now - T-SQL provides some procedural structures that may confuse you, and will have you tempted to use them. Things such as a CURSOR, or a DO...WHILE loop. When it comes to using these things, simply: DON'T. Unless it's absolutely necessary. Even then, 99.9% of the time, there is a declarative equivalent to the procedural path you're about to embark on. The reason we avoid these kinds of things in T-SQL is that they are SLOW. They will make your grandmother's driving seem on par with Richard Petty.

In T-SQL - you have to ditch your notions of a "CurrentRow" or "Looping through a set". There is nothing like this in T-SQL. You issue and command and get a set of results. If you can back yourself out of procedural thinking for awhile, you'll find the equivalant T-SQL code is usually shorter, and always faster.

Let's do a comparison of a common task. To paint the scenario, let's say our customer has implemented a new warehouse naming strategy, and as a result - needs to convert his old whse names into to new monikers. We have created a table with two fields: one to store the old whse value, and one to hold the new value. Our goal is to use this table as a "look-up" when sorting through standard Syteline tables to update the old values to new ones. In our example below, we'll focus on using this table to update the itemwhse table.

In PROGRESS, we'd do this:
Code:
for each conv_table no-lock: find first itemwhse where itemwhse.whse = conv_table.old_value. do while available(itemwhse): itemwhse.whse = conv_table.new_value. find first itemwhse where itemwhse.whse = conv_table.old_value. end. end.
Basically - we loop through the conv_table, and for each record - we search through the itemwhse table for the old value - and wherever we find it, we replace it with the new value.

Many of you, in your shift to T-SQL may try to implement the above code in a simliar, procedural fashion such as:
Code:
DECLARE @cOldVal varchar(50), @cNewVal varchar(50) DECLARE cOldNew CURSOR FOR SELECT Old_Value, New_Value FROM conv_table OPEN cOldNew FETCH NEXT FROM cOldNew INTO @cOldVal, @cNewVal WHILE @@FETCH_STATUS = 0 BEGIN UPDATE itemwhse SET itemwhse.whse = @cNewVal WHERE itemwhse.whse = @cOldVal FETCH NEXT FROM cOldNew INTO @cOldVal, @cNewVal END CLOSE cOldNew DEALLOCATE cOldNew
Phew! What a MESS!

If we can step-back, and abandon the notion of a current-row context, the proper, declarative way to write this is as follows:
Code:
UPDATE itemwhse SET itemwhse.whse = conv_table.new_value FROM itemwhse JOIN conv_table ON itemwhse.whse = conv_table.old_value

Much more simple, and produces the exact same results in substantially less time.

So - to sum up, the things you PROGRESS gurus need to keep in mind when shifting to T-SQL:

...T-SQL is NOT procedural. Stop thinking about code-flow, control structures, loops, etc. These things are procedural.
...Cursors and Looping in T-SQL are evil and slow.
...Stop thinking in the context of a "current record" and think more on a "complete result-set" level.

I hope this helps you out. Just FYI - my background is primarily SQL/VB. I have about 4 years of PROGRESS experience mixed in, but I've been typing SQL for the last 10 years.

If anyone has any questions, or needs a hand through anything - please feel free to ask!

Last edited by murphys : 11-20-2005 at 11:41 AM.
Reply With Quote
Sponsored Links
  #2  
Old 11-20-2005, 11:47 AM
murphys's Avatar
murphys murphys is offline
Administrator
 
Join Date: Oct 2005
Posts: 6
murphys has disabled reputation
Default

Also - remember this:

Progress vs. T-SQL.

It's NOT a competition about which is the "better" language. As far as I'm concerned - debates of this nature are simply religious discussions with little to no bearing in practical reality, and belong in the bit-bin with discussions such as RISC vs. CISC (or Mac vs. x86 PC for you non-geeks).

Remember - it's all about using the correct tool for the job at-hand.
Reply With Quote
  #3  
Old 11-20-2005, 01:32 PM
Walter Walter is offline
Syteline Forums Senior Member
 
Join Date: Nov 2005
Location: Oregon, US
Posts: 550
Walter is an unknown quantity at this point
Default

Very nice. I read about fetch being slow and to stay away from it.

How would you do equivalent of Progress FIND in a table you don't loop through?

for each itemwhse:

find job where job.item = itemwhse.item and ...

if available job then do.
end

else do something else

Thanks, Walter.

Last edited by Walter : 11-20-2005 at 01:35 PM.
Reply With Quote
  #4  
Old 11-20-2005, 04:25 PM
Derik's Avatar
Derik Derik is offline
Sr. Business Consultant
 
Join Date: Oct 2005
Location: Oregon
Posts: 483
Derik is on a distinguished road
Send a message via Yahoo to Derik
Default

It depends on what you want to 'DO' at the end...

Here is the code to join up the job to itemwhse...
select job.item
from job
join itemwhse
on job.item = itemwhse.item

but, in the end, it will depend on what action you want to take - and how it relates to the set of data you want to return...

If you are trying to see where there is no job tied to the item for the item whse, then you can use outer joins, etc...to demonstrate that those columns would be NULL in the result set, etc...

Hope that explains a little - keep the questions coming...

Derik
__________________
Derik Aldridge
President
ECI
www.eclipsepc.com

www.ecidynamics.com
Reply With Quote
  #5  
Old 11-21-2005, 07:09 AM
murphys's Avatar
murphys murphys is offline
Administrator
 
Join Date: Oct 2005
Posts: 6
murphys has disabled reputation
Default

Quote:
Originally Posted by Walter
Very nice. I read about fetch being slow and to stay away from it.

How would you do equivalent of Progress FIND in a table you don't loop through?

for each itemwhse:

find job where job.item = itemwhse.item and ...

if available job then do.
end

else do something else

Thanks, Walter.
Exactly what Derik said --

With T-SQL you have to get out of the record-by-record mindset...so it's rare that you'll actually be searcing for a single, specific record. You'll be searching for a group/set of records that conform to a specific criteria.

In your code above, take it conceptually up to the 50,000 ft overview level .. what you're trying to do is:

"Give me a list of jobs that have an equivalent item in the itemwhse table..."

... the SQL to produce such a result-set will contain an inner-join:

SELECT * FROM job JOIN itemwhse ON job.item = itemwhse.item

Quote:
Originally Posted by Derik
If you are trying to see where there is no job tied to the item for the item whse, then you can use outer joins, etc...to demonstrate that those columns would be NULL in the result set, etc...
Derik's example would be taken care of like so:

SELECT * FROM itemwhse LEFT JOIN job ON itemwhse.item = job.item WHERE job.item IS NULL

The above statement would return all itemwhse records that don't have a related job record.

Last edited by murphys : 11-21-2005 at 07:14 AM.
Reply With Quote
  #6  
Old 02-16-2007, 12:29 AM
PiDiDi's Avatar
PiDiDi PiDiDi is offline
Something Cool Should Go Here
 
Join Date: Feb 2007
Posts: 354
PiDiDi is an unknown quantity at this point
Default

Thanks, Derik, for this thread.
I agree with you: People, please, try to minimize usage of cursors in your code!
The cursor is very expensive - the data are stored into the temp database and also the overhead is expensive.
Here is small stupid example, but...:

-- create test table and fill it with data
if not object_id('tempdb..#ttt') is null
drop table #ttt
create table #ttt (id int identity(1,1), i int)
declare @i int
set @i = 0
while (@i < 10000)
begin
insert into #ttt(i) values(@i)
set @i = @i + 1
end

select 'START - NO CURSOR', getdate()
update #ttt
set i = i - 10000
select 'END - NO CURSORr', getdate()

-- fill the table again, to have same starting point ;-)
truncate table #ttt

set @i = 0
while (@i < 10000)
begin
insert into #ttt(i) values(@i)
set @i = @i + 1
end
-- now, do the same but using cursor
select 'START - CURSOR', getdate()
declare cur_ cursor local static for
select id from #ttt
open cur_
while (1=1)
begin
fetch next from cur_ into @i
if @@fetch_status <> 0 BREAK
update #ttt
set i = i - 10000
where id = @i
end
close cur_
deallocate cur_
select 'END - CURSOR', getdate()


And the result is:

START - NO CURSOR 2007-02-16 10:25:16.683
END - NO CURSORr 2007-02-16 10:25:16.717
--------------
START - CURSOR 2007-02-16 10:25:16.950
END - CURSOR 2007-02-16 10:25:24.420


Without cursor: "nothing", with cursor: 8 sec
__________________
Sr. Programmer & Analyst
Production, APS Planning, Configurator, FS, WF
Programmer/Analyst
Project manager

Last edited by PiDiDi : 02-16-2007 at 12:33 AM.
Reply With Quote
Reply

Sponsored Links


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

All times are GMT -7. The time now is 02:39 AM.


Powered by vBulletin Version 3.5.0
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
(c) 2007 - 2010 Syteline7.com All Rights Reserved. For reprint permissions, please send a request to an administrator. Syteline, Symix, and Syteline 7 are registered trademarks of Infor corporation or their affiliates.