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 12 (of 12 total)
You must be logged in to reply to this topic. Login to reply