Macro to Run Custom Sql Query in Access off Data in Table? - sql

Coworker is completely Access adverse. I can't force him to update a SQL query with a to/from date and customer name. Current query is this:
SELECT [all customers]
FROM [information list]
WHERE
[date] Between [start date YYYYMMDD] and [end date YYYYMMDD]
and [all customers] = ['specific customer']
Group By [all customers] (this prevents duplicate entries or shipping a customer's order between factories counting as a separate order)
This coworker is so access adverse he wants a wysiwyg and a button to press to overwrite [start date YYYYMMDD] [end date YYYYMMDD] ['specific customer']
I can make a form just fine, but I have no idea how to populate the sql query with form answers. Having him copy and paste these three things into my perfectly good, working query is out of the question, as easy as that answer is.
How would i write a macro that can update this query with those answers replacing the three existing items (the two dates and customer ID)?

you concatenate the textbox values to create the sql query string
sql = "SELECT [all customers] FROM [information list]" _
& "WHERE [date] Between ['" & myForm.Textbox1.Text _
& "'] and ['" & myForm.Textbox2.Text _
& "'] and [all customers] = ['" & myForm.Textbox3.Text _
& "'] Group By [all customers]"
adjust the form name and the textbox names to fit your needs

Related

Condition for Update vs insert

I have a table tblCosts which i display on an msaccess front end which enables users to add new entries as well as update existing ones. The table is structured as below.
ExpenseType Month Year Cost
Hardware June 2017 $500
Software July 2017 $300
Hardware Sept 2017 $150
I have an update and insert queries which work fine when run manually.
However I am having trouble differentiating the condition when to fire the query on the form. For example, if the record exists in the table, it should run the update query, if record does not exist, it should run the insert query.
For example if someone puts in
- Hardware Sept 2017 $120 it should update the 3rd entry from 150 to 120 but if someone puts in
- Furniture Sept 2017 $350 it should recognize that Furniture is not part of the DB and run the insert query. I have the update and insert queries but need help in identifying the condition when to run them.
The Update query I'm using is:
Update tblCosts
set tblCosts.Cost=[Forms]![frmCost]![txtCost]
where tblCosts.ExpenseType = [Forms]![frmCost]![txtExpType]
and tblCosts.Month = [Forms]![frmCost]![txtMonth]
and tblCosts.Year = [Forms]![frmCost]![txtYear]
The Insert query I'm using is:
Insert into tblCosts (ExpenseType , Month, Year, Cost)
Select [Forms]![frmCost]![txtExpType] as Exp1,
[Forms]![frmCost]![txtMonth] as Exp2,
[Forms]![frmCost]![txtYear] as Exp 3,
[Forms]![frmCost]![txtCost] as Exp 4
Need code (VBA or macro) behind a form that determines which action query to run. In VBA something like:
If DCount("*", "tablename", "ExpenseType='" & Me.cbxExpense & "' AND [Month]='" & Me.tbxMonth & "' AND [Year]=" & Me.tbxYear) = 0 Then
CurrentDb.Execute "INSERT INTO tablename (Expense, [Month], [Year], Cost) VALUES ('" & Me.cbxExpense & "', '" & Me.tbxMonth & "', " & Me.tbxYear & ", " & Me.tbxCost & ")"
Else
CurrentDb.Execute "UPDATE tablename SET Cost=" & Me.tbxCost & " WHERE Expense='" & Me.cbxExpense & "' AND [Month]='" & Me.tbxMonth & ", [Year]=" & Me.tbxYear
End If
Probably also want some validation code to make sure all four controls have data before executing queries.
The real trick is figuring out what event to put code into - the Cost AfterUpdate will work as long as the other fields have data entered first, otherwise the validation will fail and user will have to re-enter cost.
Could have code that doesn't make each control available until previous value is entered.
Month and Year are reserved words and should not use reserved words as names for anything.
Would be better to save month numbers instead of month names for sorting purposes.
Why updating a value which really should be a calculated aggregation of transaction records?

MSAccess VBA AfterUpdate SQL code is running for every record instead of the current record

I have an access database that I will be using to track orders and to track inventory levels. When I attempt to add the parts on my order form (sbfrmOrderDetails) to my inventory table (tblInventory) my VBA code does not execute as planned.
Please note that I have stripped down the code and the tables to just the relevant information/values. The code posted below does work, just not as intended. I explain in much more detail below.
Form Structure
I created my Order form (frmOrder) as a Single Form. This form is referred to in my later code to determine the order number using the txtOrderID control. When I link my subform, the linked master field is OrderID.
Within this form is my Order Details subform (sbfrmOrderDetails) as a continuous form. Every control is bound, and it is linked to the parent form. The linked child field is OrderID.
Photo 1: This photo may better illustrate my form:
Table Structure
The relevant tables I have are structured like so:
TableName: tblOrders
TableColumns: OrderID
TableName: tblOrderDetails
TableColumns: ID|InvID|Qty|OrderID|DeliveryStatus
TableName: tblInventory
TableColumns: ID|InvID|Qty|OrderID
Intended Action
The action I am trying to take occurs in the subform and is supposed to be isolated to the current record. When the user changes the ComboBox (Combo1 bound control to tblOrderDetails.DeliveryStatus), my VBA code will execute an 'INSERT INTO' SQL string that adds the InvID and the Qty from the current record into the inventory table (tblInventory).
VBA Code for Combo1 AfterUpdate Event (On sbfrmOrderDetails)
Private Sub Combo1_AfterUpdate()
Dim db As DAO.Database
Dim strSQL As String
Set db = CurrentDb
If Me.Combo1.Value = "Delivered" Then
strSQL = "INSERT INTO [tblInventory] ([InvID],[Qty])" _
& "SELECT " & Forms![frmOrder].Form![sbfrmOrderDetails].Form![txtInvID] & " AS InvID," & Forms![frmOrder].Form![sbfrmOrderDetails].Form![txtQty] & " AS Qty " _
& "FROM tblOrderDetails WHERE ((tblOrderDetails.OrderID)=(" & Forms![frmOrder]![txtOrderID] & "));"
Debug.Print strSQL
db.Execute strSQL, dbFailOnError
Else
'Other event
End If
End Sub
Intended Results
When Combo1 (bound control) is changed from null to “Delivered” on record ID #11 only, it is supposed to add a single new record.
Photo 2: Intended Results:
Actual Results
When Combo1 (bound control) is changed from null to “Delivered” on record ID #11 only, it is adding a new record for every record populated in the subform.
Please refer to Photo 2 above to compare the Intended Results to the Actual Results.
You can see that the quantity from records 12 and 13 are transferred over under the InvID from record 11.
Please refer to Photo 1 to view the sample data and also to Photo 2 above to see the Actual Result of the code.
I suspect that since this is a continuous form that has Parent/Child linking, the form is running the VBA code once for every record (instead of one time for the current record).
Can I alter my VBA code to only run this code once on the current record as is intended? I am hoping this is the best approach to complete this task.
The output of Debug.Print strSQL would have been helpful (see How to debug dynamic SQL in VBA ), but it would be something like this:
INSERT INTO tblInventory (InvID, Qty)
SELECT 14 AS InvID, 2 AS Qty
FROM tblOrderDetails
WHERE tblOrderDetails.OrderID = 5
You are inserting two constant values, so you may as well use the INSERT ... VALUES (...) syntax, which by definition only inserts one record:
INSERT INTO tblInventory (InvID, Qty)
VALUES (14, 2)
The reason your statement inserts multiple records is because of WHERE tblOrderDetails.OrderID = 5. Multiple records (all on the subform) satisfy this clause.
You would have to specify the OrderDetails ID instead, to get only one record:
INSERT INTO tblInventory (InvID, Qty)
SELECT 14 AS InvID, 2 AS Qty
FROM tblOrderDetails
WHERE tblOrderDetails.ID = <Forms![frmOrder]![sbfrmOrderDetails].Form![txtID]>
tblOrders.OrderID --> this table has not been referenced in the statement and vba should throw an error
strSQL = "INSERT INTO [tblInventory] ([InvID],[Qty])" _
& "SELECT " & Forms![frmOrder].Form![sbfrmOrderDetails].Form![txtInvID] & " AS InvID," & Forms![frmOrder].Form![sbfrmOrderDetails].Form![txtQty] & " AS Qty " _
& "FROM tblOrderDetails WHERE ((tblOrders.OrderID)=
(" & Forms![frmOrder]![txtOrderID] & "));"
Debug.Print strSQL

MS Access: Ignoring query criteria if blank

I have a form in Access where I run a query based on several text boxes. I apply criteria on several of the query fields that is pulled from the text boxes but would like the query to ignore the criteria when the text box is blank.
For example, if the Machine_TextBox is blank, do not apply criteria to the Events.Machine field.
SQL code is:
SELECT Events.Machine, Events.[Event Date], Events.[Event Description],
Events.[Action Taken], Events.[Machine Clinical], Events.[Modalities Not Clinical],
Events.[Manufacturer Ticket #], Events.[TLC Ticket #], Events.FSR, Events.ID,
Events.[Event Recorded By], Events.[Action Recorded By], Events.[Downtime Validation],
Events.[Event Time]
FROM Events
WHERE (((Events.Machine)=IIf([Forms]![SearchEvent]![Machine_TextBox] Is Null,"",
[Forms]![SearchEvent]![Machine_TextBox])) AND ((Events.[Event Date]) Between
Nz([Forms]![SearchEvent]![StartDate_TextBox],#1/1/1900#) And Nz([Forms]![SearchEvent]![EndDate_TextBox],#1/1/2100#))
AND ((Events.[Event Description]) Like "*" & [Forms]![SearchEvent]![EventDetails_TextBox])
AND ((Events.[Manufacturer Ticket #])=[Forms]![SearchEvent]![Manufacturer_TextBox])
AND ((Events.[TLC Ticket #])=[Forms]![SearchEvent]![TLC_TextBox])
AND ((Events.FSR)=[Forms]![SearchEvent]![FSR_TextBox]))
OR (((Events.Machine)=IIf([Forms]![SearchEvent]![Machine_TextBox] Is Null,"",[Forms]![SearchEvent]![Machine_TextBox]))
AND ((Events.[Event Date]) Between Nz([Forms]![SearchEvent]![StartDate_TextBox],#1/1/1900#)
AND Nz([Forms]![SearchEvent]![EndDate_TextBox],#1/1/2100#))
AND ((Events.[Action Taken]) Like "*" & [Forms]![SearchEvent]![EventDetails_TextBox])
AND ((Events.[Manufacturer Ticket #])=[Forms]![SearchEvent]![Manufacturer_TextBox])
AND ((Events.[TLC Ticket #])=[Forms]![SearchEvent]![TLC_TextBox])
AND ((Events.FSR)=[Forms]![SearchEvent]![FSR_TextBox]))
ORDER BY Events.[Date and Time Stamp] DESC;
Yours sincerely,
Mark
You can try the technique described here.
For each search box, use boolean logic to either filter for its value, or ignore this AND clause if it's empty, by making the AND clause TRUE.
I'll just use two search boxes as example:
SELECT stuff
FROM Events
WHERE ((Events.Machine = [Forms]![SearchEvent]![Machine_TextBox])
OR ([Forms]![SearchEvent]![Machine_TextBox] Is Null))
AND ((Events.[Event Description] Like "*" & [Forms]![SearchEvent]![EventDetails_TextBox] & "*")
OR ([Forms]![SearchEvent]![EventDetails_TextBox] Is Null))
AND ...

Aggregating Child Records at the Parent Level in Access 2010

The link above will provide an excel sheet with some sample data from both the parent and child table with expected result from the query.
Alright this should be simple but I just can't wrap my head around this for some reason. Pretty much, I have a parent table that is linked to a child table. I want to pull up few of the fields from the child table and merge it with the parent fields. I want to create a view of sort in Access.
The parent record can have multiple child records (1 - many relationship). I want to only pull up one record from the child and merge with the parent. The parent table is called Tank and the child table is Tank_Inspections. The IF statement you see below is a conditional statement that helps in determining which Out of Compliance date I should be pulling up. The issue I'm having is that the Out of Compliance date is tied to inspection type. A Tank can have multiple different inspection types. They query below merges the inspection out of compliance date with few of the tank (parent) fields. However, I want to be able to add more of the child fields (in addition to the inspection out of compliance date) but I can't do that without adding those fields to the group by clause as well. If I do that, then I won't get the right amount of records.
As you can see, the left join is getting all of the records from the parent table which is what I need. If I add any more child table fields to the query, I'll also need to add them to the group by clause and then I'll get more records than what's in the parent table. Essentially, I need to only get the records from the parent table, and then merge child fields in. I may be missing few sub queries... Any suggestions? This is what I have so far and I'm getting the right amount of records. But adding more child fields to the select statement will add more rows than i need...
SELECT parent.tankid, IIf(Min(Nz(child.[tank inspection out of compliance date], #1/1/1901#)) <> #1/1/1901#, Min(child.[tank inspection out of compliance date]), IIf(Min(Nz(child.[tank inspection out of compliance date],#1/1/1901#)) = #1/1/1901# And Max(child.[tank inspection out of compliance date])>Date(), NULL, Min(child.[tank inspection out of compliance date]))) AS [Tank Inspection Out of Compliance Date]
FROM
tank as parent
LEFT JOIN
(
SELECT * FROM tank_inspections WHERE tank_inspections.[actual inspection date] is null
) AS child ON parent.tankid = child.tankid GROUP BY parent.tankid
I was able to modify Parfait suggested query below to come up with this:
SELECT
Site.[Manager] AS PM, Site.[DLA Site Code], Tank.[Name] AS [Name], Tank.[Local Name],
Tank.RPID, Tank.[Fac Num], Tank.[Status], Tank.[Type], Tank.[Capacity], Tank.[Current Prod], IIf(main.[Inspection Out of Compliance Date]<Date() AND NOT IsNull(main.[Inspection Out of Compliance Date]), 'Out of Compliance',
IIf(isnull(main.[Inspection Out of Compliance Date]) OR main.[Inspection Out of Compliance Date]=#1/1/1901#,'Unknown Compliance Status')) AS [Compliance Status], Tank.[EA], Site.Serv, Site.[Name], Tank.Comments, main.[Type], main.[Inspection Out of Compliance Date], main.[Planned Prog Date], main.[Prog Date], main.[Prog Year], main.[Planned Inspection Date], IIf(main.[Inspection Out of Compliance Date]<DateAdd('m',12,Date()) And main.[Prog Date] Is Null,'Action Required') AS [Inspection Planning Action Required], main.[Inspection Comments], tank.TankID, main.inspectionid
FROM
Site INNER JOIN
(
(
(
SELECT ti.tankid, ti.inspectionid, ti.[Type], ti.[Inspection Out of Compliance Date], ti.[Planned Prog Date], ti.[Prog Date], ti.[Prog Year], ti.[Planned Inspection Date], ti.[Inspection Comments] FROM Tank_Inspections AS ti) AS main INNER JOIN Tank ON main.TankID = Tank.TankID) INNER JOIN
(
SELECT [TankID], dlookup("InspectionID", "Tank_Inspections", "[Tank Inspection Out of Compliance Date] " & IIf(Min(Nz([inspection out of compliance date], #1/1/1901#)) <> #1/1/1901#, "= #" & Min([inspection out of compliance date]) & "#", IIf(Min(Nz([inspection out of compliance date],#1/1/1901#)) = #1/1/1901# And Max([inspection out of compliance date])>Date(), "IS NULL", IIF(Min(Nz([inspection out of compliance date],#1/1/1901#)) = #1/1/1901# And Max([inspection out of compliance date])<Date(), "= #" & Min([inspection out of compliance date]) & "#", "IS NULL"))) & " AND TankID = " & TankID & " AND [Actual Inspection Date] is null") AS MinInspectionID FROM Tank_Inspections WHERE [Actual Inspection Date] is null GROUP BY [TankID]
)AS DT ON
(
main.InspectionID = Cint(DT.MinInspectionID)
) AND (main.TankID = DT.TankID)
) ON Site.SiteID = Tank.SiteID
WHERE IIf(main.[Inspection Out of Compliance Date]<Date() And NOT IsNull(main.[Inspection Out of Compliance Date]),'Out of Compliance',IIf(isnull(main.[Inspection Out of Compliance Date]) OR main.[Inspection Out of Compliance Date]=#1/1/1901#,'Unknown Compliance Status'));
I'm close with this query, however, I'm missing a few records. The parent records don't have some of the child records. For example, some of the tank records don't have any inspection records so it's not being pulled. I need to do a left join but can't seem to figure it out with this query. Everything I try doesn't seem to work. Suggestion?
Consider the following query that uses a derived table and joins the unit level parent (Tank) to aggregated child (TankInspections). You can save the derived table as a separate stored query and just replace entire select statement and alias (DT) with query name. I include more aggregates than needed for you to check calculated columns:
SELECT Tanks.*, main.*, DT.MaxInspectionID, DT.MaxInspectionOrComplianceDate
FROM
(TankInspections main
INNER JOIN Tanks ON Tanks.TankID = main.TankID)
INNER JOIN
(
SELECT [TankID],
Max(InspectionID) As MaxInspectionID,
Min([Planned Inspection Date]) As MinInspection,
Max([Planned Inspection Date]) As MaxInspection,
Min([Inspection Out of Compliance Date]) As MinCompliance,
Max([Inspection Out of Compliance Date]) As MaxCompliance,
Max(IIF(([Planned Inspection Date]) Is Null,
IIF(ISNULL([Inspection Out of Compliance Date]),
NULL,
[Inspection Out of Compliance Date]),
[Planned Inspection Date])) As MaxInspectionOrComplianceDate
FROM TankInspections
GROUP BY [TankID]
) As DT
ON main.TankID = DT.TankID
AND main.InspectionID = DT.MaxInspectionID;

UPDATE query not using WHERE clause

I am trying to use an UPDATE query to modify a field in a table from a field in another table.
The query statement I'm using is:
UPDATE Todays_Deliveries SET Remaining = DLookup("Remaining","Current_Delivery","[MP-Ref] = Form![MP-Ref] And [Cat No] ='" & [Cat No] & "'")
WHERE "[MP-Ref] = Form![MP-Ref] And [Cat No] ='" & [Cat No] & "'";
MP-Ref is the delivery reference.
Cat No is the item reference.
Where Todays_Deliveries is a table with the total records related to items coming in from deliveries on a given day. The user selects a delivery using a form which then uses an APPEND query to populate the Current_Delivery table based on the delivery reference. Once the user is finished the Current_Delivery table is cleared using a DELETE query.
Both tables have a Remaining value with the total number of a particular record that still needs to be booked in. The query updates the Todays_Deliveries table when the user modifies the Remaining field of the Current_Delivery on the Current_Delivery form. Everything works fine but any records that aren't in the Current_Delivery table when the query is run are updated to NULL.
Removing the WHERE clause seems to have no impact on the results, which leads me to believe I am not utalising the WHERE clause correctly.
Any help/advice would be greatly appreciated.
Your whole Where clause is enclosed within double-quotes.
That is a bit odd even for Ms Access.
Try this :
UPDATE Todays_Deliveries
SET Remaining = DLookup("Remaining","Current_Delivery","[MP-Ref] = Form![MP-Ref] And [Cat No] ='" & [Cat No] & "'")
WHERE [MP-Ref] = Form![MP-Ref] And [Cat No] = "'" & [Cat No] & "'";