I am trying to create a simple form for entering data. I have two tables, jobs and reports. The report table refers to a job with a one to many (one job, many reports). When browsing through the reports I want the combo box that lists all of the jobs to show the corresponding job as the selected value. This is easy in a .NET environment, but I'm not understanding how to set this up in the property sheet for the combobox. My ComboBox record source is from a query:
SELECT Jobs.UID, Jobs.Projectcode, Jobs.Projectname, Jobs.Owner, Jobs.Contractor
FROM Jobs
ORDER BY Jobs.[Projectcode];
And the form is based on a query that joins the tables:
SELECT Report.ID, Report.ReportNumber, Report.ReportDate, Report.Temperature, Report.Weather, Report.Progress, Report.PeopleatOAC, Report.Trades, Jobs.UID, Jobs.Projectname, Jobs.Owner, Jobs.Contractor
FROM Report
INNER JOIN Jobs ON Jobs.UID = Report.JobID
UNION ALL SELECT Report.ID, Report.ReportNumber, Report.ReportDate,
Report.Temperature, Report.Weather, Report.Progress, Report.PeopleatOAC,
Report.Trades, Jobs.UID, Jobs.Projectname, Jobs.Owner, Jobs.Contractor
FROM Report
LEFT JOIN Jobs ON Jobs.UID = Report.JobID WHERE (((Report.JobID) Is Null))
ORDER BY Report.ID;
The way I have this set up, a report can have a null job field. So I want to be able to select a job from the combo box to update the report table AND I want the combo box to reflect the correct job if the current record has a jobID associated with it. Is this possible?
What I have implemented is a tie to the Current event for the form that sets the combobox value (or clears it) depending on the JobID. As well as an tied to the changed event for the combobox to update the database with a selection. This works well enough but VBA feels so limiting compared to C#, WPF, and MVVM.
For anyone stumbling accross this with a similar question here are the 2 VBA functions:
Private Sub Form_Current()
Dim JobID As Integer
Dim i As Integer
Dim TempVal As Variant
Dim TestVal As Integer
TempVal = Me.JobID.Value
If Me.JobID.Value <> Empty Then
JobID = Me.JobID.Value
Else: JobID = -2
End If
With Me.JobCodeCombo
If (JobID >= 0) Then
For i = 0 To .ListCount - 1
TestVal = .Column(0, i)
If .Column(0, i) = JobID Then
.Value = .ItemData(i)
Exit For
End If
Next
Else
Me.JobCodeCombo = Null
End If
End With
End Sub
Private Sub JobCodeCombo_Change()
Dim ReportID As Long
Dim JobID As Long
Dim dbs As DAO.Database
Dim qdfUpdateJobID As DAO.QueryDef
Dim CurrentRecord As Long
CurrentRecord = Me.CurrentRecord
Set dbs = CurrentDb
Set qdfUpdateJobID = dbs.QueryDefs("UpdateReportWithJobID")
ReportID = Me.ReportID.Value
JobID = Me.JobCodeCombo.Column(0)
qdfUpdateJobID.Parameters(0).Value = JobID
qdfUpdateJobID.Parameters(1).Value = ReportID
qdfUpdateJobID.Execute
qdfUpdateJobID.Close
DoCmd.Save acForm, "Form1"
Me.Requery
DoCmd.GoToRecord acDataForm, "Form1", acGoTo, CurrentRecord
End Sub
The query called from the second function is a simple update query in my access file that has two parameters:
PARAMETERS [P1] Long, [P2] Long;
UPDATE Report SET JobID = P1
WHERE [ID] = P2;
Related
I have imported an existing excel file and created it as table 'Product' in access. It already has rows of existing data. I have created a form based on the table for data entry.
I would like to enter multiple values in the ProductNo cell separated by a comma ( as shown below)
PID (PK - Autonum)
PCR
ProductNo
Title
Unit
Dept
Date
Comments
PCR1
p210en, p213es, p217er
PCR1 title description
2
D1
1/23/21
fdsfsdf
and saving the record, it has to split the cell values and save it as multiple records in the backend product table.
PID (PK - Autonum)
PCR
ProductNo
Title
Unit
Dept
Date
Comments
PCR1
p210en
PCR1 title description
2
D1
01/23/2021
fdsfsdf
PCR1
p213es
PCR1 title description
2
D1
01/23/2021
fdsfsdf
PCR1
p217er
PCR1 title description
2
D1
01/23/2021
fdsfsdf
I don't want to edit the existing data in Product. It correctly reflects only one value in the ProductNo. I want to update only the values entered in the form.
I have looked for similar vba codes and found ones that modifies data in the existing table.
I have worked with SQL before but not much with Access/VBA code. I have programming knowledge. Any help is appreciated. Thank you :)
Updated -- Possible Solution:
So this is what I have done. I have a created a temporary table 'TempProduct' that I have used to input the data and when I click on save button, I have the following vba code that splits the cell data in multiple records and adds it to the original table.
enter code here
Option Compare Database
Private Sub Command11_Click()
Dim db As Database
Dim rs1 As Recordset
Dim rs2 As Recordset
Set db = CurrentDb()
Dim sqlStr, fieldStr As String
Dim i As Integer
sqlStr = "Select PCR, ProductNo, Title, Unit, Dept, Date, Comments from TempProduct"
Set rs1 = db.OpenRecordset(sqlStr)
Set rs2 = db.OpenRecordset("Product")
Do While Not rs1.EOF
fieldStr = rs1.Fields(1)
If InStr(fieldStr, ",") > 0 Then
myString = Split(fieldStr, ",")
For i = LBound(myString) To UBound(myString)
rs2.AddNew
rs2!PCR = rs1!ECRNo
rs2!ProductNo = myString(i)
rs2!Title = rs1!Title
rs2!Unit = rs1!Unit
rs2!Dept = rs1!Dept
rs2!Date = rs1!Date
rs2!Comments=rs1!Comments
rs2.Update
Next i
Else
rs2.AddNew
rs2!PCR = rs1!ECRNo
rs2!ProductNo = rs1!ProductNo
rs2!Title = rs1!Title
rs2!Unit = rs1!Unit
rs2!Dept = rs1!Dept
rs2!Date = rs1!Date
rs2!Comments=rs1!Comments
rs2.Update
End If
rs1.MoveNext
Loop
DoCmd.RunSQL ("Delete * from TempProduct")
End Sub
And it kind of works. Though the multiple records are pushed from the form into the product table only when a new record is added again. i.e. the first record entered in the form are split and entered into the product table only after the second set of records are entered in the form.
Any suggestions as how I can push the records immediately. Thanks a bunch.
I am sure this is fairly simple put I am having trouble getting started on this. I use a Form to invoice clients which includes the field [Billing_Month]. What I'm looking to accomplish is this. When I create a new invoice, the [Billing_Month] will look to the last invoice created (use [Invoice_#] with DMax?), and populate the value from that that invoices [Billing_Month]
I have thought to use: Billing_Month = DMax ("Billing_Month", "frmInvoices"), but this doesn't specifically get me the last invoice, it would just look for the highest Billing_Month, which is a text field.
I have thought to use: Billing_Month = DLookup ("Billing_Month", "frmInvoices"), But this doesn't get me the last invoice to pull from.
I'd use a custom function for this - assuming the underlying table is called tblInvoices:
Function GetBillingMonthOfLatestInvoice()
Const SQL = "SELECT TOP 1 Billing_Month FROM tblInvoices ORDER BY [Invoice_#] DESC"
Dim RS AS DAO.Recordset
Set RS = CurrentDb.OpenRecordset(SQL)
If RS.EOF Then
GetBillingMonthOfLatestInvoice = Null
Else
GetBillingMonthOfLatestInvoice = RS(0)
End If
End Function
Update
The above code can be generalised to return other related fields like so:
Function GetValueForLatestInvoice(FieldToLookUp As String)
Dim RS As DAO.Recordset, SQL As String
SQL = "SELECT TOP 1 " + FieldToLookUp + " FROM tblInvoices ORDER BY [Invoice_#] DESC"
Set RS = CurrentDb.OpenRecordset(SQL)
If RS.EOF Then
GetValueForLatestInvoice = Null
Else
GetValueForLatestInvoice = RS(0)
End If
End Function
To use, copy the code to a new standard module, then for each relevant text box on the form, set its Default Value property in the Properties window to something like this:
=GetValueForLatestInvoice("Billing_Month")
That would be for the text box holding the billing month value; for the one holding the billing year, you would use
=GetValueForLatestInvoice("Billing_Year")
You can use a combination of both DLookup() and DMax() like so:
DLookup("Billing_Month","tblInvoices","[Invoice_#]=" & DMax("[Invoice_#]","tblInvoices"))
I have not used VB much but as far as I can tell scope works the same as in C#. The problem is, I'm using VB in MS Access so I am unsure if the rules are a bit different (though I assume they are not). The following code shows values being assigned to variables which have only been declared within the function parameters. Specifically looking at PurchaseOrderID, I am unsure as to how it is retaining its assigned value for use in the function proceeding it.
Function Create(SupplierID As Long, EmployeeID As Long, OrderID As Long, PurchaseOrderID As Long) As Boolean
Dim rsw As New RecordsetWrapper
If rsw.OpenRecordset("Purchase Orders") Then
With rsw.Recordset
.AddNew
![Supplier ID] = SupplierID
If EmployeeID > 0 Then
![Created By] = EmployeeID
![Creation Date] = Now()
![Submitted By] = EmployeeID
![Submitted Date] = Now()
![Status ID] = Submitted_PurchaseOrder
End If
If OrderID > 0 Then
![Notes] = InsertString(PurchaseGeneratedBasedOnOrder, CStr(OrderID))
End If
If rsw.Update Then
.Bookmark = .LastModified
PurchaseOrderID = ![Purchase Order ID]
Create = True
End If
End With
End If
End Function
Function CreateLineItem(PurchaseOrderID As Long, ProductID As Long, UnitCost As Long, Quantity As Long) As Boolean
Dim rsw As New RecordsetWrapper
If rsw.OpenRecordset("Purchase Order Details") Then
With rsw.Recordset
.AddNew
![Purchase Order ID] = PurchaseOrderID
![Product ID] = ProductID
![Quantity] = Quantity
![Unit Cost] = UnitCost
CreateLineItem = rsw.Update
End With
End If
End Function
Can someone give me some insight on this?
In VBA, how you call a procedure can be important.
"Even if a called procedure has declared its parameters as ByRef, you
can force those to be ByVal by enclosing each argument within
parentheses."
-- http://www.cpearson.com/excel/byrefbyval.aspx
This is true of VBA in all Office applications. For example, let us say you have two procedures:
Sub SubByVal(ByVal Total As Integer)
Total = 50
End Sub
Sub SubByRef(ByRef Total As Integer)
Total = 50
End Sub
And you run a few tests:
Dim Total As Integer
Total = 100
These three versions work as expected and Total is equal to 100
Call SubByVal(Total)
SubByVal (Total)
SubByVal Total
These two work as expected and Total is equal to 50
Call SubByRef(Total)
SubByRef Total
However, in this version, in spite of calling ByRef, Total is equal to 100, because it is forced to ByVal by the parentheses.
SubByRef (Total)
Perhaps this is best handled by types. Something like this:
Type PurchaseSet
PurchaseOrderID As Long
OrderCreated as boolean
End Type
Function Create(SupplierID As Long, EmployeeID As Long, OrderID As Long ) As PurchaseSet
Dim rsw As New RecordsetWrapper
Dim ps as PurchaseSet
ps.OrderCreated = false
If rsw.OpenRecordset("Purchase Orders") Then
With rsw.Recordset
.AddNew
![Supplier ID] = SupplierID
If EmployeeID > 0 Then
![Created By] = EmployeeID
![Creation Date] = Now()
![Submitted By] = EmployeeID
![Submitted Date] = Now()
![Status ID] = Submitted_PurchaseOrder
End If
If OrderID > 0 Then
![Notes] = InsertString(PurchaseGeneratedBasedOnOrder, CStr(OrderID))
End If
If rsw.Update Then
.Bookmark = .LastModified
ps.PurchaseOrderID = ![Purchase Order ID]
ps.OrderCreated = True
End If
End With
End If
Create = ps
End Function
You can pass arguments to a VBA procedure by value or by reference. If you don't specify either ByVal or ByRef in the procedure's declaration, it defaults to ByRef. So the following two declarations are equivalent ...
Function DoSomething(PurchaseOrderID As Long) AS Boolean
Function DoSomething(ByRef PurchaseOrderID As Long) AS Boolean
The key here is that ByRef allows changes to the argument within the procedure to be transmitted back to the caller.
I need to extract information from a page I have access to.
Just in this module, I have no means to export, but just to copying and pasting the information
Looks like this in the same l
1. MANUF MODEL YEAR MFG SERIAL REG OS DATE DESC LISTED1. YEAR DLV
2. monster 4r25 1988 23547248 Waka001 7/23/2012 For sale 7/22/20092. 1989
3. FORD 12SE 1994 6262552 DBZRLZ0 7/26/2012 For sale 7/9/20093. 1994
I'm getting my data in rows, but the year mfg and year dlv is in 2 rows within one row (or 2 rows in the same field). When pasted on excel it makes 2 rows first with all the data in the row including year mng and a second row just for year dlv (in the same column).
I can parse this information in excel by adding extra column and coping that extra field and deleting blanks and so on. But I want to omit the excel part and import this from a TXT file which when pasted creates 2 rows per row as well and using tabs as delimiter (like txt text tab delimited).
When I import with bulk insert, it imports twice as much rows, but I can't imagine a way to parse this second row into a new column.
Can someone help with this? In t-sql (every row has only one row of info, but in the column year mfg /year dlv, comes with two rows).
Or point me on what to read or which would be a better approach? Maybe importing 2 rows at once ETC.
You can import the data set from the text file into a temp table including the blank lines. This will give you a data set in SQL with 2 types of records. 1. Records that have all data except delivery date. 2. Records that have only delivery dates and no other fields. (Add a unique auto increment key)
Because the related records will be one record apart, Record N and Records N+1 are actually the same record.
Then a select query Joining the temp table to its self by RecID = RecId+1 will give a complete record with all fields
SELECT * FROM tmpTable AS MainRecord INNER JOIN tmpTable AS MissingField ON MainRecord.RecId = MissingField.RecId +1
From this dataset you can instert into your main data.
Do you know how to use VBA? You can run this code (FixData()) in Excel before you use it in TSQL so it fixes the extra row problem. Hope this helps
Option Explicit
Public Sub FixData()
Dim ws As Excel.Worksheet
Dim iCurRow As Long
Dim iLastRow As Long
Set ws = ActiveSheet
iLastRow = ws.Cells.SpecialCells(xlCellTypeLastCell).Row
' move through the spreadsheet from bottom to top
For iCurRow = iLastRow To 1 Step -1
If (isCurrentRowMessedUp(ws, iCurRow) = True) Then
Call AppendDataToPreviousRow(ws, iCurRow)
' delete the row since we moved the data out of there
ws.Rows(iCurRow).EntireRow.Delete
End If
Next
End Sub
Private Sub AppendDataToPreviousRow(ByRef ws As Excel.Worksheet, ByVal currentRow As Long)
Dim firstCellInRow As Excel.Range
Dim lastCellInRow As Excel.Range
Dim previousRowRangeToPaste As Excel.Range
' check if first column has data in it, otherwise find the first column that has data
If (ws.Cells(currentRow, 1).Value = vbNullString) Then
Set firstCellInRow = ws.Cells(currentRow, 1).End(xlToRight)
Else
Set firstCellInRow = ws.Cells(currentRow, 1)
End If
Set lastCellInRow = ws.Cells(currentRow, ws.Columns.Count).End(xlToLeft)
Set previousRowRangeToPaste = ws.Cells(currentRow - 1, getNextColumnAvailableInPreviousRow(ws, currentRow))
ws.Range(firstCellInRow, lastCellInRow).Cut previousRowRangeToPaste
End Sub
Private Function isCurrentRowMessedUp(ByRef ws As Excel.Worksheet, ByVal currentRow As Long) As Boolean
Dim cellCountInRow As Long
Dim firstCellInRow As Excel.Range
Dim lastCellInRow As Excel.Range
Set firstCellInRow = ws.Cells(currentRow, 1)
Set lastCellInRow = ws.Cells(currentRow, ws.Columns.Count).End(xlToLeft)
cellCountInRow = Application.WorksheetFunction.CountA(ws.Range(firstCellInRow, lastCellInRow))
If (cellCountInRow <= 1) Then
isCurrentRowMessedUp = True
Else
isCurrentRowMessedUp = False
End If
End Function
Private Function getLastColumnInPreviousRow(ByRef ws As Excel.Worksheet, ByVal currentRow As Long) As Long
Dim rng As Excel.Range
Set rng = ws.Cells(currentRow - 1, 1).End(xlToRight)
getLastColumnInPreviousRow = rng.Column
End Function
Private Function getNextColumnAvailableInPreviousRow(ByRef ws As Excel.Worksheet, ByVal currentRow As Long) As Long
getNextColumnAvailableInPreviousRow = getLastColumnInPreviousRow(ws, currentRow) + 1
End Function
you can use SQL Server Integration Service (SSIS) for convert data from any source data such as excel to any destination data such as SQL Server
I have two tables which can be represented by this query (I have made this query the Recordsource of the form):
SELECT tblrcmtask.id, tblrcmtask.rcmtask,tblrcmtaskoptions.id,
tblrcmtaskoptions.rcm_id,
tblrcmtaskoptions.rcmtaskoptions
FROM tblrcmtask
INNER JOIN tblrcmtaskoptions
ON tblrcmtask.id=tblrcmtaskoptions.rcm_id
I want the user to be able to add new entries into these table via a form in access 2007.
Columns tblrcmtask.id and tblrcmtaskoptions.id are the primary keys of the tables tblrcmtask and tblrcmtaskoptions respectively.
I do not understand how do I create new ID in both the tables while the user adds new entries.The user can add only tblrcmtaskoptions.rcmtaskoptions and tblrcmtask.rcmtask in the form.Also, there are multiple rows in the table tblrcmtaskoptions for each tblrcmtask.id.
I want the user to be able to add new rows in the table tblrcmtaskoptions for an existing tblrcmtask.id
I tried using dropdowns for these two but I am facing problem while creating the new ID as Maximum of the ID + 1.
Dim MyRecords As DAO.Recordset
Dim Myfield As DAO.Fields
SQL = "SELECT Max(tblRCMTASK.ID) AS MaxOf_RCMTASKID FROM tblRCMTASK;"
Set MyRecords = dbTHIS.OpenRecordset(SQL)
Set Myfield = MyRecords.Fields
Me.txtRCMTASKID = Myfield("MaxOf_RCMTASKID") + 1
Me.txtRCMTASKID.DefaultValue = Myfield("MaxOf_RCMTASKID") + 1
MyRecords.Close
End If
Dim MyRecords1 As DAO.Recordset
Dim Myfield1 As DAO.Fields
SQL = "SELECT Max(tblRCMTASKOPTIONS.ID) AS MaxOf_RCMOPTIONSID FROM tblRCMTASK;"
Set MyRecords = dbTHIS.OpenRecordset(SQL)
Set Myfield1 = MyRecords1.Fields
Me.txtRCMOPTIONSID = Myfield1("MaxOf_RCMOPTIONSID") + 1
Me.txtRCMOPTIONSID.DefaultValue = Myfield("MaxOf_RCMOPTIONSID") + 1
MyRecords1.Close
I am getting an error which says you can't asign a value to this object and points to this line: Me.txtRCMTASKID = Myfield("MaxOf_RCMTASKID") + 1
How do I do this?
Access gives you trouble when trying to do operations on an autonumber field. If you would like to do these kinds of operations, you may be better off just using a regular number as a PK.
To get a recently inserted autonumber field to insert the same number in a related table, this is the VBA:
assuming recordset and database are declared, rs and db
dim id as integer
set db = CurrentDb
set rs = db.openrecordset("firstTable", dbOpenDynaSet)
With rs
.addNew
.Fields("field1").Value = Me.control1 'adds to column1 of your table the value of control1
.Fields("field2").Value = Me.control2
.update 'updates the record. If it is an autonumber, it will be automatically assigned. I will show you how to access this for your next insert
end with
'To get the autoID of the entry we just inserted, do this
id = db.OpenRecordSet("SELECT##IDENTITY")(0)
'Now you have the autoID of the recent insertion, so you may use it for your next one.
This is a classic form/subform set up. Create a form based solely on tblrcmtask with a subform tblrcmtaskoptions. The link child and master fields should be set to the common id. The wizards will do this for you. There is no code required. The id will be automatically added by the link fields.
You can see an example for in the 2007 version of the Northwind sample database.