Your original table isn’t normalized, which makes it rather difficult. You should have a seperate table for customers and products, making the join trivial.
I don’t know Access, I’m a Filemaker person, but sometimes the same concepts apply even if the implementation is a little different.
In Filemaker, I’d create a relationship between the file and itself (a self-join relationship) based on Customer Name. Then I’d drag a portal onto the layout and select the self-join relationship I’d just created, and drag the field Product onto the portal. Enter browse mode and bingo, a list of all products for which the current customer is the customer.
That would look like this:
John Smith
Computer
Mouse
keyboard
In FileMaker it’s a little less convenient if you want it to appear as you originally typed it (with the values in a horizontal row to the side of the customer name rather than arrayed below the customer name) and although I know how to make it do that, it is less likely to have any bearing on how to do so in Accessl.
First, you decide which is the crucial, central data. In this case, it would seem to be the name, “John Smith”. You then have a table centering around name. It will undoubtedly be useful to assign some kind of code to that, for instance, Social Security Number, or some assigned Employee code. Use this as the “key” field. You really, really dont want to use “John Smith”.
In the table “Equipment” track John Smiths number (say, “001”) relative to his equipment thus
001 Mouse
001 Computer
001 Mouse pad
etc. etc. This table will center around the number, but not as a “key” field because you need to be able to repeat the number.
Look for Peach.Ease.Lsoft.com. There is an Access board there that is very helpful, and many of the denizens are eager to help out the neophyte.
Sorry…normalization is the process of organizing your data such that you eliminate redundancy. This is the whole purpose of relational databases.
In your current setup, you have one table which includes the person and the product. Since the same person can be associated with more than one product, you have to enter that person’s name several times; this is redundant, and called a “one to many relationship.” The proper way to do it would be to have one table full of people, with a number for each person, and one table full of products, which a number for each product. You could then have a third table relating each product with each person, for example:
Products:
ID Name
1. Keyboard
2. Mouse
3. Computer
People:
ID Name
1. John Smith
2. Bob Jones
Now, to keep track of who has what, you would make a table like this:
Person Product
1 1
1 2
2 3
You could then to a simple select on the third table to see that John Smith has a keyboard and a mouse, and Bob Jones has a computer. (Look up “joins” in your Access manual.)
OK, yes, I understand the concept of a relational database. I’ve been working with this stuff for a while now, just havne’t taken any courses. But you’ve missed my question.
I have my SELECT query. It looks like this:
(Customer) (Product)
John Smith Computer
John Smith Mouse
John Smith Keyboard
Jack Wilson Computer
Jack Wilson Modem
etc...
I want it to look like this:
(Customer) (Products)
John Smith Computer, Mouse, Keyboard
Jack Wilson Computer, Modem
This would be simple if Access had an aggregate function that could concatenate text similar to the way the Sum function adds values together. Unfortunately, Access 97 (the version I have) doesn’t have such a function. I wish it did. Does anyone know if any SQL implementation or a later version of access has such a function?
You’ll need more than an Access query to accomplish this. It could be programed in Visual Basic for Access. It could even be done using spreadsheet calculations.
Data normalization won’t help you here but it is worth learning.
You can do this in a report using code, but I can’t think of a way using just SQL. You’re kind of working against the grain of the whole relational thing. Would a report work as well?
The Visual Basic to do this is fairly hairy stuff; not a short answer. Something that kind of gets what you want is to make a query on the database that selects all the fields, and then use Excel to import the Access query/data into a spreadsheet. This will “copy” the original data arrangement into a spreadsheet the same way it is in the database, but then in Excel you can use the data in a pivot table with the names on the left and the products on top of the pivot table. If all the product options are checked to display, Excel gives each different product its own column). You get final results that look something like this:
------------------------------------------------------
Name Keyboard Monitor Mouse Computer
John Doe 1 1
Anne Smith 1 1 1
Jim Baker 1 1
Mary Jones 1 1
--------------------------------------------------------
That is, the number in the product column is the number of *that item[/i that the person has. -I couldn’t find any easy way to get it to put the name of the item into the table, just the number.
You should be able to export the spreadsheet all the same ways you can export the database/query results. - MC
The problem with that you want to do is, you want the database to take one single column of many items and separate it into many columns of single items. For spreadsheet pivot tables that’s easy because that’s what they’re for. I just finished an advanced Access course (Final grade:97%-yay!) and I don’t ever remember seeing this capability mentioned anywhere in Access. - MC
I don’t know how pivot tables work, but I do know that they are suported by MS Access (I have 97 & 2000). Look up pivot tables in the help for more information. Perhaps MC can explain Pivot tables further?
Hope this helps, as the others have said though you would do much better to reorgainise your data in to separate tables.
A pivot table allows you to sort a spreadsheet based on different columns or rows of data. You select the “rows” and “columns” fields and it builds a spreadsheet with as many rows x columns as different values in each, and then fills in the rest of the table accurately, based on the rows and columns. ~ A crosstab query does basically the same thing, for a database dataset.
You can do a crosstab query and get pretty close, but not quite:
(Office 2K) I used a table named CustProd, with fields named Customer and Product. You start with a regular query in design view, and go up to the toolbar and switch it to a crosstab query (there’s a button with several types on a pop-up menu).
On the design grid, the first query column reads like this:
Field: Product
Table: Custprod
Total: Group By (the default value)
Crosstab: Value
Sort (blank)
Criteria (blank)
The second field reads like this:
Field: Customer Name
Table: Custprod
Total: Group By (default value)
Crosstab: Column Heading
Sort: (blank)
Criteria: (blank)
The third field reads like this:
Field: Product
Table: Custprod
Total: Expression
Crosstab: Row Heading
Sort: (blank)
Criteria: (blank)
The problem is that I don’t know if you can hide the first field in the results that you want. You can adjust the first column width to zero and hide it on-screen, but I don’t know that doing so keeps it out of any conversion results. - MC
As a general principal, SQL (queries) is used to retrieve data, reports and forms are use to present the data. You’re trying to get SQL to do the presentation. I think your best bet for an answer, if there is one, is here.
If you can’t use Libertarian’s method of an ASP page doing all the work, and you absolutely have to use a query, here’s an approach you can use. Create a calculated field in your query, have that field call a custom function created in a VB module, pass in the Customer name (or Customer ID if normalized) into the custom function, then use it to walk a recordset and have the function return the created string. You can use Lib’s code as a guide, but you don’t need the Index or the outer Do Loop.
Here’s my stab at it. I should have created this code a long time ago rather than messing with Excel.
Assuming that you have a table named “test” with the fields “Product” and “Customer”, use the following query:
SELECT test.Customer, CommaList("test","Product","Customer",[Customer]) AS Expr1
FROM test GROUP BY test.Customer;
This query calls the CommaList function. The code for this function is as follows.
'--------------------------------------------------------------------------
' CommaList returns a comma-delimited list of values associated with
' a key value from multiple records in a Microsoft Access table.
' tableName - the table containing the values
' commaField - the field whose values will be returned
' keyField - the field where the key value is found
' keyValue - the key value
'--------------------------------------------------------------------------
Public Function CommaList(tableName, commaField, keyField, keyValue) As String
Dim dbs As Database, rst As Recordset
Dim SqlString As String
'Format strings with " and dates with #
If IsDate(keyValue) Then
keyValue = "#" & keyValue & "#"
ElseIf Not (IsNumeric(keyValue)) Then
keyValue = """" & keyValue & """"
End If
'Get commaField from every record where keyField = keyValue
SqlString = "SELECT " & commaField & " FROM " & tableName & _
" WHERE (" & keyField & " = " & keyValue & ");"
Set dbs = CurrentDb()
Set rst = dbs.OpenRecordset(SqlString, dbOpenForwardOnly)
'Put the first commaField value into CommaList
CommaList = rst.Fields(0)
'Step through any additional commaFields and append their values
rst.MoveNext
Do While Not rst.EOF
CommaList = CommaList & ", " & rst.Fields(0)
rst.MoveNext
Loop
End Function
Query1:
Crosstab query, based on the Name/Product table, with
Name with Total=“GroupBy” and Crosstab=“RowHeading”
Product with “GroupBy” and “ColumnHeading”
Product with “Max” and “Value”
Query2:
Simple query based on Query1, with
Name as the first column
“Products” as the second column with the formula
Products: Computer & IIF(Computer<>"",",","") & _
Mouse & IIF(Mouse<>"",",","") & _
Keyboard & IIF(Keyboard<>"",",","")
etc., for as many products as you want to
specify. You *must* specify every product in
the formula to make this work. It would also
behoove you to restrict entry in the Product
field of the table to just these values. If
you got too many products, you might prefer to
create a function to concatenate, but for a
limited number, this would probably be easiest.
I don’t wanna sound like a total idiot, but can you please change your coding so that… "Customers becomes “Website” and “Product” becomes “Webmaster”. I tried, but I’m getting a headache just looking at it. Thank you.