I am trying to concatenate a list of attributes for same products which are in different rows.
For example:
Column A (fruit_name) has fruit names and Column B (fruit_colors) has colors.
I want fruit color on the same row as the fruit.
|**fruit_name** | **fruit_colors** |
|----------------|------------------|
|Apple |Red |
|Apple |Yellow |
|Apple |Green |
|Apple |White |
|Banana |Red |
|Banana |Yellow |
|Banana |Green |
|Banana |White |
|Plum |White |
|Plum |Bluish |
|Plum |Purple |
The result should be:
|**name** | **colors** |
|----------------|---------------------------|
|Apple | Red, Yellow, Green, White |
|Banana | Red, Yellow, Green, White |
|Plum | White, Bluish, Purple |
This is what I have:
Set fruit_name = rstsource.Fields("fruits")
Set source_fruit = rstsource.Fields("fruits_list_type")
rstsource.MoveFirst
count = rstsource.RecordCount
counter = 0
fruit_name = source_fruit
result = source_table
Do
Do
counter = counter + 1
result = result & ", " & source_table
rstsource.MoveNext
Loop Until counter = count Or fruit_name <> source_fruit
rstdest.AddNew
rstdest.Fields("names") = fruit_name
rstdest.Fields("colors") = result
rstdest.Update
fruit_name = source_fruit
result = " "
Loop Until rstsource.EOF
This is the result - Some has comma on the front.
Banana - White, White
Apple - ,Yelow, Red
Banana- ,Red
Banana - White, White
Apple , Green
Plum - ,Green
Plum - ,Red
Banana - ,Red
At the end there is a
Run time error 3021.
I would have a read and download of Allen Browne's Concat function http://allenbrowne.com/func-concat.html - It will do exactly what you want.
This will be for report or display purposes only - you shouldn't store the data like this.
How to create this query to combine values?
I have a table with the following structure and values:
EventID PersonName
----------- ------------
1 John
1 Peter
1 Sylvia
2 John
2 Sylvia
3 Peter
3 June
I'd like to run a query and get results in the following format:
EventID PersonNames
-------- ---------------
1 John, Peter, Sylvia
2 John, Sylvia
3 Peter, June
Is there a query that will accomplish this?
Concatenate fields in same table
Author(s) Dev Ashish
(Q) I need to concatenate a field in the format "Value1; Value2; Value3" etc. for each unique value of another field in the same table. How can I do this?
(A) Using the fConcatFld function, in the Northwind database, the following query should return a concatenated list of all CustomerIDs if you group by ContactTitle.
SELECT ContactTitle, fConcatFld("Customers","ContactTitle","CustomerID","string",[ContactTitle]) AS CustomersFROM CustomersGROUP BY ContactTitle;
'************ Code Start **********
'This code was originally written by Dev Ashish
'It is not to be altered or distributed,
'except as part of an application.
'You are free to use it in any application,
'provided the copyright notice is left unchanged.
'
'Code Courtesy of
'Dev Ashish
'
Function fConcatFld(stTable As String, _
stForFld As String, _
stFldToConcat As String, _
stForFldType As String, _
vForFldVal As Variant) _
As String
'Returns mutiple field values for each unique value
'of another field in a single table
'in a semi-colon separated format.
'
'Usage Examples:
' ?fConcatFld(("Customers","ContactTitle","CustomerID", _
' "string","Owner")
'Where Customers = The parent Table
' ContactTitle = The field whose values to use for lookups
' CustomerID = Field name to concatenate
' string = DataType of ContactTitle field
' Owner = Value on which to return concatenated CustomerID
'
Dim lodb As Database, lors As Recordset
Dim lovConcat As Variant, loCriteria As String
Dim loSQL As String
Const cQ = """"
On Error GoTo Err_fConcatFld
lovConcat = Null
Set lodb = CurrentDb
loSQL = "SELECT [" & stFldToConcat & "] FROM ["
loSQL = loSQL & stTable & "] WHERE "
Select Case stForFldType
Case "String":
loSQL = loSQL & "[" & stForFld & "] =" & cQ & vForFldVal & cQ
Case "Long", "Integer", "Double": 'AutoNumber is Type Long
loSQL = loSQL & "[" & stForFld & "] = " & vForFldVal
Case Else
GoTo Err_fConcatFld
End Select
Set lors = lodb.OpenRecordset(loSQL, dbOpenSnapshot)
'Are we sure that duplicates exist in stFldToConcat
With lors
If .RecordCount <> 0 Then
'start concatenating records
Do While Not .EOF
lovConcat = lovConcat & lors(stFldToConcat) & "; "
.MoveNext
Loop
Else
GoTo Exit_fConcatFld
End If
End With
'That's it... you should have a concatenated string now
'Just Trim the trailing ;
fConcatFld = Left(lovConcat, Len(lovConcat) - 2)
Exit_fConcatFld:
Set lors = Nothing: Set lodb = Nothing
Exit Function
Err_fConcatFld:
MsgBox "Error#: " & Err.Number & vbCrLf & Err.Description
Resume Exit_fConcatFld
End Function
'************ Code End **********
Copy and paste the fConcatFld( ) function into a code module. Change the
following VBA line of code:
lovConcat = lovConcat & lors(stFldToConcat) & "; "
to:
lovConcat = lovConcat & lors(stFldToConcat) & ", "
... then save it and compile the code.
Next, create a new query and open the query in SQL View and paste the
following SQL statement into the SQL View pane:
SELECT EventID, fConcatFld("MyTable","EventID","PersonName","Long", EventID)
AS PersonNames
FROM MyTable
GROUP BY EventID;
... and replace "MyTable" with the name of your table. If the "EventID"
data type isn't Long, then you'll need to replace this in the SQL statement,
too, with whatever data type your field is using.
Save and run the query. Voila! Comma separated list.
Related
Alright, so here's what happened :
I had a wide table, that needed to be a long table. I used the code below (CODE 1) to fix that problem:
It seemed to have worked, though I am now finding minor errors in the data, while I will need to resolve those, that isn't what this question is about.
In the end, my table looks correctly, and here is an actual record from the database, in fact it is the record that called my attention to the issues:
tbl_CompletedTrainings:
ID
Employee
Training
CompletedDate
306
Victoria
Clozaril
5/18/2016
306
20
8
5/18/2016
the second row is to show what the database is actually seeing (FK with both Employee and Training tables) Those tables have the following formats:
tbl_employeeInformation:
ID
LastName
FirstName
Address
Line2
City
State
Zip
Site1
Site2
Site3
20
A.
Victoria
6 Street
City
State
00000
3NNNN
4
Eric
A.
15 Street
City
State
00000
3nnnnn
tbl_Trainings:
AutoID
TrainingName
Expiration
6
Bloodborne
Annual
8
Clozaril
Annual
When the query in (CODE 2) is run on this table, the following record is returned
report Query:
LastName
FirstName
Training
CompletedDate
Site1
Site2
Site3
ID
Accccc
Eric
Bloodborne Pathogens
5/18/2016
3NN-NN
N/A
N/A
306
Notice that the ID in the report Query is only there as I was checking records, and is called from the tbl_CompletedTrainings. So here's the question, What is happening?! If the record was just wrong, and not pulled I could understand it, but that's not what's happening. Worse still is the date is the correct date for the training the query returns, but not for the training listed in the table.
Related issue, possibly, I had noticed that when I queried the table with a call on the foreign key, it returns records that are 2 off of the requested training number. Notice that this is the case here as well. The training listed, Clozaril, is exactly two further down the line than the training Bloodborne Pathogens, Key 8 and 6 respectively.
Any help would be very much appreciated in this matter, as I can't seem to catch what is causing the issue. Yet it must be something.
(CODE 1)
Option Compare Database
Option Explicit
Sub unXtab()
On Error GoTo ErrHandler
Dim db As DAO.Database
Dim rsxtab As DAO.Recordset
Dim rsutab As DAO.Recordset
Dim counter As Integer
Dim loopint As Integer
Dim qryGetNameID As DAO.Recordset
Dim qryGetTrainingNameID As DAO.Recordset
Dim expires As Date
Dim namevar As String
Dim lname As String
Dim fname As String
Set db = CurrentDb
Set rsxtab = db.OpenRecordset("SELECT * FROM [Employee Training Log];")
If Not (rsxtab.BOF And rsxtab.EOF) Then
db.Execute "DELETE * FROM tbl_CompletedTrainings;"
Set rsutab = db.OpenRecordset("SELECT * FROM tbl_CompletedTrainings WHERE 1 = 2;")
counter = rsxtab.Fields.Count - 1
Do
For loopint = 2 To counter
namevar = rsxtab.Fields(loopint).Name
lname = rsxtab("[Last Name]")
fname = rsxtab("[First Name]")
Select Case namevar
Case "First Name"
Case "Last Name"
Case "Date of Hire"
Case Else
If rsxtab.Fields(loopint) <> "" Or Not IsNull(rsxtab.Fields(loopint)) Then
Set qryGetTrainingNameID = db.OpenRecordset("SELECT AutoID FROM Trainings WHERE [Training Name] = " & Chr(34) & namevar & Chr(34) & ";")
Set qryGetNameID = db.OpenRecordset("SELECT ID FROM tbl_EmployeeInformation WHERE LastName = " & Chr(34) & lname & Chr(34) & _
" AND " & Chr(34) & fname & Chr(34) & ";")
rsutab.AddNew
Debug.Print lname
Debug.Print fname
Debug.Print namevar
Debug.Print qryGetNameID.Fields(0)
Debug.Print qryGetTrainingNameID.Fields(0)
rsutab.AddNew
rsutab("Employee") = qryGetNameID.Fields(0)
rsutab("Training") = qryGetTrainingNameID.Fields(0)
rsutab("CompletedDate") = rsxtab.Fields(loopint)
rsutab.Update
End If
End Select
Next loopint
rsxtab.MoveNext
Loop Until rsxtab.EOF
End If
exitSub:
On Error Resume Next
rsxtab.Close
rsutab.Close
Set rsxtab = Nothing
Set rsutab = Nothing
Set db = Nothing
Exit Sub
ErrHandler:
MsgBox Err.Number & " : " & Err.Description & vbCrLf & vbCrLf & " on this field: " & namevar, vbOKOnly + vbCritical
End Sub
(CODE 2)
SELECT EI.LastName, EI.FirstName, T.TrainingName AS Training, CT.CompletedDate, EI.Site1, EI.Site2, EI.Site3, CT.ID
FROM tbl_EmployeeInformation AS EI
INNER JOIN (tbl_CompletedTrainings AS CT
INNER JOIN tbl_Trainings AS T ON CT.Training = T.AutoID) ON EI.ID = CT.Employee;
I have
Table student, student_subject and subject_bsit
"student"
-----------------------
|studentID | FullName |
-----------------------
|1234 | John |
|1235 | Michael |
|1236 | Bryce |
"subject_bsit"
-----------------------------------
|subject_id| subject_name |grade |
-----------------------------------
| 1 | Programming | 3 |
| 2 | Networking | 2.5 |
| 3 | Algorithm | 1.75|
| 4 | Physical Educ | 2 |
This is the Junction table to connect the
two now.
"student_subject"
----------------------------
| student_id | subject_id |
----------------------------
| 1235 | 1 |
| 1235 | 2 |
| 1235 | 3 |
| 1234 | 1 |
As you can see the table ID 1235 is michael He has three three subjects, subject_id 1,2 and 3. What I want to do is to display all the subject name and grades of michael in textboxes, not in a datagrid view.
As of now I still have failed to output it to textboxes. This is my sample query
sql = "SELECT subject_name " & _
" FROM student_subject " & _
" INNER JOIN subject_bsit ON subject_bsit.subject_id = student_subject.sub_id" & _
" where student_subject.student_id='" & Txtbox.Text & "'"
The Txtbox.text in the last query is where the user will input the ID number.
This is my code on displaying the data to the textbox. I don't have any idea or approach on how can i loop on the textbox and display it on each textbox.
cmd = New MySqlCommand(sql, myconn)
dr = cmd.ExecuteReader
While dr.Read
TextBox1.Text = dr.Item("subject_name").ToString
TextBox2.Text = dr.Item("subject_name").ToString
End While
This is the sample User Interface of what i am trying to achieve. Thank you so much.
When you read a query's resultset, you use a loop as you know.
While dr.Read
' run this for every row in your resultset
...
End While
The While loop keeps going until you have read all the rows.
You don't have to use a loop. If you wish you can read the rows one at a time, like this
If dr.Read
' just the first row
End If
If dr.Read
' just the second row
End If
If dr.Read
' just the third row
End If
...
From your question I guess you have Textbox1, Textbox2, ... Textbox5 on your form. I also guess you have Grade1, Grade2 ....
To handle both of the subject name and grade, change the first line of your query to
sql = "SELECT subject_name, grade " & _
You can populate those items like this:
If dr.Read
TextBox1.Text = dr.Item("subject_name").ToString
Grade1.Text = dr.Item("grade").ToString
End If
If dr.Read
TextBox2.Text = dr.Item("subject_name").ToString
Grade2.Text = dr.Item("grade").ToString
End If
If dr.Read
TextBox3.Text = dr.Item("subject_name").ToString
Grade3.Text = dr.Item("grade").ToString
End If
' more of these sets of four lines to fill your whole form.
This solves your problem. But you probably notice it is absurdly repetitive. What you really need is an array (actually two arrays) of textboxes. You create, and then fill in, these texboxes in your program. I have not debugged this: that is for you do to.
Dim Subjects As Textbox()
Dim Grades As Textbox()
...
Dim rownumber, Y
rownumber = 0
Y = 200
Dim Subject
Dim Grade
While dr.Read
Subject = New Textbox
Subject.Text = dr.Item("subject_name").ToString
Subject.Width = 200
Subject.Height = 40
Subject.X = 175
Subject.Y = Y
Subjects(rownumber) = Subject
Form.Controls.Add(Subject)
Grade = New Textbox
Grade.Text = dr.Item("grade").ToString
Grade.Width = 50
Grade.Height = 40
Grade.X = 400
Grade.Y = Y
Grades(rownumber) = Grade
Form.Controls.Add(Grade)
rownumber = rownumber + 1
Y = Y + 50
End While
When this runs you will have two columns of controls, one for each subject. But this code is complex, and you have to do all the layout of your form with Something.Y = value and then Y = Y + 50 arithmetic.
That's why grid controls exist. They take care of that kind of thing.
If you are looking to create Textboxes dynamically then you should refer to the #OJones answer
You can simply loop over Me.Controls.OfType(Of TextBox)()
cmd = New MySqlCommand(sql, myconn)
dr = cmd.ExecuteReader
While dr.Read
For Each txt As TextBox In Me.Controls.OfType(Of TextBox)()
txt.Text = dr.Item("subject_name").ToString
Next
End While
Or you can do a similar approach if you need to fill the first subjects name inside the textboxes (if returned subjects are more than textboxes additional subjects will be ignored):
While dr.Read = True
Dim txt As New TextBox = DirectCast(Me.Controls.Find(string.Format("Textbox{0}", cnt ),false).FirstOrDefault(),Textbox);
If Not txt Is Nothing Then txt.Text = dr.Item("subject_name").ToString
cnt += 1
End While
dr.Close()
I'm having a problem with an Access 2010 database where the Primary Key of a new record is also being added to a non-related field when I move to another control on the linked form.
My minimal database consists of a single table called Teams. There are four fields in the table:
+-----------------+-----------+-----------+--------------+
| TeamID | TeamName | CostCode | SortOrder |
+-----------------+-----------+-----------+--------------+
| AutoNumber (PK) | Text(255) | Text(255) | Long Integer |
+-----------------+-----------+-----------+--------------+
This table is linked by the Record Source to a form called Edit_Teams.
There are three controls on the form:
+-----------------+-------------+-----------+------------------------------------+
| Control: | TextBox | TextBox | ComboBox |
+-----------------+-------------+-----------+------------------------------------+
| Name: | txtCostCode | txtTeamID | cmbTeamName |
| Control Source: | CostCode | TeamID | - |
| Row Source: | - | - | SELECT TeamID, TeamName FROM Teams |
+-----------------+-------------+-----------+------------------------------------+
The combobox is bound to column 1, Limit To List = Yes
The form has some code to keep the combobox in sync with the rest of the form when you move between records:
Private Sub Form_Current()
If Not IsNull(Me.txtTeamID) Then
Me.cmbTeamName.Requery
Me.cmbTeamName = Me.txtTeamID
If Me.cmbTeamName <> 0 Then
'Some other code that adds stuff to a subform.
Me.Refresh
End If
Else
Me.cmbTeamName = 0
End If
End Sub
The combobox has two events:
Private Sub cmbTeamName_AfterUpdate()
If Me.cmbTeamName = "0" Then
DoCmd.GoToRecord , , acNewRec
Else
GoToBookmark Me, "TeamID", cmbTeamName
If cmbTeamName <> 0 Then
'Some other code that adds stuff to a subform.
Me.Refresh
End If
End If
End Sub
and
Private Sub cmbTeamName_NotInList(NewData As String, Response As Integer)
With DoCmd
.SetWarnings False
If MsgBox("Add '" & NewData & "' as a new team?", vbYesNo + vbQuestion) = vbYes Then
.RunSQL "INSERT INTO Teams(TeamName, CostCode, SortOrder) " & _
"VALUES ('" & NewData & "', Null," & DCount("TeamID", "Teams") + 1 & ")"
Response = acDataErrAdded
Me.cmbTeamName = Me.cmbTeamName.ItemData(0) 'Move to an item that exists so Requery doesn't fire NotInList.
Me.Requery
GoToBookmark Me, "TeamName", NewData
Me.cmbTeamName.Requery
Me.cmbTeamName = DLookup("TeamID", "Teams", "TeamName='" & TeamName & "'")
Me.txtCostCode.SetFocus
Else
Response = acDataErrContinue
Me.cmbTeamName.Undo
End If
.SetWarnings True
End With
End Sub
There's also this which is used within the previous procedures:
Public Sub GoToBookmark(frm As Form, FieldName As String, FieldValue As String)
Dim rst As DAO.Recordset
Dim rst_Type As Long
On Error GoTo ERR_HANDLE
Set rst = frm.RecordsetClone
FieldName = "[" & FieldName & "]"
Select Case rst.Fields(FieldName).Type
Case 4 'dbLong
rst.FindFirst FieldName & "=" & FieldValue
Case 10 'dbText
rst.FindFirst FieldName & "='" & FieldValue & "'"
End Select
If Not (rst.BOF And rst.EOF) Then
frm.Recordset.Bookmark = rst.Bookmark
End If
rst.Close
EXIT_PROC:
Set rst = Nothing
On Error GoTo 0
Exit Sub
ERR_HANDLE:
'Commented out so I don't have to post the DisplayError procedures.
'DisplayError Err.Number, Err.Description, "mdl_GoToBookMark.GoToBookmark()"
Resume EXIT_PROC
End Sub
The problem:
When I type a new team name into the combobox it asks whether I want to add it to the team list, it then adds the team and moves me to the CostCode textbox where I can type in a cost code if available.
If a cost code isn't available the control should remain blank, but when I move to another control or record (i.e the control loses the focus) then the Primary Key for that record appears in the CostCode textbox and is saved when I change records (losing focus just puts it in the textbox, it doesn't appear in the table until the record is saved).
Your problem lies in the following line:
Response = acDataErrAdded
This line triggers Access to set the field that has focus equal to the value you just added as soon as it loses focus. Because you change focus to a different field, you get this weird behaviour.
Change it for Response = acDataErrContinue (that basically tells Access to not care about what you entered, and lets you handle it yourself) and your code should behave as expected.
I have an example data in Access2010 .mdb as described below, the PipeId is the same for the three TVObservations. The FS, OB and RB describes the kind of observation, I need in to count the number of observations.
SampleData:
| PipeID | TVObservation | NumberOf |
|--------|---------------|----------|
| 301 | FS | 2 |
| 301 | OB | 2 |
| 301 | RB | 1 |
Needed output:
| PipeID | NumberOf |
|--------|---------------------|
| 301 | FS: 2, OB: 2, RB: 1 |
I can get the number of observations, but returning the observations with a Name/title before it, in one cell is proving difficult.
Count(Iif([TVObservation]="FS",True,IIf([TVObservation]="OB",True,IIf(TVObservation]="RB",True,Null)))) AS NumberOf
As a follow-on from what #krish-km mentioned, here's a function I've adapted from Allen Browne's ConcatRelated function (note that I've removed a lot of the original's general purpose utility, so should only be used for your specific scenario).
Put this in a VBA module...
Public Function ConcatRelated(strField1 As String, _
strField2 As String, _
strRelField As String, _
lngRelFieldVal As Long, _
strOrderBy As String, _
strTable As String, _
Optional strSeparator = ", ") As Variant
On Error GoTo Err_Handler
Dim db As DAO.Database ' Database
Dim rs As DAO.Recordset '
Dim strSql As String ' SQL statement
Dim strOut As String ' Output string to concatenate to.
Dim lngLen As Long ' Length of string.
' Initialize to Null
ConcatRelated = Null
' Find related records limited by related field
strSql = "SELECT " & strRelField & ", " & strField1 & ", " & strField2 _
& " FROM " & strTable & " WHERE " & strRelField & " = " & lngRelFieldVal _
& " ORDER BY " & strOrderBy
Set db = CurrentDb
Set rs = db.OpenRecordset(strSql)
' Loop through related fields to build comma separated list
Do While Not rs.EOF
strOut = strOut & rs.Fields(strField1) & ": " & rs.Fields(strField2) & strSeparator
rs.MoveNext
Loop
rs.Close
' Return the string without the trailing separator.
lngLen = Len(strOut) - Len(strSeparator)
If _
lngLen > 0 _
Then
ConcatRelated = Left(strOut, lngLen)
End If
Exit_Handler:
'Clean up
Set rs = Nothing
Set db = Nothing
Exit Function
Err_Handler:
MsgBox "Error " & Err.Number & ": " & Err.Description, vbExclamation, "ConcatRelated()"
Resume Exit_Handler
End Function
You'll then be able to use this function in an SQL statement.
The first and second arguments are your 2 fields that you want to concatenate in to the comma-separated list; these are passed as strings so use double-quotes.
The third and forth argument is the the field whose value is the same across the records you're trying to summarise (in your case it's PipeID). Note that argument 3 needs to be in double-quotes "PipeID" and argument 4 is the sql-reference field, so mustn't be in quotes tblTvObservations.PipeID.
The fifth argument is the field you've specified in either strField or strField2 that you want the comma separated list to be ordered by.
The sixth and final argument is the table/query name where this data comes from.
Here's an example of it used in an sql query...
SELECT tblTvObservations.PipeID, ConcatRelated("TVObservation","NumberOf","PipeID",tblTvObservations.PipeID,"TVObservation","tblTvObservations") AS NumberOf
FROM tblTvObservations;
...to get the following result:
I've been trying to output my results from a table as a String for awhile now. Whenever I use a query in my table and call the Field Table Adapter, it will always show a foreign key constraint exception. I have deleted all my primary and foreign keys to test but it still shows the same exception. I have tried using this code to output to a textbox :
Public Sub listfields()
Dim ds As New DataSet
Dim dt As DataTable = ds.Tables.Item("")
Dim fieldname As String = Field_nameComboBox.SelectedItem
dt = FieldvalueTableAdapter.GetData
Dim i As Integer = 0
While i < dt.Rows.Count
txtbx_field_list.Text = dt.Rows(i).Item("field_name")
txtbx_field_list2.Text = dt.Rows(i).Item("field_value")
txtbx_field_list3.Text = dt.Rows(i).Item("sort_priority")
i += 1
End While
End Sub
However, this shows the last item in the array only. Is there a way to either use a query to output data I want as a string or a method of placing the results into a string?
Thank you.
if you want to show all you records in one textBox with delimiter |
use :
Dim i As Integer = 0
While i < dt.Rows.Count - 1
txtbx_field_list.Text += " | " & dt.Rows(i).Item("field_name") & " | " & Environment.NewLine
txtbx_field_list2.Text += " | " & dt.Rows(i).Item("field_value") & " | " & Environment.NewLine
txtbx_field_list3.Text += " | " & dt.Rows(i).Item("sort_priority") & " | " & Environment.NewLine
i += 1
End While
I still don;t uderstand what you want:
+---------------------+------------------------------+---------------------+
|Name 1 | Name2 | Name 3 | Val 1 Val2 Val3|sort1 sort2 sort3|
or you want
Name1 | val1 | sort1 |
Name2 | val2 | sort2 | etc..
You are overriding each of the text Box variables on each loop iteration.
Change the '=' to '+=' to get all items,
add delimiters if necessary.