March 24, 2015 at 8:33 am
Hey All.
I need some help with T-SQL. I've been struggling for many many hours with it and it is pissing me up.
I can't use loops, cursors, etc. This is because I need high performance.
I would be very grateful if you may help me.
Here is my problem:
I have a table called __tt_Freight_Product which has the following columns:
dt_reference_date, id_contract, qtt_terminal_loaded
And a table called Product which has the following columns:
dt_reference_date, id_contract, id_fixing, qtt_fixing, qtt_terminal
There are NO foreign key between them, yet id_contract and dt_reference_date are supposed to be the same.
Example data on __tt_Freight_Product:
('2015-02-25', '0000006-t12', 200000)
('2015-02-26', '0000006-t12', 200000)
('2015-02-28', '0000006-t12', 100000)
That data means that 200,000 TONS was loaded on contract '0000006-t12' into terminal on '2015-02-25', and so on
Example data on Product:
('2015-02-24', '0000006-t12', 1, 300000, 0)
('2015-02-25', '0000006-t12', 1, 300000, 0)
('2015-02-26', '0000006-t12', 1, 300000, 0)
('2015-02-27', '0000006-t12', 1, 300000, 0)
('2015-02-28', '0000006-t12', 1, 300000, 0)
('2015-02-29', '0000006-t12', 1, 300000, 0)
('2015-02-24', '0000006-t12', 2, 200000, 0)
('2015-02-25', '0000006-t12', 2, 200000, 0)
('2015-02-26', '0000006-t12', 2, 200000, 0)
('2015-02-27', '0000006-t12', 2, 200000, 0)
('2015-02-28', '0000006-t12', 2, 200000, 0)
('2015-02-29', '0000006-t12', 2, 200000, 0)
What I need to accomplish is to split the loaded volumes that are on __tt_Freight_Product into the Product table, per dt_reference_date/id_contract/id_fixing. That splited volume will be updated on the Product table.
It's kinda we had to divide the volume per "id_fixing".
So, considering the example data on __tt_Freight_Product we will update:
dt_reference_date: '2015-02-24'
Nothing will be updated as the cargo loaded just con 25th
dt_reference_date: '2015-02-25'
qtt_terminal of id_fixing "1" will be updated to 200,000
qtt_terminal of id_fixing "2" won't change
dt_reference_date: '2015-02-26'
qtt_terminal of id_fixing "1" will be updated to 300,000
qtt_terminal of id_fixing "2" will be updated to 100,000
dt_reference_date: '2015-02-27'
qtt_terminal of id_fixing "1" will be updated to 300,000, as we had cargo on the previous day and no loaded cargo on 27th OR considering we already have id_fixing '1' "*full allocated*"
qtt_terminal of id_fixing "2" will be updated to 100,000, as we had cargo on the previous day and no loaded cargo on 27th
dt_reference_date: '2015-02-28'
qtt_terminal of id_fixing "1" will be updated to 300,000, as we had cargo on the previous day and no loaded cargo on 27th OR considering we already have id_fixing '1' "*full allocated*"
qtt_terminal of id_fixing "2" will be updated to 200,000
dt_reference_date: '2015-02-29'
qtt_terminal of id_fixing "1" will be updated to 300,000, as we had cargo on the previous day and no loaded cargo on 29th OR considering we already have id_fixing '1' "*full allocated*"
qtt_terminal of id_fixing "2" will be updated to 200,000, as we had cargo on the previous day and no loaded cargo on 29th
Any ideas?
March 24, 2015 at 8:38 am
Hi and welcome to the forums. In order to help we will need a few things:
1. Sample DDL in the form of CREATE TABLE statements
2. Sample data in the form of INSERT INTO statements
3. Expected results based on the sample data
Please take a few minutes and read the first article in my signature for best practices when posting questions.
_______________________________________________________________
Need help? Help us help you.
Read the article at http://www.sqlservercentral.com/articles/Best+Practices/61537/ for best practices on asking questions.
Need to split a string? Try Jeff Modens splitter http://www.sqlservercentral.com/articles/Tally+Table/72993/.
Cross Tabs and Pivots, Part 1 – Converting Rows to Columns - http://www.sqlservercentral.com/articles/T-SQL/63681/
Cross Tabs and Pivots, Part 2 - Dynamic Cross Tabs - http://www.sqlservercentral.com/articles/Crosstab/65048/
Understanding and Using APPLY (Part 1) - http://www.sqlservercentral.com/articles/APPLY/69953/
Understanding and Using APPLY (Part 2) - http://www.sqlservercentral.com/articles/APPLY/69954/
March 24, 2015 at 8:57 am
Like Sean, I could do with more of a "code" explanation. I knocked up your post in to sample data, ready to play with: -
-- CREATE sample "__tt_Freight_Product"
IF object_id('tempdb..#__tt_Freight_Product') IS NOT NULL
BEGIN
DROP TABLE #__tt_Freight_Product;
END;
SELECT a.dt_reference_date,
a.id_contract,
a.qtt_terminal_loaded
INTO #__tt_Freight_Product
FROM ( VALUES ( '2015-02-25', '0000006-t12', 200000),
( '2015-02-26', '0000006-t12', 200000),
( '2015-02-28', '0000006-t12', 100000) ) a ( dt_reference_date, id_contract, qtt_terminal_loaded );
-- CREATE sample "Product"
IF object_id('tempdb..#Product') IS NOT NULL
BEGIN
DROP TABLE #Product;
END;
SELECT a.dt_reference_date,
a.id_contract,
a.id_fixing,
a.qtt_fixing,
a.qtt_terminal
INTO #Product
FROM ( VALUES ( '2015-02-24', '0000006-t12', 1, 300000, 0),
( '2015-02-25', '0000006-t12', 1, 300000, 0),
( '2015-02-26', '0000006-t12', 1, 300000, 0),
( '2015-02-27', '0000006-t12', 1, 300000, 0),
( '2015-02-28', '0000006-t12', 1, 300000, 0),
( '2015-02-29', '0000006-t12', 1, 300000, 0),
( '2015-02-24', '0000006-t12', 2, 200000, 0),
( '2015-02-25', '0000006-t12', 2, 200000, 0),
( '2015-02-26', '0000006-t12', 2, 200000, 0),
( '2015-02-27', '0000006-t12', 2, 200000, 0),
( '2015-02-28', '0000006-t12', 2, 200000, 0),
( '2015-02-29', '0000006-t12', 2, 200000, 0) ) a ( dt_reference_date, id_contract, id_fixing, qtt_fixing, qtt_terminal );
But I don't understand what your expected result is. Are you planning on updating "Product", or selecting data out?
March 24, 2015 at 11:36 am
Cadavre,
Thank you for your help.
What I expect as a result is to update the "Product" table, on the column "qtt_terminal".
Here is a picture with example output data based on input data:
March 24, 2015 at 7:37 pm
I see no alternative other than a loop for this. Where the heck is Itzik Ben-Gan when you need him!
-- CREATE sample "__tt_Freight_Product"
IF object_id('tempdb..#__tt_Freight_Product') IS NOT NULL
BEGIN
DROP TABLE #__tt_Freight_Product;
END;
SELECT a.dt_reference_date,
a.id_contract,
a.qtt_terminal_loaded
INTO #__tt_Freight_Product
FROM ( VALUES ( '2015-02-25', '0000006-t12', 200000),
( '2015-02-26', '0000006-t12', 200000),
( '2015-02-28', '0000006-t12', 100000) ) a ( dt_reference_date, id_contract, qtt_terminal_loaded );
-- CREATE sample "Product"
IF object_id('tempdb..#Product') IS NOT NULL
BEGIN
DROP TABLE #Product;
END;
SELECT a.dt_reference_date,
a.id_contract,
a.id_fixing,
a.qtt_fixing,
a.qtt_terminal
INTO #Product
FROM ( VALUES ( '2015-02-24', '0000006-t12', 1, 300000, 0),
( '2015-02-25', '0000006-t12', 1, 300000, 0),
( '2015-02-26', '0000006-t12', 1, 300000, 0),
( '2015-02-27', '0000006-t12', 1, 300000, 0),
( '2015-02-28', '0000006-t12', 1, 300000, 0),
( '2015-02-29', '0000006-t12', 1, 300000, 0),
( '2015-02-24', '0000006-t12', 2, 200000, 0),
( '2015-02-25', '0000006-t12', 2, 200000, 0),
( '2015-02-26', '0000006-t12', 2, 200000, 0),
( '2015-02-27', '0000006-t12', 2, 200000, 0),
( '2015-02-28', '0000006-t12', 2, 200000, 0),
( '2015-02-29', '0000006-t12', 2, 200000, 0) ) a ( dt_reference_date, id_contract, id_fixing, qtt_fixing, qtt_terminal );
SELECT * FROM #__tt_Freight_Product;
DECLARE @max_id_fixing INT = (SELECT MAX(id_fixing) FROM #Product)
,@id_fixing INT = 0;
WHILE @id_fixing < @max_id_fixing
BEGIN
SELECT @id_fixing = @id_fixing + 1;
WITH AlreadyLoaded AS
(
SELECT dt_reference_date, id_contract, qtt_terminal_loaded
,al=ISNULL(
(
SELECT SUM(qtt_terminal)
FROM #Product a
WHERE a.id_contract = b.id_contract AND a.dt_reference_date = b.dt_reference_date AND
a.id_fixing < @id_fixing
), 0)
,rt=SUM(qtt_terminal_loaded) OVER
(
PARTITION BY id_contract
ORDER BY dt_reference_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
FROM #__tt_Freight_Product b
)
UPDATE a
SET qtt_terminal = CASE SIGN(b.rt - al) WHEN -1 THEN 0 ELSE b.rt - al END
FROM #Product a
JOIN AlreadyLoaded b
ON a.id_contract = b.id_contract AND a.dt_reference_date = b.dt_reference_date
WHERE a.id_fixing = @id_fixing;
--SELECT * FROM #Product;
WITH Product AS
(
SELECT dt_reference_date, id_contract, id_fixing, qtt_fixing
,qtt_terminal
,qtt=SUM(qtt_terminal) OVER
(
PARTITION BY a.id_contract
ORDER BY a.dt_reference_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
FROM #Product a
WHERE a.id_fixing = @id_fixing
)
UPDATE a
SET qtt_terminal = CASE WHEN qtt > qtt_fixing THEN qtt_fixing ELSE qtt END
FROM Product a;
END
SELECT * FROM #Product;
GO
DROP TABLE #Product;
DROP TABLE #__tt_Freight_Product;
Basically what this does is it allocates the incoming freight to one of your "id_fixing" terminals (?) per iteration, while throwing away that which has already been allocated to one of the terminals.
Not sure what would happen if you end up with more incoming freight than your terminals will hold, and presumably you need some additional transactions to deplete what's already been stored. But we'll leave that for another day.
Edit: Oh yes. And thanks to Cadavre (haven't seen you in a long time sir!) for setting up the test data!
My thought question: Have you ever been told that your query runs too fast?
My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.
Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
Since random numbers are too important to be left to chance, let's generate some![/url]
Learn to understand recursive CTEs by example.[/url]
[url url=http://www.sqlservercentral.com/articles/St
March 24, 2015 at 11:09 pm
marco alves (3/24/2015)
Cadavre,Thank you for your help.
What I expect as a result is to update the "Product" table, on the column "qtt_terminal".
Here is a picture with example output data based on input data:
Will there only ever be two "id_fixing" values? If not, how many are there or could be?
--Jeff Moden
Change is inevitable... Change for the better is not.
March 25, 2015 at 1:04 am
Jeff Moden (3/24/2015)
Will there only ever be two "id_fixing" values? If not, how many are there or could be?
I hate it when you ask questions like that. Makes me think I overlooked something obvious.
My solution assumes you could have as many as you want.
My thought question: Have you ever been told that your query runs too fast?
My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.
Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
Since random numbers are too important to be left to chance, let's generate some![/url]
Learn to understand recursive CTEs by example.[/url]
[url url=http://www.sqlservercentral.com/articles/St
March 25, 2015 at 7:12 am
dwain.c (3/24/2015)
I see no alternative other than a loop for this. Where the heck is Itzik Ben-Gan when you need him!
Speak and he shall appear. The OP posted this same question over at SO and guess who provided an answer?
http://stackoverflow.com/questions/29235423/struggling-with-logic-in-t-sql?noredirect=1
_______________________________________________________________
Need help? Help us help you.
Read the article at http://www.sqlservercentral.com/articles/Best+Practices/61537/ for best practices on asking questions.
Need to split a string? Try Jeff Modens splitter http://www.sqlservercentral.com/articles/Tally+Table/72993/.
Cross Tabs and Pivots, Part 1 – Converting Rows to Columns - http://www.sqlservercentral.com/articles/T-SQL/63681/
Cross Tabs and Pivots, Part 2 - Dynamic Cross Tabs - http://www.sqlservercentral.com/articles/Crosstab/65048/
Understanding and Using APPLY (Part 1) - http://www.sqlservercentral.com/articles/APPLY/69953/
Understanding and Using APPLY (Part 2) - http://www.sqlservercentral.com/articles/APPLY/69954/
March 25, 2015 at 5:37 pm
Sean Lange (3/25/2015)
dwain.c (3/24/2015)
I see no alternative other than a loop for this. Where the heck is Itzik Ben-Gan when you need him!Speak and he shall appear. The OP posted this same question over at SO and guess who provided an answer?
http://stackoverflow.com/questions/29235423/struggling-with-logic-in-t-sql?noredirect=1
And of course it puts my solution to shame!
My thought question: Have you ever been told that your query runs too fast?
My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.
Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
Since random numbers are too important to be left to chance, let's generate some![/url]
Learn to understand recursive CTEs by example.[/url]
[url url=http://www.sqlservercentral.com/articles/St
March 25, 2015 at 10:08 pm
dwain.c (3/25/2015)
Jeff Moden (3/24/2015)
Will there only ever be two "id_fixing" values? If not, how many are there or could be?I hate it when you ask questions like that. Makes me think I overlooked something obvious.
My solution assumes you could have as many as you want.
As Itzik pointed out in his post, his code isn't optimized (but it sure does give food for thought). Prior to seeing that, this looked to me like a temporal bin stacking problem. It seemed to me that it might be simpler to attack the problem horizontally than vertically but to do that without dynamic SQL, there needs to be a fixed number of horizontal bins and that's why I wanted to know if there were only 2 id_Fixing values.
Of course, Marco took Cadavre's datapost to another forum, hasn't replied back here, got an answer from Itzik that does work (even if it isn't optimized with a 57 read work table and a bit of a cross join), and didn't say thanks or anything. Itzik's sort on the Product table is where I had gotten to just by playing with the setup but stopped for the id_Fixing question. I'll save the problem as an intellectual curiosity for later on when I'm not so hammered by work.
--Jeff Moden
Change is inevitable... Change for the better is not.
March 25, 2015 at 10:26 pm
Jeff Moden (3/25/2015)
dwain.c (3/25/2015)
Jeff Moden (3/24/2015)
Will there only ever be two "id_fixing" values? If not, how many are there or could be?I hate it when you ask questions like that. Makes me think I overlooked something obvious.
My solution assumes you could have as many as you want.
As Itzik pointed out in his post, his code isn't optimized (but it sure does give food for thought). Prior to seeing that, this looked to me like a temporal bin stacking problem. It seemed to me that it might be simpler to attack the problem horizontally than vertically but to do that without dynamic SQL, there needs to be a fixed number of horizontal bins and that's why I wanted to know if there were only 2 id_Fixing values.
Of course, Marco took Cadavre's datapost to another forum, hasn't replied back here, got an answer from Itzik that does work (even if it isn't optimized with a 57 read work table and a bit of a cross join), and didn't say thanks or anything. Itzik's sort on the Product table is where I had gotten to just by playing with the setup but stopped for the id_Fixing question. I'll save the problem as an intellectual curiosity for later on when I'm not so hammered by work.
I thought it was a bin-packing problem too at first, hence why I thought it couldn't be done without a loop.
Interesting that a new post just popped up with nearly the same requirement:
http://www.sqlservercentral.com/Forums/Topic1671558-3077-1.aspx
My thought question: Have you ever been told that your query runs too fast?
My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.
Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
Since random numbers are too important to be left to chance, let's generate some![/url]
Learn to understand recursive CTEs by example.[/url]
[url url=http://www.sqlservercentral.com/articles/St
Viewing 11 posts - 1 through 10 (of 10 total)
You must be logged in to reply to this topic. Login to reply