July 21, 2012 at 11:43 pm
Hi expert ,
Here is the details ,
DECLARE @t TABLE(col1 INT, col2 INT)
INSERT INTO @t(col1,col2)
SELECT 1, NULL UNION ALL
SELECT 2, 2 UNION ALL
SELECT 3, NULL UNION ALL
SELECT 4, NULL UNION ALL
SELECT 5, NULL UNION ALL
SELECT 6, 6 UNION ALL
SELECT 7, 7 UNION ALL
SELECT 8, 8 UNION ALL
SELECT 9, 9 UNION ALL
SELECT 10, NULL;
SELECT * FROM @T
-- Logic
Here i need to update if col2 has NULL then I need to col2 value to the NEXT col2 value .
from the given input data in row 3,4,5 col2 has NULL , So here we need to update row 3,4,5 to row6 of col2 .
similarly row 1 col2 value to row2 col2 vlaue ...
If last row of col2 has NULL then no need to update
-- EXPECTED OUTPUT:
col1col2
12
22
36
46
56
66
77
88
99
10NULL
Please help me .
Thanks!
July 22, 2012 at 1:08 am
Here it is (there can be another better solution as well)
with cte1
as
( select col1,col2 from @t
),
cte2
as
(
select col1,col2 from @twhere col2 is not null
)
select col1,coalesce(col2,(select top 1 col2
from cte2 where cte2.col1>cte1.col1)) col22
from cte1;
~ Lokesh Vij
Link to my Blog Post --> www.SQLPathy.com[/url]
Follow me @Twitter
July 22, 2012 at 3:28 am
Without an ORDER BY, TOP is meaningless:
SELECT
t1.col1,
col2 = ISNULL(t1.col2, x.col2)
FROM @T t1
OUTER APPLY (
SELECT TOP 1
t2.col2
FROM @T t2
WHERE t2.col1 > t1.col1
AND t2.col2 IS NOT NULL
AND t1.col2 IS NULL
ORDER BY t2.col1 ASC
) x
For better assistance in answering your questions, please read this[/url].
Hidden RBAR: Triangular Joins[/url] / The "Numbers" or "Tally" Table: What it is and how it replaces a loop[/url] Jeff Moden[/url]
July 22, 2012 at 3:53 am
Thanks Chris for correcting me 🙂
~ Lokesh Vij
Link to my Blog Post --> www.SQLPathy.com[/url]
Follow me @Twitter
July 22, 2012 at 5:10 am
Here's an ( oldfashioned ) alternative so you can compare performance depending of the % of your set that needs to be updated.
Run it over a big set of data to figure out the version that serves your situation best.
Update U
set col2 = Ur.col2
from @t U
inner join (
Select T1.col1
, MIN(T2.col1) NextCol1
from @t T1
inner join @t T2
on T2.col1 > T1.col1
and T1.col2 is null
and T2.col2 is not null
group by T1.col1
) R
on R.col1 = U.col1
inner join @t Ur
on Ur.col1 = R.NextCol1
Johan
Learn to play, play to learn !
Dont drive faster than your guardian angel can fly ...
but keeping both feet on the ground wont get you anywhere :w00t:
- How to post Performance Problems
- How to post data/code to get the best help[/url]
- How to prevent a sore throat after hours of presenting ppt
press F1 for solution, press shift+F1 for urgent solution 😀
Need a bit of Powershell? How about this
Who am I ? Sometimes this is me but most of the time this is me
July 22, 2012 at 8:04 am
Thanks to all ,
July 22, 2012 at 6:04 pm
ALZDBA (7/22/2012)
Here's an ( oldfashioned ) alternative so you can compare performance depending of the % of your set that needs to be updated.Run it over a big set of data to figure out the version that serves your situation best.
Excellent idea. Let's see who's created an accidental cross join or triangular join and who hasn't. 🙂 Here's code that will create 100,000 rows of data (whatever you want, really). I've setup the test data table so that the only thing anyone needs to change in their current for this problem is "@t" to "#T". As usual, details are in the code.
--===== Conditionally drop the test tables to make reruns easier in SSMS
IF OBJECT_ID('tempdb..#T','U') IS NOT NULL DROP TABLE #T;
IF OBJECT_ID('tempdb..#N','U') IS NOT NULL DROP TABLE #N;
GO
--===== Declare and set a variable for the desired number of test rows.
-- I did it this way so that folks using 2K5 don't have to make
-- any changes to get it to work.
DECLARE @Rows INT;
SET @Rows = 100000;
--===== Create and populate the test table on-the-fly.
SELECT TOP (@Rows)
Col1 = ISNULL(CAST(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS INT),0),
Col2 = CAST(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS INT)
INTO #T
FROM sys.all_columns ac1
CROSS JOIN sys.all_columns ac2
;
--===== Add a PK/Clustered Index to what looks like should be the PK.
ALTER TABLE #T
ADD PRIMARY KEY CLUSTERED (Col1)
;
--===== Try to nullify about 1/3rd of the columns.
-- About 28% will actually be nullified due to dupe updates.
-- The separate "#N" table gets rid of a major performance problem here.
SELECT TOP (@Rows/3)
Col1ToNullify = ABS(CHECKSUM(NEWID()))%@Rows+1
INTO #N
FROM #T
;
UPDATE tgt
SET Col2 = NULL
FROM #t tgt
INNER JOIN #N n
ON tgt.Col1 = n.Col1ToNullify
;
SELECT * FROM #T
;
--Jeff Moden
Change is inevitable... Change for the better is not.
July 22, 2012 at 6:19 pm
Nagaram (7/22/2012)
Thanks to all ,
There's a question in my mind that's still outstanding about all of this. Do you just want to return a result set or do you want to update the original table?
--Jeff Moden
Change is inevitable... Change for the better is not.
July 22, 2012 at 7:02 pm
ChrisM@home (7/22/2012)
Without an ORDER BY, TOP is meaningless:
SELECT
t1.col1,
col2 = ISNULL(t1.col2, x.col2)
FROM @T t1
OUTER APPLY (
SELECT TOP 1
t2.col2
FROM @T t2
WHERE t2.col1 > t1.col1
AND t2.col2 IS NOT NULL
AND t1.col2 IS NULL
ORDER BY t2.col1 ASC
) x
This is pretty cool. With the right kind of indexing (nothing special, just the PK in this case), change it to an UPDATE, and add a WHERE clause to only work WHERE t1.Col2 IS NULL, it actually beats the Quirky Update that uses a safety counter. Not by much but clearly a win for two reasons. Obviously, it's faster and the other reason is because it's supported code.
For doing the same thing but in the same direction as the clustered index instead of the reverse, an "unfettered" QU still comes in 6 times faster processing a million rows in about 2 seconds on my old machine. Still, the method you wrote comes in at 12 seconds on a million rows with a 28% modification rate (28% of Col2 is NULL). Unlike the QU, you can control which rows get updated so you don't fire any triggers present on rows that don't need updating.
And, it's about as fast as some of the new "previous row" functionality available in 2012.
All of that is "geekinese" for "Well Done!" 🙂
--Jeff Moden
Change is inevitable... Change for the better is not.
July 22, 2012 at 7:21 pm
Jeff Moden (7/22/2012)
Nagaram (7/22/2012)
Thanks to all ,There's a question in my mind that's still outstanding about all of this. Do you just want to return a result set or do you want to update the original table?
I want to update the original table
July 22, 2012 at 7:30 pm
Nagaram (7/22/2012)
Jeff Moden (7/22/2012)
Nagaram (7/22/2012)
Thanks to all ,There's a question in my mind that's still outstanding about all of this. Do you just want to return a result set or do you want to update the original table?
I want to update the original table
Then Chris' method works (very fast in the presence of a Clustered Index on Col1) with just a couple o' tweeks...
UPDATE t1
SET col2 = x.col2
-- SELECT t1.col1, col2 = ISNULL(t1.col2, x.col2)
FROM @T t1
OUTER APPLY
(
SELECT TOP 1
t2.col2
FROM @T t2
WHERE t2.col1 > t1.col1
AND t2.col2 IS NOT NULL
AND t1.col2 IS NULL
ORDER BY t2.col1 ASC
) x
WHERE t1.Col2 IS NULL --Use this if updating
;
--Jeff Moden
Change is inevitable... Change for the better is not.
July 22, 2012 at 9:00 pm
Jeff Moden (7/22/2012)
ChrisM@home (7/22/2012)
Without an ORDER BY, TOP is meaningless:
SELECT
t1.col1,
col2 = ISNULL(t1.col2, x.col2)
FROM @T t1
OUTER APPLY (
SELECT TOP 1
t2.col2
FROM @T t2
WHERE t2.col1 > t1.col1
AND t2.col2 IS NOT NULL
AND t1.col2 IS NULL
ORDER BY t2.col1 ASC
) x
This is pretty cool. With the right kind of indexing (nothing special, just the PK in this case), change it to an UPDATE, and add a WHERE clause to only work WHERE t1.Col2 IS NULL, it actually beats the Quirky Update that uses a safety counter. Not by much but clearly a win for two reasons. Obviously, it's faster and the other reason is because it's supported code.
For doing the same thing but in the same direction as the clustered index instead of the reverse, an "unfettered" QU still comes in 6 times faster processing a million rows in about 2 seconds on my old machine. Still, the method you wrote comes in at 12 seconds on a million rows with a 28% modification rate (28% of Col2 is NULL). Unlike the QU, you can control which rows get updated so you don't fire any triggers present on rows that don't need updating.
And, it's about as fast as some of the new "previous row" functionality available in 2012.
All of that is "geekinese" for "Well Done!" 🙂
Jeff - I'm guessing this is the kind of answer that earns you the big bucks. 🙂
Now if I can just figure out what the heck you said. 😛
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
July 22, 2012 at 9:24 pm
Jeff Moden (7/22/2012)
Nagaram (7/22/2012)
Jeff Moden (7/22/2012)
Nagaram (7/22/2012)
Thanks to all ,There's a question in my mind that's still outstanding about all of this. Do you just want to return a result set or do you want to update the original table?
I want to update the original table
Then Chris' method works (very fast in the presence of a Clustered Index on Col1) with just a couple o' tweeks...
UPDATE t1
SET col2 = x.col2
-- SELECT t1.col1, col2 = ISNULL(t1.col2, x.col2)
FROM @T t1
OUTER APPLY
(
SELECT TOP 1
t2.col2
FROM @T t2
WHERE t2.col1 > t1.col1
AND t2.col2 IS NOT NULL
AND t1.col2 IS NULL
ORDER BY t2.col1 ASC
) x
WHERE t1.Col2 IS NULL --Use this if updating
;
You know, it is really sad that people can't think for themselves. They're shown a method that can provide them with the answer the are looking for, but can't make the simple logic jump to do what they want. I mean, really, how hard is it to convert a select statement that displays the answer, to an update statement.
July 22, 2012 at 9:42 pm
thanks for all for the valuable different methods . which were really help me to think in different perspectives.
I have gone thorough the all the solutions .
I will check all the above solutions with original data (one lac + records ..) for performance wise .
Thanks
~IRK
July 22, 2012 at 9:52 pm
Lynn Pettis (7/22/2012)
Jeff Moden (7/22/2012)
Nagaram (7/22/2012)
Jeff Moden (7/22/2012)
Nagaram (7/22/2012)
Thanks to all ,There's a question in my mind that's still outstanding about all of this. Do you just want to return a result set or do you want to update the original table?
I want to update the original table
Then Chris' method works (very fast in the presence of a Clustered Index on Col1) with just a couple o' tweeks...
UPDATE t1
SET col2 = x.col2
-- SELECT t1.col1, col2 = ISNULL(t1.col2, x.col2)
FROM @T t1
OUTER APPLY
(
SELECT TOP 1
t2.col2
FROM @T t2
WHERE t2.col1 > t1.col1
AND t2.col2 IS NOT NULL
AND t1.col2 IS NULL
ORDER BY t2.col1 ASC
) x
WHERE t1.Col2 IS NULL --Use this if updating
;
You know, it is really sad that people can't think for themselves. They're shown a method that can provide them with the answer the are looking for, but can't make the simple logic jump to do what they want. I mean, really, how hard is it to convert a select statement that displays the answer, to an update statement.
I'm not sure that the OP couldn't make or didn't try the leap. I had just gotten done testing it for performance and figured I'd post it. My question on whether the OP wanted a full result set or just to update the original table was so I'd know what to test for. The OP seemed quite happy with the answers previously given so it may be that he did actually make the leap and simply didn't post it.
--Jeff Moden
Change is inevitable... Change for the better is not.
Viewing 15 posts - 1 through 15 (of 21 total)
You must be logged in to reply to this topic. Login to reply