Returning a variable number of record values as columns

C

Chris

For each record in a Customers table, there can be zero or more associated
records in an Orders table. I'm interested in the order numbers of the five
most recent orders for each customer. I'm trying to write a query that will
return the customer number and zero or more columns--the latter columns
containing the order numbers.

Customers (parent)
CustNum

Orders (child)
CustNum
OrderNum

Result of Query
CustNum OrderNum OrderNum OrderNum
CustNum OrderNum
CustNum
CustNum OrderNum OrderNum OrderNum OrderNum OrderNum
CustNum OrderNum OrderNum
CustNum
CustNum OrderNum
...
...

I'm stumped on how to do this. Any thoughts? Thanks!
 
D

Duane Hookom

You should be able to use the generic concatenate function from
http://www.rogersaccesslibrary.com/OtherLibraries.asp#Hookom,Duane. You
expression would be something like:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE CustNum="""
& CustNum & """ ORDER BY SomeDateFieldNotIdentified DESC")

The above assume CustNum is text, if it is numeric, try:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE CustNum=" &
CustNum & " ORDER BY SomeDateFieldNotIdentified DESC")
 
C

Chris

That's great, Duane; thanks!

I wasn't very clear on my desired result. Rather than return the top five
child records as one concatenated field, I'd like to return up to five
columns, with each column containing the value from a child record.

So the result of the query would be:with each space-delimited value being a separate column.

Is this possible?


Duane Hookom said:
You should be able to use the generic concatenate function from
http://www.rogersaccesslibrary.com/OtherLibraries.asp#Hookom,Duane. You
expression would be something like:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE
CustNum=""" & CustNum & """ ORDER BY SomeDateFieldNotIdentified DESC")

The above assume CustNum is text, if it is numeric, try:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE CustNum="
& CustNum & " ORDER BY SomeDateFieldNotIdentified DESC")

--
Duane Hookom
MS Access MVP


Chris said:
For each record in a Customers table, there can be zero or more
associated records in an Orders table. I'm interested in the order
numbers of the five most recent orders for each customer. I'm trying to
write a query that will return the customer number and zero or more
columns--the latter columns containing the order numbers.

Customers (parent)
CustNum

Orders (child)
CustNum
OrderNum

Result of Query
CustNum OrderNum OrderNum OrderNum
CustNum OrderNum
CustNum
CustNum OrderNum OrderNum OrderNum OrderNum OrderNum
CustNum OrderNum OrderNum
CustNum
CustNum OrderNum
...
...

I'm stumped on how to do this. Any thoughts? Thanks!
 
D

Duane Hookom

You need to create a calculated column in your query that numbers your
records for each CustNum. This is usually done with DCount(). You can then
use the resulting value as a column heading for a crosstab query.

--
Duane Hookom
MS Access MVP


Chris said:
That's great, Duane; thanks!

I wasn't very clear on my desired result. Rather than return the top five
child records as one concatenated field, I'd like to return up to five
columns, with each column containing the value from a child record.

So the result of the query would be:with each space-delimited value being a separate column.

Is this possible?


Duane Hookom said:
You should be able to use the generic concatenate function from
http://www.rogersaccesslibrary.com/OtherLibraries.asp#Hookom,Duane. You
expression would be something like:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE
CustNum=""" & CustNum & """ ORDER BY SomeDateFieldNotIdentified DESC")

The above assume CustNum is text, if it is numeric, try:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE
CustNum=" & CustNum & " ORDER BY SomeDateFieldNotIdentified DESC")

--
Duane Hookom
MS Access MVP


Chris said:
For each record in a Customers table, there can be zero or more
associated records in an Orders table. I'm interested in the order
numbers of the five most recent orders for each customer. I'm trying to
write a query that will return the customer number and zero or more
columns--the latter columns containing the order numbers.

Customers (parent)
CustNum

Orders (child)
CustNum
OrderNum

Result of Query
CustNum OrderNum OrderNum OrderNum
CustNum OrderNum
CustNum
CustNum OrderNum OrderNum OrderNum OrderNum OrderNum
CustNum OrderNum OrderNum
CustNum
CustNum OrderNum
...
...

I'm stumped on how to do this. Any thoughts? Thanks!
 
C

Chris

Thanks, again. I will look into DCount().

Just to be clear (and for my own sanity), the names of the column *headings*
will still be meaningful; i.e., not renamed to be the resulting values,
right? e.g.,

Column heading names: CustNum, Order1Num, Order2Num, Order3Num ...
First Row of data: 12345, 848884, 848892, 850093, ...

I imagine there's another function/tool altogether to actually create an
empty table and have the names of the column headings generated on the fly.


Duane Hookom said:
You need to create a calculated column in your query that numbers your
records for each CustNum. This is usually done with DCount(). You can then
use the resulting value as a column heading for a crosstab query.

--
Duane Hookom
MS Access MVP


Chris said:
That's great, Duane; thanks!

I wasn't very clear on my desired result. Rather than return the top five
child records as one concatenated field, I'd like to return up to five
columns, with each column containing the value from a child record.

So the result of the query would be:
Result of Query
CustNum OrderNum OrderNum OrderNum
CustNum OrderNum
CustNum
CustNum OrderNum OrderNum OrderNum OrderNum OrderNum
CustNum OrderNum OrderNum
CustNum
CustNum OrderNum
with each space-delimited value being a separate column.

Is this possible?


Duane Hookom said:
You should be able to use the generic concatenate function from
http://www.rogersaccesslibrary.com/OtherLibraries.asp#Hookom,Duane. You
expression would be something like:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE
CustNum=""" & CustNum & """ ORDER BY SomeDateFieldNotIdentified DESC")

The above assume CustNum is text, if it is numeric, try:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE
CustNum=" & CustNum & " ORDER BY SomeDateFieldNotIdentified DESC")

--
Duane Hookom
MS Access MVP


For each record in a Customers table, there can be zero or more
associated records in an Orders table. I'm interested in the order
numbers of the five most recent orders for each customer. I'm trying to
write a query that will return the customer number and zero or more
columns--the latter columns containing the order numbers.

Customers (parent)
CustNum

Orders (child)
CustNum
OrderNum

Result of Query
CustNum OrderNum OrderNum OrderNum
CustNum OrderNum
CustNum
CustNum OrderNum OrderNum OrderNum OrderNum OrderNum
CustNum OrderNum OrderNum
CustNum
CustNum OrderNum
...
...

I'm stumped on how to do this. Any thoughts? Thanks!
 
D

Duane Hookom

Your first step is to create the "ranking" query. There are lots of messages
posted regarding how to do this.

Your crosstab will create a column headings that use the ranking column
value to create Order1Num etc.

--
Duane Hookom
MS Access MVP


Chris said:
Thanks, again. I will look into DCount().

Just to be clear (and for my own sanity), the names of the column
*headings* will still be meaningful; i.e., not renamed to be the resulting
values, right? e.g.,

Column heading names: CustNum, Order1Num, Order2Num, Order3Num ...
First Row of data: 12345, 848884, 848892, 850093, ...

I imagine there's another function/tool altogether to actually create an
empty table and have the names of the column headings generated on the
fly.


Duane Hookom said:
You need to create a calculated column in your query that numbers your
records for each CustNum. This is usually done with DCount(). You can
then use the resulting value as a column heading for a crosstab query.

--
Duane Hookom
MS Access MVP


Chris said:
That's great, Duane; thanks!

I wasn't very clear on my desired result. Rather than return the top
five child records as one concatenated field, I'd like to return up to
five columns, with each column containing the value from a child record.

So the result of the query would be:
Result of Query
CustNum OrderNum OrderNum OrderNum
CustNum OrderNum
CustNum
CustNum OrderNum OrderNum OrderNum OrderNum OrderNum
CustNum OrderNum OrderNum
CustNum
CustNum OrderNum
with each space-delimited value being a separate column.

Is this possible?


You should be able to use the generic concatenate function from
http://www.rogersaccesslibrary.com/OtherLibraries.asp#Hookom,Duane. You
expression would be something like:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE
CustNum=""" & CustNum & """ ORDER BY SomeDateFieldNotIdentified DESC")

The above assume CustNum is text, if it is numeric, try:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE
CustNum=" & CustNum & " ORDER BY SomeDateFieldNotIdentified DESC")

--
Duane Hookom
MS Access MVP


For each record in a Customers table, there can be zero or more
associated records in an Orders table. I'm interested in the order
numbers of the five most recent orders for each customer. I'm trying
to write a query that will return the customer number and zero or more
columns--the latter columns containing the order numbers.

Customers (parent)
CustNum

Orders (child)
CustNum
OrderNum

Result of Query
CustNum OrderNum OrderNum OrderNum
CustNum OrderNum
CustNum
CustNum OrderNum OrderNum OrderNum OrderNum OrderNum
CustNum OrderNum OrderNum
CustNum
CustNum OrderNum
...
...

I'm stumped on how to do this. Any thoughts? Thanks!
 
C

Chris

I'm not sure I've properly communicated what I'm trying to accomplish. I
don't think a crosstab query will produce the desired result. Basically, the
first column needs to hold the customer number, the second column needs to
hold the most recent order number, the third column needs to hold the second
most recent order number, etc., up to the sixth column, which needs to hold
the fifth most recent order number, assuming there are that many orders for
the customer. e.g.,

Column Headings: CustNum, OrdNum1, OrdNum2, OrdNum3, OrdNum4, OrdNum5
12345, 850093, 848892, 848884
12346, 850011, 850001
12347, 861234, 859893, 859722, 859701, 859622
12348, 861246

Using your Concatenate function as a base, I wrote a custom function that
takes a customer number and a digit from 1 to 5, representing the desired
most recent order. 1 would be the most recent order; 5 would be the fifth
most recent order. The function executes a SQL statement using the specified
customer number. It then uses a counter to loop through the result set until
the specified digit is reached or EOF. If EOF is not reached, the value in
the current record's field is returned as the function's value. I call the
function like this:

SELECT DISTINCTROW Customers.CustNum, ReturnOrderNum([Customers].[CustNum],
1) AS OrderNum1, ReturnOrderNum([Customers].[CustNum],2) AS OrderNum2,
ReturnOrderNum([Customers].[CustNum],3) AS OrderNum3,
ReturnOrderNum([Customers].[CustNum], 4) AS OrderNum4,
ReturnOrderNum([Customers].[CustNum],5) AS OrderNum5
FROM Customers INNER JOIN Orders ON Customers.CustNum = Orders.CustNum
ORDER BY Customers.CustNum;

Note the increasing digit passed to the ReturnOrderNum function as a
parameter: 1, 2, 3, 4, 5.

This works, but seems overly complex. And if I want to return (say) the *15*
most recent orders, the length of the SQL statement would multiply by a
factor of three. In addition, I'm wondering if it's wise to have the SQL
string embedded within a function. Will this upscale to SQL Server without
too much difficulty?

Is this do-able any other way? Can a crosstab query produce this?

Thanks, so much for your expertise with this. I appreciate your comments and
suggestions.


Duane Hookom said:
Your first step is to create the "ranking" query. There are lots of
messages posted regarding how to do this.

Your crosstab will create a column headings that use the ranking column
value to create Order1Num etc.

--
Duane Hookom
MS Access MVP


Chris said:
Thanks, again. I will look into DCount().

Just to be clear (and for my own sanity), the names of the column
*headings* will still be meaningful; i.e., not renamed to be the
resulting values, right? e.g.,

Column heading names: CustNum, Order1Num, Order2Num, Order3Num ...
First Row of data: 12345, 848884, 848892, 850093, ...

I imagine there's another function/tool altogether to actually create an
empty table and have the names of the column headings generated on the
fly.


Duane Hookom said:
You need to create a calculated column in your query that numbers your
records for each CustNum. This is usually done with DCount(). You can
then use the resulting value as a column heading for a crosstab query.

--
Duane Hookom
MS Access MVP


That's great, Duane; thanks!

I wasn't very clear on my desired result. Rather than return the top
five child records as one concatenated field, I'd like to return up to
five columns, with each column containing the value from a child
record.

So the result of the query would be:
Result of Query
CustNum OrderNum OrderNum OrderNum
CustNum OrderNum
CustNum
CustNum OrderNum OrderNum OrderNum OrderNum OrderNum
CustNum OrderNum OrderNum
CustNum
CustNum OrderNum
with each space-delimited value being a separate column.

Is this possible?


You should be able to use the generic concatenate function from
http://www.rogersaccesslibrary.com/OtherLibraries.asp#Hookom,Duane.
You expression would be something like:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE
CustNum=""" & CustNum & """ ORDER BY SomeDateFieldNotIdentified DESC")

The above assume CustNum is text, if it is numeric, try:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE
CustNum=" & CustNum & " ORDER BY SomeDateFieldNotIdentified DESC")

--
Duane Hookom
MS Access MVP


For each record in a Customers table, there can be zero or more
associated records in an Orders table. I'm interested in the order
numbers of the five most recent orders for each customer. I'm trying
to write a query that will return the customer number and zero or
more columns--the latter columns containing the order numbers.

Customers (parent)
CustNum

Orders (child)
CustNum
OrderNum

Result of Query
CustNum OrderNum OrderNum OrderNum
CustNum OrderNum
CustNum
CustNum OrderNum OrderNum OrderNum OrderNum OrderNum
CustNum OrderNum OrderNum
CustNum
CustNum OrderNum
...
...

I'm stumped on how to do this. Any thoughts? Thanks!
 
D

Duane Hookom

I thought you could find a ranking query like
SELECT CustNum, OrderNum, DCount("OrderNum","Orders","CustNum = " & CustNum
& " AND OrderNum <=" & OrderNum) As Rank
FROM Orders
ORDER BY CustNum, OrderNum;

You can then use the above saved query as the basis for a crosstab query
that uses CustNum as the Row Heading, First Of OrderNum as the Value, and
"OrderNum" & Rank as the Column Heading.

--
Duane Hookom
MS Access MVP


Chris said:
I'm not sure I've properly communicated what I'm trying to accomplish. I
don't think a crosstab query will produce the desired result. Basically,
the first column needs to hold the customer number, the second column
needs to hold the most recent order number, the third column needs to hold
the second most recent order number, etc., up to the sixth column, which
needs to hold the fifth most recent order number, assuming there are that
many orders for the customer. e.g.,

Column Headings: CustNum, OrdNum1, OrdNum2, OrdNum3, OrdNum4, OrdNum5
12345, 850093, 848892, 848884
12346, 850011, 850001
12347, 861234, 859893, 859722, 859701, 859622
12348, 861246

Using your Concatenate function as a base, I wrote a custom function that
takes a customer number and a digit from 1 to 5, representing the desired
most recent order. 1 would be the most recent order; 5 would be the fifth
most recent order. The function executes a SQL statement using the
specified customer number. It then uses a counter to loop through the
result set until the specified digit is reached or EOF. If EOF is not
reached, the value in the current record's field is returned as the
function's value. I call the function like this:

SELECT DISTINCTROW Customers.CustNum,
ReturnOrderNum([Customers].[CustNum], 1) AS OrderNum1,
ReturnOrderNum([Customers].[CustNum],2) AS OrderNum2,
ReturnOrderNum([Customers].[CustNum],3) AS OrderNum3,
ReturnOrderNum([Customers].[CustNum], 4) AS OrderNum4,
ReturnOrderNum([Customers].[CustNum],5) AS OrderNum5
FROM Customers INNER JOIN Orders ON Customers.CustNum = Orders.CustNum
ORDER BY Customers.CustNum;

Note the increasing digit passed to the ReturnOrderNum function as a
parameter: 1, 2, 3, 4, 5.

This works, but seems overly complex. And if I want to return (say) the
*15* most recent orders, the length of the SQL statement would multiply by
a factor of three. In addition, I'm wondering if it's wise to have the SQL
string embedded within a function. Will this upscale to SQL Server without
too much difficulty?

Is this do-able any other way? Can a crosstab query produce this?

Thanks, so much for your expertise with this. I appreciate your comments
and suggestions.


Duane Hookom said:
Your first step is to create the "ranking" query. There are lots of
messages posted regarding how to do this.

Your crosstab will create a column headings that use the ranking column
value to create Order1Num etc.

--
Duane Hookom
MS Access MVP


Chris said:
Thanks, again. I will look into DCount().

Just to be clear (and for my own sanity), the names of the column
*headings* will still be meaningful; i.e., not renamed to be the
resulting values, right? e.g.,

Column heading names: CustNum, Order1Num, Order2Num, Order3Num ...
First Row of data: 12345, 848884, 848892, 850093, ...

I imagine there's another function/tool altogether to actually create an
empty table and have the names of the column headings generated on the
fly.


You need to create a calculated column in your query that numbers your
records for each CustNum. This is usually done with DCount(). You can
then use the resulting value as a column heading for a crosstab query.

--
Duane Hookom
MS Access MVP


That's great, Duane; thanks!

I wasn't very clear on my desired result. Rather than return the top
five child records as one concatenated field, I'd like to return up to
five columns, with each column containing the value from a child
record.

So the result of the query would be:
Result of Query
CustNum OrderNum OrderNum OrderNum
CustNum OrderNum
CustNum
CustNum OrderNum OrderNum OrderNum OrderNum OrderNum
CustNum OrderNum OrderNum
CustNum
CustNum OrderNum
with each space-delimited value being a separate column.

Is this possible?


You should be able to use the generic concatenate function from
http://www.rogersaccesslibrary.com/OtherLibraries.asp#Hookom,Duane.
You expression would be something like:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE
CustNum=""" & CustNum & """ ORDER BY SomeDateFieldNotIdentified
DESC")

The above assume CustNum is text, if it is numeric, try:

OrderNums:Concatenate("SELECT TOP 5 [OrderNum] FROM Orders WHERE
CustNum=" & CustNum & " ORDER BY SomeDateFieldNotIdentified DESC")

--
Duane Hookom
MS Access MVP


For each record in a Customers table, there can be zero or more
associated records in an Orders table. I'm interested in the order
numbers of the five most recent orders for each customer. I'm trying
to write a query that will return the customer number and zero or
more columns--the latter columns containing the order numbers.

Customers (parent)
CustNum

Orders (child)
CustNum
OrderNum

Result of Query
CustNum OrderNum OrderNum OrderNum
CustNum OrderNum
CustNum
CustNum OrderNum OrderNum OrderNum OrderNum OrderNum
CustNum OrderNum OrderNum
CustNum
CustNum OrderNum
...
...

I'm stumped on how to do this. Any thoughts? Thanks!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top