ADO Shape Command:
First of all, I would like to mention that this SHAPE Command is not particular to any of the Query Language (i.e., Oracle, SQL Server or Access). It can work in any of the mentioned databases. It’s a powerful command provided by ADO Object. Main objective of SHAPE command in ADO lets you to create a hierarchical Recordsets.
It's really useful and much better - faster than creating two Recordsets or a big join. Let's assume you have to write a Query that needs to show a Master Record (Let’s say Order) and related Child records (products in that order) - the routine way of doing it in VB/VBA is to,
- Open Order Master as a separate Recordset
- Open Order Details as a separate Recordset based on the Order Master Primary Key field values.
We will be opening 2 Recordset Objects in our code in order to accomplish this task. This example drills up to 2 Levels only ( i.e., Master – Detail ), there will be cases where we will be required to drill down up to 4 or 5 levels, in those cases opening 4 or 5 Recordsets can cause a lot of performance issue in Applications. In order to handle such cases, Hierarchical Recordsets can be used and it’s possible only by using ADO SHAPE Command. Here is how you use it:
Sample Syntax:
SHAPE {SELECT ord_no,cust_name FROM ord_mstr} AS Order APPEND ({SELECT ord_no, item_no FROM ord_details} AS OrderDet RELATE ord_no TO ord_no)
Let us see the usage more in detail with a sample code,
Create a Master Table as,
create table ord_mstr(ord_no int, cust_name varchar(10))
insert into ord_mstr values(100,'name1')
insert into ord_mstr values(200,'name2')
insert into ord_mstr values(300,'name3')
select * from ord_mstr
ord_no cust_name
----------- ----------
100 name1
200 name2
300 name3
Create a Detail table as,
create table ord_details(ord_no int, item_no varchar(5))
insert into ord_details values(100,'1itm1')
insert into ord_details values(100,'1itm2')
insert into ord_details values(200,'2itm1')
insert into ord_details values(300,'3itm1')
insert into ord_details values(300,'3itm2')
insert into ord_details values(300,'3itm3')
select * from ord_details
ord_no item_no
----------- -------
100 1itm1
100 1itm2
200 2itm1
300 3itm2
300 3itm3
300 3itm1
If you see the table values, ord_no 100 has 2 child records and 200 has 1 child record and 300 has 3 child records. We will see how we can bring this hierarchy in a single SQL statement using ADO SHAPE Command,
Note: In order to use ADO SHAPE Command, we need to create a ODBC DSN for connecting to appropriate database ( i.e., to SQL Server or Oracle or Access), We will be setting the Provider Property of the Connection Object to MsDataShape and Connection String will be set to the DSN Name.
Create a New Standard EXE Project and paste the following code,
Dim cn As ADODB.Connection
Dim rsOrd As ADODB.Recordset
Dim rsOrdDet As ADODB.Recordset
Set cn = new ADODB.Connection
Set rsOrd = new ADODB.Recordset
Set rsOrdDet = new ADODB.Recordset
'mention the Provider Name as MSDataShapte
cn.Provider = "MSDataShape"
'specify the DSN Name for DataShape provider
'Here , test ODBC DSN points to a SQL Server Database
cn.Open "dsn=test"
'open the recordset using SHAPE Command containing master-detail set of records
'master records will be from ord_mstr
'detail records will be from ord_detail
'use the RELATE Keyword to relate your ord_mstr and ord_detail table
rsOrd.Open "SHAPE {SELECT ord_no,cust_name FROM ord_mstr} AS Order APPEND ({SELECT ord_no, item_no FROM ord_details} AS OrderDet RELATE ord_no TO ord_no)", cn, adOpenStatic
If rsOrd.RecordCount > 0 Then
rsOrd.MoveFirst
While Not rsOrd.EOF
'display field values from Master Table i.e., ord_mstr
MsgBox "Order No from Master = " & rsOrd.Fields("ord_no")
MsgBox "Customer Name from Master = " & rsOrd.Fields("cust_name")
'child records will be stored inside Master Recordset itself
'i.e., ord_details records will be stored inside ord_mstr recordset
'OrderDet Recordset object will be stored inside rsOrd Recordset
'we dont have to open a seperate recordset for fetching order_details table
Set rsOrdDet = rsOrd.Fields("OrderDet").Value
If rsOrdDet.RecordCount > 0 Then
rsOrdDet.MoveFirst
While Not rsOrdDet.EOF
MsgBox "Order No from Detail = " & rsOrdDet.Fields("ord_no")
MsgBox "Item No from Detail = " & rsOrdDet.Fields("item_no")
rsOrdDet.MoveNext
Wend
End If
rsOrd.MoveNext
Wend
Set cn = Nothing
Set rsOrd = Nothing
Set rsOrdDet = Nothing
End If
If you see the above code, the Master Recordset (rsOrd) itself has the reference for rsOrdDet(Order Details) Recordset. This is the beauty of the SHAPE Command and we can change the Query to drill down up to N-Levels ie., Master – Detail –Detail etc.,
References
Please check the below Microsoft link for more information about this SHAPE Command and how efficiently we can use it in our applications,
http://support.microsoft.com/kb/q189657/
Biography
I am a software developer and have worked on Microsoft technologies for about eight years now. I have always been fascinated by Microsoft technologies and with the advent of .NET , this fascination has reached new heights. I take a lot of interest in reading technical articles and equally enjoy writing them.