Access VBA using SQL for importing multiple tables and then ensuring that they are union - sql

Okay I am getting stuck with my code.
What I am trying to do is use specific data from multiple tables, but I want to use basically the UNION ALL and INNER JOIN functions, however, this is not supported with the Visual Basic of Access and I require it to go to a table so that I can proceed to my next step.
The whole interface work from a form that has buttons to press for normal users, basically setting up a whole interface for importing the reports.
My original import followed the advise that I received from here for the tables:
strSQL = "INSERT INTO [Clicks Returns] " & _
"(SKU, [Item Description], [Jan 2016 FIN YTD TY % Returns]) " & _
"SELECT Sku, [Item Description], [Jan 2016 FIN YTD TY % Returns] FROM [Jan 2016 Clicks Returns];"
DoCmd.RunSQL strSQL
This works perfectly for appending the data to one table, however when importing the data from multiple tables into one table it follows this pattern:
Result Example
However, I require this to be the result:
Required Result
The issue is that Both SKU numbers would be similar and the Item Desc. would be the same.
And with the normal append method it just keep duplicating and I want it to follow a join type action, and I do not know how to approach this exactly with Visual Basics on Access.
Thank you for taking the time to review this and also providing assistance.

with getting the information from the second table, you require the table to be updated. (so insert into won't work for the second time you need to get data...)
I would however reconsider your data structure, to have 1 data column in the table, and have 1 column indicating which month. Then when reporting you can pivot that information...
so basically this table format:
1) SKU
2) Item Description
3) Month
4) Month YTD information.
In the case above, your insert into will much more easily work, and you won't need an update statement.
I hope this helps.
Kind regards,

Related

Calculated Field in subreport

TL:DR I want a whole column of SQL equivalent of excel's COUNTIFS() Function.
I'm still quite new to MS Access, but I'm quite proficient with Excel. I've inherited an Access Database that tracks reasons for delays in a large logistics group, and am trying to build a report showing which reasons come up most.
So, I can output an SQL report showing all the reasons (they're in a table called 'Reasons', so that bit's easy). What I want is a calculated field next to that column, showing how many times each reason has been cited on the [Master Data] Table (field called 'Lateness Reason') in a given date range. And for double extra bonus points, the percentage they come up would be extremely handy.
I've looked online and found COUNTIFS equivalents for a single set of criteria, but in this case I want it calculating on each row of a report. I've also tried a few things myself, but the closest I could figure was:
SELECT Reasons.Reason, Count([Master Data].[ID]) AS Num
FROM Reasons INNER JOIN [Master Data] ON Reasons.[ID] = [Master Data].[Lateness Reason]
WHERE ((([Master Data].[Lateness Reason])=[Reasons].[Reason]));
which has incorrect syntax and possibly a few other problems (that WHERE clause has to apply equally to all lines, doesn't it?). My only other option might be to do a separate calculation for each line and 'union' them together, but that is likely to cause other problems in the future if more reasons get added (and there are quite a lot already).
Firstly, Is it Possible?
Secondly, If so, How??
Many Thanks in advance
EDIT: In response to comments, table structure is as follows;
Table "Reasons" has two columns; "Reason" and "ID"
Table "Master Data" has many columns, the ones I'd be bothered about are "Date", "ID" and "Lateness Reason" (Lateness reason is equivalent to an ID from table 'Reasons')
Table Reasons
ID Reason
___________________
1 | Stock Shortage
2 | Courier Problems
etc | etc
Master Data
ID Date Reason
__________________
1 | 01/01/1980 | 2
2 | 03/05/2020 | 2
etc
This is how I think your query should look like based on the information you provided.
SELECT Reasons.Reason, Count([Master Data].ID) AS Num
FROM Reasons INNER JOIN [Master Data] ON Reasons.ID = [Master Data].[Lateness Reason]
WHERE ((([Master Data].Date) Between [BeginDate] And [EndDate]))
GROUP BY Reasons.Reason;
Replace [BeginDate] and [EndDate] if you're using form control references.
As for the percentages based on the total, you can use text boxes as #June7 has suggested:
Use a total count in the header or footer of the report =Count(*) and then in the detail add a text box with the following control source: =[Num]/Count(*), where Num is the name of the textbox in your report which holds the counted values per reason. In this case, the control source for Num will be Num based on the query given.
Just a side note, naming your field Date is not advised since it's a reserved keyword in MS Access. It can cause unintended issues along the road.

Microsoft Access: Query by Form with Multiple Criteria and Possible Blanks in SQL View

I have started to create a Query by Form using the Form QueryHelp and the Query called DEALLOG3. My goal is for the user to be able to filter by Submarket, Building Type, and a sale date range. With the criteria I have now, it works fine in most scenarios where all of the comboboxes have values. However, when one of the comboboxes is blank, I want to be able to still have the other two criteria working, while showing all of the records for the blank field. (ex: Tampa Submarket, [Blank] Building Type, and a sale date from 01/01/2000 to 01/01/2016).
I've been scouring this sight for the past two days and can't find anything that will work. I think I might be looking for a dynamic query, but I am unsure. Here is what I have currently, please let me know if you can help:
SELECT DEALLOG3.PROPERTY, DEALLOG3.CODE, DEALLOG3.CLOSED, DEALLOG3.Submarket, DEALLOG3.NRA, DEALLOG3.PRICE, DEALLOG3.OCCUPANCY, DEALLOG3.[5 YR IRR], DEALLOG3.PURCHASER, DEALLOG3.SELLER, [PRICE]/[NRA]
AS PSF, [DEALLOG3]![NOI]/[PRICE]
AS [Cap Rate], DEALLOG3.[Building Type]
FROM DEALLOG3
WHERE (((DEALLOG3.CLOSED)
Between [Forms]![QueryHelp]![closeyear1]
And [Forms]![QueryHelp]![closeyear2])
AND ((DEALLOG3.Submarket)=IIf(IsNull([Forms]![QueryHelp]![Submarket]), " * " ,[Forms]![QueryHelp]![Submarket]))
AND ((DEALLOG3.[Building Type])=IIf(IsNull([Forms]![QueryHelp]![BuildingType]),"*",[Forms]![QueryHelp]![BuildingType])))
;
Try again after changing your WHERE clause in
WHERE DEALLOG3.CLOSED Between [Forms]![QueryHelp]![closeyear1]
AND [Forms]![QueryHelp]![closeyear2]
AND (
DEALLOG3.Submarket)=[Forms]![QueryHelp]![Submarket])
OR [Forms]![QueryHelp]![Submarket] Is Null
)
AND (
DEALLOG3.[Building Type])=[Forms]![QueryHelp]![BuildingType]
OR [Forms]![QueryHelp]![BuildingType] Is Null
)

VBA Access Query for Day Summary

I use this forum all the time for VBA help but this is the first time I have to post something myself.
I am trying to make a report that provides a summary of various alarms stored in Access. I want to provide a simple Count of each alarm, each day. I have used some SQL queries but not really any Access. I took the fact that Access can do Pivot tables from Access itself. If there is a better way, please let me know.
Set CommandQuery.activeConnection = conn
commandQuery.CommandText = _
"TRANSFORM Count(FixAlarms.[Alm_NativeTimeLast]) AS CountOfAlm_NativeTimeLast " & _
"SELECT FixAlarms.Alm_Tagname, FixAlarms.Alm_Desc " & _
"FROM FixAlarms " & _
"WHERE ((FixAlarms.Alm_Tagname) <> """")) AND FixAlarms.Alm_NativeTimeIn > CellTime " & _
"GROUP BY FixAlarms.[Alm_Tagname], FixAlarms.Alm_Descr " & _
"PIVOT Format([Alm_NativeTimeIn],""Short Date"")"
rec.Open commandQuery
This is the code I am using. I had to retype it, so please forgive any typo. It does most of what I want but it does not give me any indication of what day each column is. I need a header on each column in case there were no alarms one day. I think the answer lies within the IN part of the PIVOT but I can't get it to work without syntax errors. I thought all I had to do was add on
PIVOT Format([Alm_NativeTimeIn],""Short Date"") IN 01/20/15"
Please help if you can.
Thanks.
In order to get the records for all day, even those where there were no activity you need to create these days. The simplest way to do so in access is to use a set of UNION statements to create a fake table for the days similar to this:
SELECT #2015-01-20# as dt FROM dual
UNION ALL
SELECT #2015-01-21# as dt FROM dual
UNION ALL
SELECT #2015-01-22# as dt FROM dual
If you try the above query in Access it will not work, as there is no table called dual. You will have to create it. Check this SO question.
After you created the above query you can LEFT JOIN it with the source table.
TRANSFORM Count(FixAlarms.[Alm_NativeTimeLast]) AS CountOfAlm_NativeTimeLast
SELECT FixAlarms.Alm_Tagname, FixAlarms.Alm_Desc
FROM
(SELECT #2015-01-20# as dt FROM dual
UNION ALL
SELECT #2015-01-21# as dt FROM dual
UNION ALL
SELECT #2015-01-22# as dt FROM dual) as dates LEFT JOIN
FixAlarms ON DateValue(FixAlarms.[Alm_NativeTimeIn]) = dates.dt
WHERE ((FixAlarms.Alm_Tagname) <> """")) AND FixAlarms.Alm_NativeTimeIn > CellTime
GROUP BY FixAlarms.[Alm_Tagname], FixAlarms.Alm_Descr
PIVOT Format(dates.dt, 'Short Date')
EDIT: I must add that this is not the only way of achieving it. Another way is to use a Numbers table. Create a table called Numbers with a single numeric column n and fill it with numbers 0 to 100 (depends on the maximum number of days you wish to include into your query). Then your query for the dates will be:
SELECT DateAdd('d', n, #2015-01-20#) as dt FROM numbers where n < 30;
And the resulting query will be:
TRANSFORM Count(FixAlarms.[Alm_NativeTimeLast]) AS CountOfAlm_NativeTimeLast
SELECT FixAlarms.Alm_Tagname, FixAlarms.Alm_Desc
FROM
(SELECT DateAdd('d', n, #2015-01-20#) as dt FROM numbers where n < 30) as dates LEFT JOIN
FixAlarms ON DateValue(FixAlarms.[Alm_NativeTimeIn]) = dates.dt
WHERE ((FixAlarms.Alm_Tagname) <> """")) AND FixAlarms.Alm_NativeTimeIn > CellTime
GROUP BY FixAlarms.[Alm_Tagname], FixAlarms.Alm_Descr
PIVOT Format(dates.dt, 'Short Date')
When using PIVOT columnName IN (ValueList) ValueList is
In parentheses
In quotes
Comma separated
So you're
PIVOT Format([Alm_NativeTimeIn],""Short Date"") IN 01/20/15"
Needs to become
PIVOT Format([Alm_NativeTimeIn],""Short Date"") IN (""01/20/15"")
With that said, this will not filter your records using PIVOTS in IN statement. You need to use the WHERE clause still.
If the end goal is to represent your data left to right then this will work. It will be a lot of extra work to make this work as a report though because your controls will not be bound to predictable columns. The Column names will change for different parameters.
You could leave this as a traditional query (not pivoted) and have a much easier time reporting it. If you are showing users the grid directly or exporting to Excel then this is not a problem.
So, I just wanted to add a header to my pivot table that would tell me what date the particular column was for.
The part of the code that I did not show was that I was using a rec.getrows to move all of my data into a simpler array variable. While this had all the data from Access, it did not have any headers to inform me what was a tagname, what was a description, and what was which date.
I found that in the recordset itself under fields.item(n) there was a Name attribute. This name told me where the column data came from or the date of the data. Using this and a simple day(date) function, I was able to make my monthly report summarizing all of the alarms.
Thanks for your help guys, but I either was not clear in my description of the problem or it was being over thought.

Access - SQL Query -> find most recent record and save it to a table

I am sure this has been asked before and I have found several references to similar things. I just can't work out how to make it work for me.
I have a table (tblHistory) with data
Unit Number,Action,LoggerID,SensorID,CableID,Date,Data Location etc
I also have another table (tblUnit) with more data
Unit,Logger,Sensor,Cable
I want to create a query that scours tblHistory to find the most recent LoggerID, SensorID and CableID for each Unit.
To add to this there may need to be safeguards in the query in case the user does not place Logger, Sensor or Cable IDs so that it does not just find the most recent date and return a null value.
The final aspect of this which may or may not be simple is that I want this to overwrite the data in the tblUnit table so that when a new logger, sensor or cable is in place the unit uses this new data. I don't want these fields to be just edited because I want to keep a history of it. My knowledge of SQL and Access is pretty limited as I'm usually more familiar with excel and vb.
I have tried using these:
MSAccess: select N records from each category
sql for finding most recent record in a group
but being a beginner I'm not 100% sure how to apply them to my problem.
If anyone can help that would be great.
Example: (tblHistory)
Unit Number,Action,LoggerID,SensorID,CableID,ActionDate
1,Replace Sensor,,KTSM01S03,,15/02/2015
1,Replace Logger,KTSM01FM02,,,11/01/2014
1,Replace Cable,,,sa123124,10/01/2014
1,Replace Logger,KTSM01FM03,,,12/01/2014
2,Replace Sensor,,KTSM01S01,,13/01/2014
2,Replace Cable,,,sa123123,12/01/2014
2,Replace Cable,,,sa123124,16/02/2014
2,Replace Logger,KTSM01FM01,,,13/01/2014
tblUnit
Unit Number,Logger,SensorID,Cable
1,KTSM01FM01,KTSM01S01,sa123123
2,Logger1,Sensor1,Cable1
SELECT TOP 1 *
FROM tblHistory a
INNER JOIN
(SELECT Unit Number, Max([Date]) as MaxDate
FROM tblHistory
GROUP BY Unit Number) b
on a.[Unit Number] = b.[Unit Number]
and a.[Date] = b.MaxDate
You have to bracket the field called Date because Date() is a reserved function and Access will think you're trying to use the function instead of calling the field in your table. In the future, always try to avoid using reserved words as field names, it will save you a lot of headaches.

Insert textbox value into Access SQL query

Being an amateur in Access and VBA, I've hit a wall with the following...
In MS Access 2007, I have the following query:
SELECT .... WHERE format(NZ(l_f_date),'yyyy-mm-dd')<=**'2012-04-03'**);
I have shortened it a bit of course.
The database has approx 20 queries that need to be run on a daily basis. I have created 4 macros to run groups of queries in the manner that I need them to be run. The problem is that in every one of those queries I first have to change the date (like in the upper query). I am looking for the way to automate it a bit more.
I have an idea to create a Form, place a button for every macro on it and 2 textbox-es to enter the 2 dates I need. Now, I need those dates to appear in the bolded part. As I think about it, I have 2 options:
Create a temporary table in the database to store those two dates and pull those 2 fields in my queries.
Insert the value of the textbox somehow directly into the bolded part of the query.
I think I can manage the first solution, but the second one is making my head hurt.
Can you help?
SQL from comment
select proc_desc,count(s) as broj
into upit3
from ( select distinct a.case_id as s,
a.org_case_id,a.act_date as day,d.prod_id,d.prod_desc,
c.fname,c.dpd,c.due_amount,proc_id,proc_desc
from actions_b as a, cases_old_b as c,processes_b as p,
product_dict_b as d
where a.org_case_id=c.[org_ case_id]
and a.act_date=Forms!Form!Text10 and d.prod_id=c.product
and p.proc_id=c.process and not_lead=1 )
group by proc_desc order by proc_desc;
OK, sample data....
In x.dates, value is exactly like this: 03.04.2012
In a.act_date value is like this: 01.07.2011 13:53:56
so if its not possible with this values as they are, is it possible to use a LIKE statement in the query? Pseudo: WHERE a.act_date LIKE x.date%
If its possible, how to use it? i am a novice in sql and access queries... I google but sometimes, like this time, i get stuck.
Thanks
This structure:
SELECT .... WHERE format(NZ(l_f_date),'yyyy-mm-dd')<='2012-04-03');
Is not a good idea. The general rule is to try and stick to field (column) names on the left side of the equals. So
SELECT .... WHERE l_f_date <=#2012-04-03#
Nulls will not be included and I hope your dates are dates and not strings.
Next add the form:
SELECT .... WHERE l_f_date <= Forms!TheNameOfTheForm!TheNameOfTheTextbox
EDIT re comments
You are using the query design window, yes? Please try this test query:
SELECT a.case_id, a.act_date
FROM actions_b AS a
WHERE a.act_date=Forms!Form!Text10
OK, so i decided to create a simple 2-column table in my database that will be used just for storing yesterdays and todays date... i added 2 text-boxes to a form, 1 button and added the next procedure to the button:
Private Sub Command25_Click()
CurrentDb.Execute "DELETE * FROM Datumi"
Dim tbl As Recordset
Set tbl = CurrentDb.OpenRecordset("Datumi")
tbl.AddNew
tbl!brojka = "1"
tbl!datum = Text8.Value
tbl.Update
tbl.AddNew
tbl!brojka = "2"
tbl!datum = Text10.Value
tbl.Update
End Sub
As you can see, the click on the button will clear the table and store new values into 2 rows... row 1 is yesterday, row 2 is today...
And after that im pulling the values from that table like this:
... where x.brojka=1 and format(a.act_date,'yyyy-mm-dd')=format(x.datum,'yyyy-mm-dd') ...
I'm sure it can be done better but this one works for me...
I Solved this problem with :
[Software: MS Access 2013]
CurrentDb.Execute "INSERT INTO [Inventory Transactions] ([Product ID], [Order ID])" _
& "VALUES ( " & Me.Product_ID & ", " & Me.Order_ID & ")"