I have a table, call it TBL. It has two columns,call them A and B. Now in the query I require one column as A and other column should be a comma seprated list of all B\'s wh
@Remou on DHookom's Concatenate function: neither the SQL standard nor the Jet has a CONCATENATE()
set function. Simply put, this is because it is a violation of 1NF. I'd prefer to do this on the application side rather than try to force SQL to do something it wasn't designed to do. Perhaps ACE's (Access2007) multi-valued types is a better fit: still NFNF but at least there is engine-level support. Remember, the question relates to a stored object: how would a user query a non-scalar column using SQL...?
@David W. Fenton on whether Jet has stored procedures: didn't you and I discuss this in the newsgroups a couple of years ago. Since version 4.0, Jet/ACE has supported the following syntax in ANSI-92 Query Mode:
CREATE PROCEDURE procedure (param1 datatype[, param2 datatype][, ...]) AS sqlstatement;
EXECUTE procedure [param1[, param2[, ...]];
So Jet is creating and executing something it knows (in one mode at least) as a 'procedure' that is 'stored' in the MDB file. However, Jet/ACE SQL is pure and simple: it has no control-of-flow syntax and a PROCEDURE
can only contain one SQL statement, so any procedural code is out of the question. Therefore, the answer to whether Jet has stored procedures is subjective.
To accomplish your task you will need to use code. One solution, using more meaningful names, is as follows:
Main table with two applicable columns:
Table Name: Widgets
Field 1: ID (Long)
Field 2: Color (Text 32)
Add table with two columns:
Table Name: ColorListByWidget
Field 1: ID (Long)
Field 2: ColorList (Text 255)
Add the following code to a module and call as needed to update the ColorListByWidget table:
Public Sub GenerateColorList()
Dim cn As New ADODB.Connection
Dim Widgets As New ADODB.Recordset
Dim ColorListByWidget As New ADODB.Recordset
Dim ColorList As String
Set cn = CurrentProject.Connection
cn.Execute "DELETE * FROM ColorListByWidget"
cn.Execute "INSERT INTO ColorListByWidget (ID) SELECT ID FROM Widgets GROUP BY ID"
With ColorListByWidget
.Open "ColorListByWidget", cn, adOpenForwardOnly, adLockOptimistic, adCmdTable
If Not (.BOF And .EOF) Then
.MoveFirst
Do Until .EOF
Widgets.Open "SELECT Color FROM Widgets WHERE ID = " & .Fields("ID"), cn
If Not (.BOF And .EOF) Then
Widgets.MoveFirst
ColorList = ""
Do Until Widgets.EOF
ColorList = ColorList & Widgets.Fields("Color").Value & ", "
Widgets.MoveNext
Loop
End If
.Fields("ColorList") = Left$(ColorList, Len(ColorList) - 2)
.MoveNext
Widgets.Close
Loop
End If
End With
End Sub
The ColorListByWidget Table now contains your desired information. Be careful that the list (colors in this example) does not exceed 255 characters.
Well, you can use a Recordset object to loop through your query in VBA, concatenating field values based on whatever criteria you need.
If you want to return the results as strings, you'll be fine. If you want to return them as a query, that will be more complicated. You might have to create a temporary table and store the results in there so you can return them as a table or query.
You can concatenate the records with a User Defined Function (UDF).
The code below can be pasted 'as is' into a standard module. The SQL for you example would be:
SELECT tbl.A, Concatenate("SELECT B FROM tbl
WHERE A = " & [A]) AS ConcA
FROM tbl
GROUP BY tbl.A
This code is by DHookom, Access MVP, and is taken from http://www.tek-tips.com/faqs.cfm?fid=4233
Function Concatenate(pstrSQL As String, _
Optional pstrDelim As String = ", ") _
As String
'example
'tblFamily with FamID as numeric primary key
'tblFamMem with FamID, FirstName, DOB,...
'return a comma separated list of FirstNames
'for a FamID
' John, Mary, Susan
'in a Query
'(This SQL statement assumes FamID is numeric)
'===================================
'SELECT FamID,
'Concatenate("SELECT FirstName FROM tblFamMem
' WHERE FamID =" & [FamID]) as FirstNames
'FROM tblFamily
'===================================
'
'If the FamID is a string then the SQL would be
'===================================
'SELECT FamID,
'Concatenate("SELECT FirstName FROM tblFamMem
' WHERE FamID =""" & [FamID] & """") as FirstNames
'FROM tblFamily
'===================================
'======For DAO uncomment next 4 lines=======
'====== comment out ADO below =======
'Dim db As DAO.Database
'Dim rs As DAO.Recordset
'Set db = CurrentDb
'Set rs = db.OpenRecordset(pstrSQL)
'======For ADO uncomment next two lines=====
'====== comment out DAO above ======
Dim rs As New ADODB.Recordset
rs.Open pstrSQL, CurrentProject.Connection, _
adOpenKeyset, adLockOptimistic
Dim strConcat As String 'build return string
With rs
If Not .EOF Then
.MoveFirst
Do While Not .EOF
strConcat = strConcat & _
.Fields(0) & pstrDelim
.MoveNext
Loop
End If
.Close
End With
Set rs = Nothing
'====== uncomment next line for DAO ========
'Set db = Nothing
If Len(strConcat) > 0 Then
strConcat = Left(strConcat, _
Len(strConcat) - Len(pstrDelim))
End If
Concatenate = strConcat
End Function