September 28, 2006 at 5:30 pm
Hi there, I need some t-sql query help. My problem is this. We have a table name customer and one of it's column is parent_id. The colum "parent_id" tells if the current customer has a parent customer (and so on). If the value is either null or 0 it has no parent. What I need I think is like a recursive query to determine all my children and I need a pure T-Sql query because we will be passing this query thru a JDBC driver inside a java application.
The partial structure of table is this
Table name: customer
id int
name varchar(50)
parent_id int
Your help is greatly appreciated.
Thanks
September 28, 2006 at 6:15 pm
It must be table UDF accepting @CustomerId as a parameter and collecting ID's for all children using recursive search on table Customer.
After all you use
SELECT * FROM dbo.CustomerChildren(@SomeID)
You may join it to any query as usual table.
_____________
Code for TallyGenerator
September 28, 2006 at 6:21 pm
Ya but you can't join using a column as a parameter (unless you use sql 2005 where the cross apply operator becomes your friend
).
September 28, 2006 at 7:23 pm
Warning: Recursion is good only to 32 levels and then BOOM!!! ![]()
--Jeff Moden
Change is inevitable... Change for the better is not.
September 28, 2006 at 7:32 pm
Why?
Once I forgot to change IDs to newly retrieved and it was retrieving same set again and again.
When I stopped it there were couple of millions recursive calls completed.
And tempdb was really stuffed. ![]()
But it was not stopped without my intrusion. It would go until the disk space is exhaysted. ![]()
_____________
Code for TallyGenerator
September 28, 2006 at 11:00 pm
You can have millions of recursive calls so long as you don't exceed 32 levels of nesting... same as number of nested triggers, nested stored procedures, etc. Write a function that calls itself, say, 40 times... at 33rd call (33rd level deep), you'll get the error message about recursive levels not allowed for more than 32 levels.
--Jeff Moden
Change is inevitable... Change for the better is not.
September 28, 2006 at 11:21 pm
Oh, what is this about...
There are no recursive calls in that function.
Just simple WHILE loop addressing table variable.
So, no one can stop me if I make a mistake! ![]()
_____________
Code for TallyGenerator
September 29, 2006 at 7:56 am
That'll do... I was just worried about the fact that you said it uses "recursive search on Customer table". To me, recursion is when a proc or function calls itself... not loops as you say although I also used to call loops a form of recursion until my old SQL mentor hit me in the head with a bat 10 years ago... yeah, that explains a lot, doesn't it? ![]()
--Jeff Moden
Change is inevitable... Change for the better is not.
September 29, 2006 at 9:24 am
I'm not sure what results you're seeking, what would your results look like if you suceeded?
September 30, 2006 at 5:50 am
Jun,
Crud... Dan's right... sorry we got off track...
To reiterate Dan's question, what should the output look like?
--Jeff Moden
Change is inevitable... Change for the better is not.
October 2, 2006 at 6:35 pm
Guys thanks for all your response. Answer to the question by Dan is ...
Here is a data sample:
1. customer "WALMART CORPORATE" with id = 1 AND parent_id = null
2. customer "WALMART WESTCOST" with id = 10 AND parent_id = 1
3. customer "WALMART CALIFORNIA" with id = 11 AND parent_id = 1
4. customer "WALMART OREGON" with id = 12 AND parent_id = 1
5. customer "WALMART WASHINGTON" with id = 13 AND parent_id = 1
6. customer "WALMART SEATTLE" with id = 1301 AND parent_id = 13
7. customer "WALMART LYNNWOOD" with id = 1302 AND parent_id = 13
8. customer "WALMART BELLEVUE" with id = 1303 AND parent_id = 13
9. customer "WALMART OLYMPIA" with id = 1304 AND parent_id = 13
10. customer "WALMART REDMOND" with id = 1305 AND parent_id = 13
Use Case: I want to return myself and all my children
Scenario #1: customer.id = 1 (WALMART CORPORATE)
This should return all 10 rows above.
Scenario #1: customer.id = 13 (WALMART WASHINGTON)
This should return the following data:
5. customer "WALMART WASHINGTON" with id = 13 AND parent_id = 1
6. customer "WALMART SEATTLE" with id = 1301 AND parent_id = 13
7. customer "WALMART LYNNWOOD" with id = 1302 AND parent_id = 13
8. customer "WALMART BELLEVUE" with id = 1303 AND parent_id = 13
9. customer "WALMART OLYMPIA" with id = 1304 AND parent_id = 13
10. customer "WALMART REDMOND" with id = 1305 AND parent_id = 13
Scenario #1: customer.id = 1301 (WALMART SEATTLE)
This should return the following data:
6. customer "WALMART SEATTLE" with id = 1301 AND parent_id = 13
As you can see from the sample data, that the "WALMART CORPORATE" is the parent of all "WALMART ?????" rows or stores.
Hope this sample answer dan's questions. Also, I can not use store procedures or UDF for this matter (business requirement). If it is only possible to create a single query or few, that will be good.
October 2, 2006 at 7:55 pm
WTH? Why can't you use stored procedures or a UDF? Yeah, I know... "Business Requirement". WHAT is that business requirement?
--Jeff Moden
Change is inevitable... Change for the better is not.
October 2, 2006 at 8:28 pm
This should pass your Use Cases...
--=============================================================================
-- Setup for testing
--=============================================================================
--===== System presets
SET NOCOUNT ON
--===== If the temporary test table exists, drop it
IF OBJECT_ID('TempDB..#Customer') IS NOT NULL
DROP TABLE #Customer
--===== Create the temporary test table
CREATE TABLE #Customer
(
ID INT PRIMARY KEY CLUSTERED,
Parent_ID INT,
Name VARCHAR(100)
)
--===== Populate the temporary test table
INSERT INTO #Customer
(Name,ID,Parent_ID)
SELECT 'WALMART CORPORATE' , 1, NULL UNION ALL
SELECT 'WALMART WESTCOST' ,10, 1 UNION ALL
SELECT 'WALMART CALIFORNIA',11, 1 UNION ALL
SELECT 'WALMART OREGON' ,12, 1 UNION ALL
SELECT 'WALMART WASHINGTON',13, 1 UNION ALL
SELECT 'WALMART SEATTLE' ,1301,13 UNION ALL
SELECT 'WALMART LYNNWOOD',1302,13 UNION ALL
SELECT 'WALMART BELLEVUE',1303,13 UNION ALL
SELECT 'WALMART OLYMPIA' ,1304,13 UNION ALL
SELECT 'WALMART REDMOND' ,1305,13
--=============================================================================
-- Demo possible solution
--=============================================================================
--===== If the results table exists, drop it
IF OBJECT_ID('TempDB..#Results') IS NOT NULL
DROP TABLE #Results
--===== Create the results table with row numbers to preserve the order
CREATE TABLE #Results
(
RowNum INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
ID INT,
Parent_ID INT,
Name VARCHAR(100)
)
--===== Create and preset the variable to hold the ID to find the downline for
DECLARE @SeedID INT --Could be a parameter for a stored proc or UDF rable variable
SELECT @SeedID = 1301 --<<LOOK!!! This is what you change for your USE cases!!!
--===== Seed the results table
INSERT INTO #Results (ID,Parent_ID,Name)
SELECT ID,Parent_ID,Name
FROM #Customer
WHERE ID = @SeedID
--===== Step through the hierarchy and return rows in order
WHILE @@ROWCOUNT > 0
BEGIN
INSERT INTO #Results
(ID,Parent_ID,Name)
SELECT c.Id ,c.Parent_ID,c.Name
FROM #Results i
INNER JOIN #Customer c
ON c.Parent_ID = i.ID
LEFT OUTER JOIN #Results i1
ON i1.Id = c.Id
WHERE i1.Id IS NULL
END
--===== Display the results
SELECT * FROM #Results
--Jeff Moden
Change is inevitable... Change for the better is not.
Viewing 13 posts - 1 through 13 (of 13 total)
You must be logged in to reply to this topic. Login to reply