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.

 All Forums
 SQL Server 2005 Forums
 Transact-SQL (2005)
 Help get rid of the curs(e)or

Author  Topic 

stickmus
Starting Member

3 Posts

Posted - 2009-03-24 : 06:10:08
Hi all

First post, have been lurking for a while though. Great forum, helped me loads

I've got a cursor situation that I'm hoping you guys can help with.

I'm importing data from an excel spreadsheet with carrier pricing information in the format

band_start|band_end|zone1_charge|zone2_charge|...
0|0.5|0.51|1.23|...
0.5|1|0.58|1.30|...


What I need to do is get this into a table eg

zoneref|bandref|charge
1|1|0.51
1|2|0.58
2|1|1.23
2|2|1.30


The issue is that there are 20 zones and 1000 bands

I was using a nested cursor to process the information, which was taking over an hour. I've re-factored to a single cursor which gets me down to about 7 minutes, but I'm hoping there's a better way.

FOR
SELECT [min], [max], eu1, eu2, eu3, eu4, eu5, eu6, eu7, eu8, eu9, eu10, eu11, eu12, eu13, eu14, eu15, eu16, eu17, eu18, eu19, air3, air4, air5, air6, air7, air8, air9, code, zoneref
FROM #imp_carrierpricing, zonematching
OPEN band
FETCH NEXT FROM band INTO @min, @max, @eu1, @eu2, @eu3, @eu4, @eu5, @eu6, @eu7, @eu8, @eu9, @eu10, @eu11, @eu12, @eu13, @eu14, @eu15, @eu16, @eu17, @eu18, @eu19, @air3, @air4, @air5, @air6, @air7, @air8, @air9, @zonecode, @zoneref
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN
-- all the above stuff is just to get the values from each band into the cursor variables
-- we need to check if this band already exists
SELECT @bandref = ref from deliverymethodband WHERE low = @min AND high = @max
IF @bandref IS NULL
BEGIN
-- if it doesn't lets create a band for it
--PRINT 'null'
INSERT INTO deliverymethodband (code, description, type, low, high) SELECT CAST(@max * 2 AS INT), CAST(@min AS VARCHAR(5)) + '-' + CAST(@max AS VARCHAR(5)), 'W', @min, @max
END

DECLARE @charge MONEY
-- let's case the values, not very nice to look at, but it works
SET @charge = CASE
WHEN @zonecode = 'EU1' THEN @EU1
WHEN @zonecode = 'EU2' THEN @EU2
...
WHEN @zonecode = 'AIR8' THEN @AIR8
WHEN @zonecode = 'AIR9' THEN @AIR9
END
-- lets just make sure we have a charge...
IF @charge is not null
BEGIN
-- work out if we're updating/inserting
IF (
EXISTS (
SELECT * FROM deliverymethodzonecharge
WHERE deliveryref = @deliveryref AND zoneref= @zoneref AND bandref = @bandref
)
)
-- update
BEGIN
UPDATE deliverymethodzonecharge
SET charge = @charge
WHERE deliveryref = @deliveryref AND zoneref= @zoneref AND bandref = @bandref
END
ELSE
--insert
BEGIN
INSERT INTO deliverymethodzonecharge (deliveryref, zoneref, bandref, charge)
VALUES(@deliveryref, @zoneref, @bandref, @charge)
END
END
SET @bandref = NULL
SET @charge = NULL
FETCH NEXT FROM band INTO @min, @max, @eu1, @eu2, @eu3, @eu4, @eu5, @eu6, @eu7, @eu8, @eu9, @eu10, @eu11, @eu12, @eu13, @eu14, @eu15, @eu16, @eu17, @eu18, @eu19, @air3, @air4, @air5, @air6, @air7, @air8, @air9, @zonecode, @zoneref
END
END
CLOSE band
DEALLOCATE band


I'm fairly new to sql (6 months now) so any hints on any other things I'm doing horribly wrong also gratefully received (I'm not proud)

TIA

George.

heavymind
Posting Yak Master

115 Posts

Posted - 2009-03-24 : 07:02:43
from first glance I think you need PIVOT

Thanks, Vadym
MCITP DBA 2005/2008
Chief DBA at http://www.db-staff.com
Go to Top of Page

stickmus
Starting Member

3 Posts

Posted - 2009-03-24 : 07:25:33
Okay, so looks like I've gone down the wrong route (UNION)

Is this wrong? It's much faster!

Is there a way to update rather than delete and recreate? Do I need to worry about this? The data is correct and will work if deleted and recreated, but there's about 26000 rows every time, will this cause problems?

Sorry for all the questions.

DELETE from deliverymethodzonecharge where zoneref in (select ref from deliveryzone where code like 'EU%' or code like 'AIR%')

INSERT INTO deliverymethodzonecharge (bandref, zoneref, charge, deliveryref)
SELECT *
FROM
(
SELECT d.ref as bandref, z.ref as zoneref, v.eu1 as charge, @deliveryref as deliveryref
FROM #vko_imp_carrierpricing v, deliverymethodband d, deliveryzone z
WHERE d.low = v.min AND d.high = v.max AND z.code = 'EU1'
union
SELECT d.ref as bandref, z.ref as zoneref, v.eu2 as charge, @deliveryref as deliveryref
FROM #vko_imp_carrierpricing v, deliverymethodband d, deliveryzone z
WHERE d.low = v.min AND d.high = v.max AND z.code = 'EU2'
union
...
SELECT d.ref as bandref, z.ref as zoneref, v.air8 as charge, @deliveryref as deliveryref
FROM #vko_imp_carrierpricing v, deliverymethodband d, deliveryzone z
WHERE d.low = v.min AND d.high = v.max AND z.code = 'AIR8'
union
SELECT d.ref as bandref, z.ref as zoneref, v.air9 as charge, @deliveryref as deliveryref
FROM #vko_imp_carrierpricing v, deliverymethodband d, deliveryzone z
WHERE d.low = v.min AND d.high = v.max AND z.code = 'AIR9'
)a
Go to Top of Page

stickmus
Starting Member

3 Posts

Posted - 2009-03-24 : 08:25:01
Actually I managed to modify the above to run as an update. I've learned something today.

Next time I think I need to use a cursor, I will think again. And I will have a look at that pivot at some point too.
Go to Top of Page

robvolk
Most Valuable Yak

15732 Posts

Posted - 2009-03-24 : 09:12:24
Actually you'll probably want to use UNPIVOT.
Go to Top of Page
   

- Advertisement -