September 30, 2010 at 9:36 am
Good afternoon folks,
I could use a little help/advice with extracting some data from a CTE.
I have attached the source code of my stored procedure that includes the CTE as a text file for reference. At present, the proc just returns all the results from the CTE.
What the CTE does is get a set of config values for a device. Each level of the CTE contains a set of config values. In each level, some values may or may not be null.
What I actually want to return is a single config where each value is the first non-null value from the CTE (i.e If value A is null in recursion level 0 but populated in recursion 1 and 2 then I want the value from recursion 1).
I could do this based on a single value using a query something like:
SELECT VALUEA
FROM CTE
WHERE RECURSIONLEVEL = (SELECT MIN(RECURSIONLEVEL) FROM CTE WHERE VALUEA IS NOT NULL)
But is there a way I can check and return the non-null values from the lowest recursion for all values the in the config in a set based way?
TIA,
Chris
September 30, 2010 at 10:13 pm
Chris I looked at your code, but I'm afraid I can't visualize the results you want from the description you gave. (It's late and my mental telepathy is breaking down.) Could you post up a script to create your tables and populate them with some sample data? Then add a picture of the results as you would expect to see them?
Doing that almost guarantees that more people will attempt to help you out with your question. Sorry I can't be more help tonight.
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
October 1, 2010 at 5:27 am
I've now uploaded a script to create a test db with some data.
I've also uploaded an Excel sheet showing the result set currently returned by my procedure and what I actually want to get back.
Hopefully someone can point me in the right direction.
Edit: Here's how I call the sp to get the supplied result set as well:
EXEC dbo.usp_Comms_GetMUConfig @SN = '12345678' -- varchar(8)
TIA,
Chris
October 1, 2010 at 7:57 am
Beautiful. Thanks for making the effort. I can see what you're after now. Answer soon come.
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
October 1, 2010 at 8:04 am
Great.
I've implemented a solution in the interim that uses a sub-query to provide the first non-null value for each column but I'm still hoping that there's a better way to do it.
Example:
SELECTTOP 1
(SELECTTOP 1 Code + Number FROM MUConfigCTE INNER JOIN dbo.PhoneNumber ON MUConfigCTE.DataOutPhoneNumberID = dbo.PhoneNumber.PhoneNumberID WHERE MUConfigCTE.DataOutPhoneNumberID IS NOT NULL ORDER BY RecursionLevel) AS DataOutPhoneNumber,
(SELECTTOP 1 Code + Number FROM MUConfigCTE INNER JOIN dbo.PhoneNumber ON MUConfigCTE.DataOutBkUpPhoneNumberID = dbo.PhoneNumber.PhoneNumberID WHERE MUConfigCTE.DataOutBkUpPhoneNumberID IS NOT NULL ORDER BY RecursionLevel),
(SELECTTOP 1 Code + Number FROM MUConfigCTE INNER JOIN dbo.PhoneNumber ON MUConfigCTE.VoiceOutPhoneNumberID = dbo.PhoneNumber.PhoneNumberID WHERE MUConfigCTE.VoiceOutPhoneNumberID IS NOT NULL ORDER BY RecursionLevel)
FROM MUConfigCTE
Good luck and thanks for your help!
Chris
October 1, 2010 at 8:11 am
I don't see a good way to get there with a cte. You want recursion with a while loop or a cursor, that assigns values to scalar variables using COALESCE or ISNULL.
I have a simple example for you, but I was getting an error trying to include the code.
Its been attached now.
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
November 4, 2010 at 4:01 am
Hi Dixie,
Thanks for the example you sent. I've been trying it out but it's not giving me exactly what I need.
In the example, the returned resultset is
idfruit meat
0NULL NULL
1NULL Beef
2Apples Chicken
3Oranges NULL
In terms of the example, what I am trying to get to is a resultset that would look like:
id fruit meat
0 Apples Beef
I'm trying to get a single row which contains the lowest (in terms of id) non-null value from each column.
Is there a way to adapt the recursive WHILE loop to return this?
TIA,
Chris
November 4, 2010 at 5:42 am
Hi Chris
Just as a matter of interest, what is the maximum value for RECURSIONLEVEL that ever appears in a result set from this sproc?
For fast, accurate and documented assistance in answering your questions, please read this article.
Understanding and using APPLY, (I) and (II) Paul White
Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden
November 4, 2010 at 6:07 am
Hi Chris,
In the real-world system which I am building this for, the max recursion level will never exceed 10 and will on most occasions be 3 or 4.
Each level will return a single row of data.
Thanks,
Chris
November 4, 2010 at 6:18 am
Can you please provide a full explanation of the relationship here:
FROM dbo.[Site] s
INNER JOIN dbo.Node n ON s.OwnerNodeID = n.NodeID
For fast, accurate and documented assistance in answering your questions, please read this article.
Understanding and using APPLY, (I) and (II) Paul White
Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden
November 4, 2010 at 6:24 am
Certainly,
What the proc does is assemble a config for a device. Some of the config items are in a table called SiteConfig.
Sites belong to nodes in the system and have an OwnerNodeID field in their table.
The proc looks first for config items at a site level then at the level of the node that owns the site then recursively up a hierachical tree of nodes.
Hope that makes sense. 🙂
November 4, 2010 at 7:45 am
Here's a hacky way of doing it...
declare @sample table (id int identity (0,1), fruit varchar(20), meat varchar(20))
insert into @sample
select null, null union all
select null, 'Beef' union all
select 'Apples', 'Chicken' union all
select 'Oranges',null
select min(id) as id,
stuff(min(cast(id as char(2))+fruit),1,2,'') as fruit,
stuff(min(cast(id as char(2))+meat),1,2,'') as meat
from @sample
____________________________________________________
Deja View - The strange feeling that somewhere, sometime you've optimised this query before
How to get the best help on a forum
http://www.sqlservercentral.com/articles/Best+Practices/61537November 4, 2010 at 8:12 am
Here's another hacky way of doing it. You would benefit from running the results of the CTE into a #Temp table first.
SELECT ISNULL(r0.DataOutPhoneNumber, ISNULL(r1.DataOutPhoneNumber, r2.DataOutPhoneNumber))
FROM #MUConfigCTE r0
LEFT JOIN #MUConfigCTE r1 ON r1.RecursionLevel = 1
LEFT JOIN #MUConfigCTE r2 ON r2.RecursionLevel = 2
WHERE r0.RecursionLevel = 0
For fast, accurate and documented assistance in answering your questions, please read this article.
Understanding and using APPLY, (I) and (II) Paul White
Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden
November 4, 2010 at 8:34 am
Thanks for the suggestions gents, very much appreciated. 🙂
I am going to try both approaches and see if there are any performance benefits.
November 8, 2010 at 8:30 am
Having tried out both suggestions, I found that the method using STUFF worked best as I was able to adapt my existing code using a CTE to use this method.
I also found that any columns that weren't char based such as bit and int needed to be converted to chars in my select statement before I could use the stuff function on them.
Once that was done though it worked a treat.
Thanks again for the wise advice chaps. 🙂
Viewing 15 posts - 1 through 14 (of 14 total)
You must be logged in to reply to this topic. Login to reply