Merge like dates in MS Access - ms-access

I am a pilot who flies multiple legs in a day. The software I use to log flights spits out a csv file and lists every leg separately. I import the csv file into table 1 in ms access. I would like to merge all flights from the same day into one record on a new table. My problem is combining the route and adding the time.
Table 1
Date Plane From To Time
2009-10-13 111WS CHO LGA 120
2009-10-13 111WS LGA ITH 100
2009-10-13 111WS ITH LGA 90
2009-10-13 111WS LGA BOS 110
Table 2
Date Plane Route Time
2009-10-13 111WS CHO-LGA-ITH-LGA-BOS 420
I would like to use VBA code to do this, but I haven't done any programming in 12 years and unfortunately don't have the time to relearn. I don't think the code has to be too elaborate, it seems pretty straightforward. I just don't know how to do it. I hope someone can help me out. Thanks in advance.
Note:
I am using MS Access 97 (hope that's not a problem)/
The date field is a string, not a date/
The time is in minutes, and can stay that way/
There normally will not be more than 80 records in table 1/
There can be anywhere from one to eight flights in one day/

Create a Totals query, bring in your table, and include the Date and Time as columns. The Date Column should be set to Group By in the Total Row, and the Time should be set to Sum. You will also need another column to get the final entry in the route, so put the To column in the grid also, and set the Totals row for that column to Last.
To get the remainder of the route, you will need to use a combining function like this one:
Return a concatenated list of sub-record values
http://www.mvps.org/access/modules/mdl0004.htm
This will combine the FROM column into a single value, which you can include as another column in the output. Set the Total row for this column to Expression.
To get the complete route, combine the concatenated FROM columm with the LAST TO column.
Note that you don't need to build the entire query at once. Build each of the three pieces (total time, concatenated route, ending destination) individually (in its own query), and make sure each piece works individually, before combining them into a single query.

Add module
Public Function ConcatField(FieldName As String, TableName As String, Where As String, Optional Delimeter = "-", Optional OrderBy = "") As String
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT " & FieldName & " FROM " & TableName & " WHERE " & Where & IIf(OrderBy > "", " ORDER BY " & OrderBy, ""))
ConcatField = DLookup("From", "RTE", Where)
While Not rs.EOF
ConcatField = ConcatField + IIf(ConcatField = "", "", Delimeter) + rs.Fields(0)
rs.MoveNext
Wend
rs.Close
Set rs = Nothing
End Function
and run query
Worked on mine
SELECT rte.Date, rte.Plane, ConcatField("to","rte","Date='" & [Date] & "' AND Plane='" & [Plane] & "'") AS Expr1, Sum(rte.Time) AS SumOfTime
FROM rte
GROUP BY rte.Date, rte.Plane, ConcatField("to","rte","Date='" & [Date] & "' AND Plane='" & [Plane] & "'");
enter code here

Unlike ACE (Access 2007), the Jet 3.51 engine (Access97) doesn't have multivalue types. SQL the language (including the Access Database Engine's own proprietary SQL) does not have a 'Concatenate' function because it would be a violation of first normal form (1NF) which requires scalar types. So this isn't something for a SQL query. Sounds to me more like a candidate for a report.
Speaking of 1NF, considering it is possible to fly to the same destination twice in one day, your table lacks a relational key. It sounds like you need to replace you single 'date' column that is typed as 'text' with a pair of DATETIME values representing a period, with the required 'sequenced primary key' e.g. a CHECK constraint to prevent overlapping periods. Temporal databases are definitely non-trivial!

Thanks for all your responses. I used "THEn's" answer, but I had to change a few things (hope that's not a problem). I only needed the flights grouped by date, so I took out the grouping by plane, and just logged the first plane on the first leg of that day. Also I just found out that my software exports the csv file in reverse order, so I changed the module a little to account for this. So this is what the imported data looks like (I start and end in CHO):
Date Plane From To Time
2009-10-14 111WS LGA CHO 120
2009-10-14 111WS BOS LGA 110
2009-10-13 111WS LGA BOS 110
2009-10-13 111WS ITH LGA 90
2009-10-13 111WS LGA ITH 100
2009-10-13 111WS CHO LGA 120
This is the Module:
Public Function ConcatField(FieldName As String, TableName As String, Where As String, Optional Delimeter = "-") As String
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT " & FieldName & " FROM " & TableName & " WHERE " & Where)
rs.MoveLast
While Not rs.BOF
ConcatField = ConcatField + IIf(ConcatField = "", "", Delimeter) + rs.Fields(0)
rs.MovePrevious
Wend
ConcatField = ConcatField + "-" + DLookup("To", "rte", Where)
rs.Close
Set rs = Nothing
End Function
This is the query:
SELECT rte.Date, First(rte,plane), ConcatField("From","rte","Date='" & [Date] & "'") AS Expr1, Sum(rte.time) AS [Total Time]
FROM rte
GROUP BY rte.Date;
This causes a problem because I'm using a field called "From" in the openrecordset line, I tried renaming the field to something else and it worked perfectly. However I was hoping to keep the field names the way they are. It worked when I was using the field name "To" in the openrecordset line, but then I was running into a problem with the data being in reverse order. So I was looking for any suggestions, but I would like to keep the field names the same, and I would like to keep the table in reverse order if possible. Thanks again guys.

Related

How to create a jpa query that takes multiple (dynamic) number of ranges for between clause to fetch results

I am writing a JPA native query for searching records.
I have a table lets say "machines" which contain a numeric column "capacity" which stores capacity of machine, search input can contain List of ranges of capacity in which the machines should be filtered.
For example range list can contain
10 to 20
25 to 30
32 to 40
So the machines having capacity between any of above ranges should be fetched.
Here is my native query which works for only one element from capacity ranges
How to make it dynamic so that it would support for multiple such capacityMin and capacityMax values.
Thanks in advance.
#Query(value = "SELECT * FROM machine m where m.status='A' " +
"and (:capacityMin IS NULL or (m.capacity>= :capacityMin and m.capacity<= :capacityMax))" , nativeQuery=true)
public List<Object[]> searchMachines(#Param("capacityMin") Integer capacityMin,#Param("capacityMax") Integer capacityMax);
When you have a few parameters then use the solution you already found the solution for the first parameter
#Query(value = "SELECT * FROM machine m where m.status='A' " +
"and (:capacityMin IS NULL or (m.capacity>= :capacityMin ) " +
"and (:capacityMax IS NULL or (m.capacity<= :capacityMax )" , nativeQuery=true)
public List<Object[]> searchMachines(#Param("capacityMin") Integer capacityMin,#Param("capacityMax") Integer capacityMax);
When you have many optional parameters you can better use the already mentioned Criteria API or QueryDSL

unpaid monthly salaries (mysql +vb.net)

I have a MySQL table some thing like that
NAME salary amount month 1 month 2 month 3 month 4
john 300 300 300 0 0
maria 400 400 0 0 0
tom 380 380 380 380 0
I wanna see results in table or list view or whatever like that
name unpaid month salary amount
john month 3 300
john month 4 300
maria month 2 400
maria month 3 400
maria month 4 400
tom month 4 380
I tried code like:
sql1="select name,month1 from table where month1=0 "
sql2="select name,month2 from table where month2=0"
sql3="select name,month3 from table where month3=0"
sql4="select name,month4 from table where month4=0"
Dim Sql = String.Concat(sql1, ";", sql2 ,";",sql2,";",sql4 )
but didn't work , any help pls ?
The syntax looks a little off in your code that you have now. I do not know if this is the exact code that you have in your program, but when the SQL statements are not properly formatted nothing will happen. I have made some changes to show what may be the issue.
sql1="SELECT name, month1, amount FROM table WHERE month1=0"
sql2="SELECT name, month2, amount FROM table WHERE month2=0"
sql3="SELECT name, month3, amount FROM table WHERE month3=0"
sql4="SELECT name, month4, amount FROM table WHERE month4=0"
Dim Sql = String.Concat(sql1, ";", sql2 ,";",sql2,";",sql4 )
The issue that I see with your current formatting is that you may want to have two separate tables for the name and the pay. With the separate tables you could then use foreign keys and join the two tables to have each name on every month with the amount they were paid that month. You would also be able to group the users based off of their name using GROUP BY
With the restructured table your call would be as simple as the statement below. Since I do not know your table names I have made fake ones for them.
Dim Sql = "SELECT NameTable.name, MonthTable.month, MonthTable.amount
FROM NameTable INNER JOIN MonthTable
ON {prmarykey for name} = {foreign key for month}
GROUP BY NameTable.name"
This should give you the result that you are looking for. Let me know if you have any questions or need clarification.
Try the UNION mysql aggregate :
sql1="select name,month1 as unpaid_month from table where month1=0 "
sql2="select name,month2 as unpaid_month from table where month2=0"
sql3="select name,month3 as unpaid_month from table where month3=0"
sql4="select name,month4 as unpaid_month from table where month4=0"
Dim Sql = String.Concat(sql1, " UNION ", sql2 ,"UNION ",sql2," UNION ",sql4
How you could use spaces before column names.
I would suggest you to use UNION.
But, here's the least version of SQL;
sql = "SELECT NAME, month1 as unpaid_month, salary_amount FROM tablename WHERE month1 = 0"
sql = sql & " UNION "
sql = sql & "SELECT NAME, month2 as unpaid_month, salary_amount FROM tablename WHERE month2 = 0"
sql = sql & " UNION "
sql = sql & "SELECT NAME, month3 as unpaid_month, salary_amount FROM tablename WHERE month3 = 0"
sql = sql & " UNION "
sql = sql & "SELECT NAME, month4 as unpaid_month, salary_amount FROM tablename WHERE month4 = 0"
But, the query is not good enough. What will happen if someone is paid half of its salary. And why you should get more than one record for a single person? Shouldn't there be any SUM for salary_amount and string concatenation for unpaid_month?
As it wasn't the part of your question, I can't post the advanced SQL here. Please ask for it in comment if you want that.
Please read these functions SUM() and GROUP_CONCAT() with temporary table AS TABLE. I think that you should use them for good programming.

Access: Dlookup between 2 columns and multiple criteria

I am relatively new with Dlookup in access.
I have 2 tables
Table 1
empname | Doctype | Average
Table 2
Function | Ranking | bottomavg | topavg
I am writing a query and placing a relationship between function and doc type. I am pulling emp name, Doctype, average, and Score(renamed from Ranking). I am looking for employee score based on their average and where it falls in between bottomavg and topavg.
As an Expression, I wrote Score: DLookUp("Ranking","Table 2","" & [Average] & "Between Bottomavg And Topavg"). it works but it is not seeing the different doc types.
I tried score: DLookUp("Ranking","table 2","" & [Average] & "Between Bottomavg And Topavg" And [doctype]="&[function]&") and it did not work.
What am I missing to link Doc type to function?
Your quotes and & are all wrong. In addition I am not sure BETWEEN can be used the way you are trying to use it. Assuming your logic is correct and your syntax is the only problem and all your fields are numeric, this should work:
DLookUp("Ranking","table 2",[Average] & ">=Bottomavg And " & [Average] & "<=Topavg And " & [doctype] & "=Function")
With BETWEEN assuming Erik von Asmuth is correct and it works:
DLookUp("Ranking","table 2",[Average] & " BETWEEN Bottomavg And Topavg And " & [doctype] & "=Function")

Record edited twice if edited column has index

TableA has one column 'fielda' of type Long.
There are three records in the table with values 3,4 and 5 respectively.
After running the code below the values should be 18, 19 and 20.
This is the case if there isn't an index on fielda but if there is then the vaues will be
33, 19 and 20.
One record gets edited twice. Is this a bug in DAO or is this normal behaviour?
Dim rs As Recordset
Dim s1 As String
s1 = "select * from tableA"
Set DB = OpenDatabase(DBAddress)
Set rs = MyDB.OpenRecordset(s1)
If Not rs.BOF Or Not rs.EOF Then
rs.MoveFirst
Do While Not rs.EOF
rs.Edit
rs.Fields("fielda").Value = rs.Fields("fielda").Value + 15
rs.Update
rs.MoveNext
Loop
End If
While I was unable to recreate the behaviour you describe I can offer one possible explanation. As you are stepping through the records you may hit the same record more than once if the Recordset periodically checks for changes that may have been made to the underlying table by other users.
Say your Recordset starts out as
3 4 5
and you update the first record so the table now contains
18 4 5
if the Recordset then tries to "refresh" itself and the index on [fielda] controls the order in which the records appear in the Recordset it could end up being
3 4 5 18
and if it continues updating until .EOF the final result could be
3 19 20 33
Possible workarounds would be to
create the Recordset with a SQL statement that includes an ORDER BY clause on some other field so the order of the records will not change as you modify them, or
apply the update via SQL, e.g. UPDATE tableA SET fielda = fielda + 15

Concatenating multiple rows into single line in MS Access [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Combine rows in Access 2007
Access 2007 - Concatenate fields from one column in one table into a single, comma delmited value in another table
Currently I have a table structure that is somewhat like this:
Name --- Cat --- Desc --- Thresh --- Perc --- Err --- BP
Bob -------C1-------Inf--------7Per--------0.05------0-----ADC2
Bob -------C1-------Inf--------7Per--------0.05------2-----BAC2
Bob -------C1-------Inf--------7Per--------0.05------0-----RBE2
Bob -------C1-------Inf--------7Per--------0.05------8-----VBE2
Bob -------C1-------Inf--------7Per--------0.05------6-----AEC2
Bob -------C1-------Inf--------7Per--------0.05------0-----PBC2
Bob -------C2-------Com------8Per--------0.45------1-----XBC4
Bob -------C2-------Com------8Per--------0.45------0-----AEC2
Bob -------C2-------Com------8Per--------0.45------0-----PBC2
Bob -------C2-------Com------8Per--------0.45------3-----ADC2
Bob -------C2-------Com------8Per--------0.45------0-----ADC2
Bob -------C2-------Com------8Per--------0.45------0-----BAC2
Joe--------C1-------Inf---------7Per--------0.05------0-----PBC2
Joe--------C1-------Inf---------7Per--------0.05------0-----ZTM2
Joe--------C1-------Inf---------7Per--------0.05------2-----QYC2
Joe--------C1-------Inf---------7Per--------0.05------0-----FLC2
Joe--------C1-------Inf---------7Per--------0.05------1-----KSC2
Joe--------C1-------Inf---------7Per--------0.05------0-----JYC2
What i'm looking to do is have 1 line per "Name" and per "Cat", that will sum up all the "Err" (per "Name" and "Cat") and concatenate only the "BP" fields into a single line. Such as:
Name --- Cat --- Desc --- Thresh --- Perc --- Err --- BP
Bob -------C1-------Inf--------7Per--------0.05-----16-----BAC2, VBE2, AEC2
Bob -------C2------Com------8Per--------0.45------4------XBC4, ADC2
Joe--------C1-------Inf--------7Per--------0.05------3------QYC2, KSC2
There have been similar questions asked but I cannot seem to apply it as my knowledge of VBA scripting is beginner. Is there any way to do all of this via SQL? If VBA scripting is the only option (ie. creating a function), any help would be greatly appreciated. Thank You in advance.
Question part 2:
I created the function as per Allen Browne's guide. The module is saved as modConcatRelated. Now, i've tried to run this query (im not sure if this is the correct SQL to get the result that i'm looking for):
SELECT
[Name],
[Cat],
[Desc],
[Thresh],
[Perc],
sum([Err]),
ConcatRelated("[BP]", "make_table_bp", "[Err] = " & [BP])
FROM make_table_bp
GROUP BY
[Name],
[Cat],
[Desc],
[Thresh],
[Perc],
[Err],
[BP];
It said "Error 3061. Too few parameters. Expected 1." Also it said "Undefined Function ConcatRelated." I'm looking for guidance on how to create the correct SQL statement so that I can call the ConcatRelated function correctly and yield the result as depicted above. Thanks again.
Next question:
What if the table had a unique date field tagged on as the last column in the table. Something like this:
Name --- Cat --- Desc --- Thresh --- Perc --- Err --- BP --- Date
Bob -------C1-------Inf--------7Per--------0.05------0-----ADC2--12/02/2011
Bob -------C1-------Inf--------7Per--------0.05------2-----BAC2--09/05/2011
Bob -------C1-------Inf--------7Per--------0.05------0-----RBE2--11/02/2011
Bob -------C1-------Inf--------7Per--------0.05------8-----VBE2--08/14/2012
Bob -------C1-------Inf--------7Per--------0.05------6-----AEC2--02/25/2009
Bob -------C1-------Inf--------7Per--------0.05------0-----PBC2--07/02/2011
Bob -------C2-------Com------8Per--------0.45------1-----XBC4--09/05/2011
Bob -------C2-------Com------8Per--------0.45------0-----AEC2--02/02/2010
Bob -------C2-------Com------8Per--------0.45------0-----PBC2--08/14/2012
Bob -------C2-------Com------8Per--------0.45------3-----ADC2--05/05/2001
Bob -------C2-------Com------8Per--------0.45------0-----ADC2--08/02/2010
Bob -------C2-------Com------8Per--------0.45------0-----BAC2--06/17/2010
Joe--------C1-------Inf---------7Per--------0.05------0-----PBC2--08/14/2012
Joe--------C1-------Inf---------7Per--------0.05------0-----ZTM2--09/05/2011
Joe--------C1-------Inf---------7Per--------0.05------2-----QYC2--05/17/2010
Joe--------C1-------Inf---------7Per--------0.05------0-----FLC2--3/19/2010
Joe--------C1-------Inf---------7Per--------0.05------1-----KSC2--09/05/2011
Joe--------C1-------Inf---------7Per--------0.05------0-----JYC2--08/14/2012
Let's say I wanted to build a query to say something like: show me all records still within this same format:
Name --- Cat --- Desc --- Thresh --- Perc --- Err --- BP
Bob -------C1-------Inf--------7Per--------0.05-----16-----BAC2, VBE2, AEC2
Bob -------C2------Com------8Per--------0.45------4------XBC4, ADC2
Joe--------C1-------Inf--------7Per--------0.05------3------QYC2, KSC2
But for a date range of 01/01/2009 to 09/31/2011
#HansUp could you help with this?
I used a subquery for the GROUP BY which computes the Sum of Err for each group. Then I added the ConcatRelated function (from Allen Browne) with the fields returned by the subquery. This is the query and the output (based on your sample data in make_table_bp) from the query:
SELECT
sub.[Name],
sub.Cat,
sub.[Desc],
sub.Thresh,
sub.Perc,
sub.SumOfErr,
ConcatRelated("BP",
"make_table_bp",
"[Err] > 0 AND [Name] = '" & sub.[Name]
& "' AND Cat = '"
& sub.Cat & "'",
"BP")
AS concat_BP
FROM
(SELECT
q.[Name],
q.Cat,
q.[Desc],
q.Thresh,
q.Perc,
Sum(q.[Err]) AS SumOfErr
FROM make_table_bp AS q
GROUP BY
q.[Name],
q.Cat,
q.[Desc],
q.Thresh,
q.Perc
) AS sub
ORDER BY
sub.Name,
sub.Cat;
The query outputs this result set:
Name Cat Desc Thresh Perc SumOfErr concat_BP
Bob C1 Inf 7Per 0.05 16 AEC2, BAC2, VBE2
Bob C2 Com 8Per 0.45 4 ADC2, XBC4
Joe C1 Inf 7Per 0.05 3 KSC2, QYC2
Notice I enclosed Name, Desc, and Err with square brackets every place they were referenced in the query. All are reserved words (see Problem names and reserved words in Access). Choose different names for those fields if possible. If not, use the square brackets to avoid confusing the db engine.
But this will not work unless/until your copy of the ConcatRelated function is recognized by your data base engine. I don't understand why it's not; I followed the same steps you listed for storing the function code, and this works fine on my system.
Edit: I tested that query with my version of the table, which has [Err] as a numeric data type. Sounds like yours is text instead. In that case, I'll suggest you change yours to numeric, too. I don't see the benefit of storing numerical values as text instead of actual numbers.
However if you're stuck with [Err] as text, you can adapt the query to deal with it. Change this ...
"[Err] > 0 AND [Name] = '" & sub.[Name]
to this ...
"Val([Err]) > 0 AND [Name] = '" & sub.[Name]
That change prevented the "Data type mismatch in criteria expression" error when I tested with [Err] as text data type. However, I also changed this ...
Sum(q.[Err]) AS SumOfErr
to this ...
Sum(Val(q.[Err])) AS SumOfErr
AFAICT that second change is not strictly necessary. The db engine seems willing to accept numbers as text when you ask it to Sum() them. However I prefer to explicitly transform them to numerical values rather than depend on the db engine to make the right guess on my behalf. The db engine has enough other stuff to deal with, so I try to tell it exactly what I want.
Edit2: If you want only unique values concatenated, you can modify the ConcatRelated() function. Find this section of the code ...
'Build SQL string, and get the records.
strSql = "SELECT " & strField & " FROM " & strTable
and change it to this ...
'Build SQL string, and get the records.
strSql = "SELECT DISTINCT " & strField & " FROM " & strTable