Loop through employee numbers and see if certain date falls within a period - vba

Who can help a beginner out. I've added two screenshots to make my story clearer.
My excel sheet is two tabs. One is 'calculation' and other is 'project'.
What i'd like to know is how to program the following in vba:
In the calculation tab there is a employee number in column E. I have to look if that number also is written in the projects tab. If so i need to know if the date of the calculation tab falls within the start and end date in the projects tab. If so then write the info if that row to the empty columns in the calculation tab.
Another problem arises when an employee works multiple jobs in the projects tab. I guess there needs to be another loop in here:
If the date from calculation tab doesn't fall in the period from start to end in the projects tab, is there another row with the same employee number and maybe it falls within that period.
I hope i made my story clear. I know what the steps should be, just not how to program it. I hope someone is able to help me with this.

Since your screenshots appear to be Excel for Windows consider an SQL solution using Windows' JET/ACE Engine (.dll files) as you simply need to join the two worksheets with a WHERE clause for date filter. In this approach you avoid any need for looping and use of arrays/collections.
To integrate below, add a new worksheet called RESULTS as SQL queries on workbooks are read-only operations and do not update existing data. A LEFT JOIN is used to keep all records in Calculations regardless of matches in Projects but matched data will populate in empty columns. Results should structurally replicate Calculations. Adjust column names in SELECT, ON, and WHERE clauses as required (as I cannot clearly read column names from screenshots). Finally, a very important item: be sure date columns are formatted as Date type.
Dim conn As Object, rst As Object
Dim strConnection As String, strSQL As String
Dim i As Integer
Set conn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
' OPEN DB CONNECTION
strConnection = "DRIVER={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _ '
& "DBQ=C:\Path\To\Workbook.xlsx;"
conn.Open strConnection
' OPEN QUERY RECRDSET
strSQL = "SELECT t1.*, t2.[Project] AS [Which Project], t2.[Customer] As [Which Customer]," _
& " t2.[Start], t2.[End planned], t2.[Hours per week]" _
& " FROM [Calculation$A$3:$D$1048576] t1" _
& " LEFT JOIN [Projects$A$3:$J$1048576] t2" _
& " ON t1.EmployeeNum = t2.EmployeeNum" _
& " WHERE t1.[Date] BETWEEN t2.Start AND t2.[End planned];"
rst.Open strSQL, conn
' COLUMNS
For i = 1 To rst.Fields.Count Worksheets("RESULTS").Cells(3, i) =
rst.Fields(i - 1).Name
Next i
' DATA ROWS
Worksheets("RESULTS").Range("A4").CopyFromRecordset rst
rst.Close
conn.Close
Set rst = Nothing
Set conn = Nothing

it would be great to let us know, what you have done so far. I think the easiest way for a beginner is to just use two loops. One for the calculation and one for the projects tab.
Then you can start to develop your functionality. Use a "row counter" for each worksheet and iterate trough the rows. Here is an example pseudo code:
Dim lRowCountCalc as Long
Dim lRowCountPrj as Long
lRowCountCalc = 1
lRowCountPrj = 1
do
do
If Table2.Range("A" & lRowCountPrj).Value = Table1.Range("E" & lRowCountPrj).Value Then
If ... dates are equal
'Do some stuff
End if
End If
lRowCountPrj = lRowCountPrj +1
Loop Until lRowCountPrj = 5000 Or Table2.Range("A" & lRowCountPrj).text = ""
lRowCountCalc = lRowCountCalc +1
Loop Until lRowCountCalc = 5000 Or Table1.Range("A" & lRowCountCalc).text = ""
Just check for each employee number in calculation if there is a the same number in the current row in projects. If so, do your checks and fill in the information you need. If there is more than one project, you will find it also because all rows will be checked.
But be careful. This is very expensive because this code iterates for each row in projects over all rows in calculation. But for the beginning I would do it like this.

Related

Changing headers display and order from a recordset to excel sheet

I have an excel sheet that I use as database, and a search form that allow user to search for information, based on some criterias, and display the filtered results in a new sheet.
I am using SQL to fetch data, and display them to the user.
I use something like top open connection, then to create a record set and pass my sql request to it
m_Connection.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0;HDR=Yes;"";"
Set OpenRecordset = CreateObject("ADODB.Recordset")
OpenRecordset.Open sql, GetConnection(), 3, 3, &H1
Set rst = OpenRecordset("SELECT * FROM [Database$] Where " & Myconditions & ";")
Everything works fine, but I need to allow users to choose the column headers names and order that may be different from what i have in the sheet from which i make my select that i call database
We need this because users are in different countries, so the display name will be configured based on the country of the user, but also we want to allow user to change the display name and order of the fields based on their needs and because the display name may be too long (multi line).
My real "database" sheet is about 110 columns, and about 1000 records (rows).
I can't publish the real data because it's confidential, but to help you understand me, I created this example that represent what I have
let us suppose I have this "database"
the user enter this search screen to select the information he needs from the database
I wish that the user will get this result and not in the same order and display of the database
as you can see, the display names and orders of the columns in the result page is different from the "database" sheet
I would like to create a configuration page, in which the user can specify the display name he wants and the order in which he wants the fields to appears. something like that
Is there any fast way to do that directly in my Recordset in SQL/EXCEL or I should after I fetch data, change the headers in excel sheet using vba ? if so, I have to make a kind of array in vba that contains both database Names and display names and replace the names of the database by its corresponding just before I show the result page shows ?
any suggestions ?
same question about the order of the fields, how to sort them based on the order the user choosed ? any fast way ?
Thanks for anyone who can help with the best way to do that
You could do the following, it loops through the data range based on the number of rows in the range being the min and max of positions available, it looks for these rankings in turn, in column C, then checks if shown, then add's the field name and it's alias to an array. This array is then joined. So using data similar to yours, in columns of the the same ordering, I called:
GenerateOrderedSQL("table 1",range("a2:d6"),3,4) A1:D1 contained headers
This called my function
Function GenerateOrderedSQL(strInputTable As String, _
rngRangeForSelection As Excel.Range, _
lngOrderColumn As Long, _
lngShowColumn As Long) As String
Dim l As Long
Dim fPos As Long
Dim lfPos As Long
Dim a() As Variant
l = rngRangeForSelection.Rows.Count
ReDim a(l)
For fPos = 1 To l
lfPos = Application.WorksheetFunction.Match(fPos, _
rngRangeForSelection.Columns(lngOrderColumn), 0)
If rngRangeForSelection.Cells(lfPos, lngShowColumn).Value = "Yes" Then
a(fPos-1) = "[" & rngRangeForSelection.Cells(lfPos, 1) & _
"] AS [" & rngRangeForSelection.Cells(lfPos, 2) & "]"
a(fPos-1) = a(fPos-1) & IIf(fPos < l, ",", vbNullString)
End If
Next
Debug.Print "SELECT " & Join(a, vbNullString) & " FROM [" & strInputTable; "]"
End Function`
This gave the following
SELECT [Fname] AS [First Name],[Lname] AS [Last Name],[Zip] AS [Zip],[City] AS [City] FROM [table 1]

Excel - Merge matching rows

I have an Excel sheet with a list of rows containing information in columns.
I also have a reference sheet (or copied further down in the same sheet) with lots of rows also containing strings/values in columns, in the same format.
Many of the rows in column A in the project sheet have a duplicate in the reference area.
The sheets will have different rows from time to time, but the column format will always be the same.
The macro function i need has to do the following:
Check row 2 column A for a match further down the list in the same column (there will be no triples).
If there is one, copy cells from column E,F,G,H,I,J of the row further down the list into row 2.
If no duplicate is found, or when information is copied and pasted, repeat process for row 3, etc until no more filled rows.
Like this:
That's it. Sounds simple, but i have not been able to figure out how to write the function.
Extensive googling has not given me an example of something similar.
Forgive me if I missed something, but I have tried to find similar questions and failed.
I feel like it shouldn't be very hard to solve this, so hopefully someone can help out :)
Edit:
So I managed to solve it like this:
I put the reference sheet I in a separate workbook (named it TagReference.xlsb).
In the project workbook cell O1 i added the function
=VLOOKUP(A1; [TagReference.xlsb]Sheet1!$A:$E;5;false)
and did an autofill down to row 1500 which is plenty.
That gave me the values for column E. I copied and pasted that as values into the column.
Then i did the same thing for column F with
=VLOOKUP(A1; [TagReference.xlsb]Sheet1!$A:$F;6;false
and so on until all columns were filled.
Recorded everything as a macro, and now it works fine :)
I am a complete noob at Excel, so I mostly needed a point to start at, and =VLOOKUP did the job.
Thanks everyone!
s = s & "FROM [DATA$] AS a, [Reference$] AS b "
DATA is sheet's name (Sheet with a list of rows containing information in columns).
Reference is sheet's name (reference sheet )
Sub test()
Dim s As String, Ws As Worksheet
s = "SELECT a.name, a.device, a.address, a.datatype, b.rawmin, b.rawmax, b.engmin, b.engmax, b.unit, b.format, a.description, a.alarmoptions, a.trendoptions "
s = s & "FROM [DATA$] AS a, [Reference$] AS b "
s = s & "WHERE a.name = b.name "
Set Ws = Sheets.Add
ExeSQL Ws, s
End Sub
Sub ExeSQL(Ws As Worksheet, strSQL As String)
Dim Rs As Object
Dim strConn As String
Dim i As Integer
strConn = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & ThisWorkbook.FullName & ";" & _
"Extended Properties=Excel 12.0;"
Set Rs = CreateObject("ADODB.Recordset")
Rs.Open strSQL, strConn
If Not Rs.EOF Then
With Ws
.Range("a1").CurrentRegion.Clear
For i = 0 To Rs.Fields.Count - 1
.Cells(1, i + 1).Value = Rs.Fields(i).Name
Next
.Range("a" & 2).CopyFromRecordset Rs
End With
End If
Rs.Close
Set Rs = Nothing
End Sub
So I managed to solve it like this:
I put the reference sheet I in a separate workbook (named it TagReference.xlsb).
In the project workbook cell O1 i added the function
=VLOOKUP(A1; [TagReference.xlsb]Sheet1!$A:$E;5;false)
and did an autofill down to row 1500 which is plenty.
That gave me the values for column E. I copied and pasted that as values into the column.
Then i did the same thing for column F with
=VLOOKUP(A1; [TagReference.xlsb]Sheet1!$A:$F;6;false
and so on until all columns were filled.
Recorded everything as a macro, and now it works fine :)
I am a complete noob at Excel, so I mostly needed a point to start at, and =VLOOKUP did the job.
Thanks everyone!

SQL in VBA: filtering part of DB row

I have a code which takes data from a DB with a SQL statement with 2 WHERE conditions. What I want is to paste the recordset into sheet2 . Each recordset has 13 columns of data. Problem is, when I take the recordset and I paste them into sheet2, the pasted columns are only the first 3.To note that from column 4 to 10 there can be empty columns
Do you know what could be the problem?
UPDATE 3: Updated question and code according to feedback
'Create the SQL statement to retrieve the data from table.
With Recordset
SQL = "SELECT * FROM Data WHERE [PRini] = '" & var & "' or [QAini] = '" & var & "' "
'Create the ADODB recordset object.
Set rs = New ADODB.Recordset 'assign memory to the recordset
'ConnectionString Open '—-5 aguments—-
'Source, ActiveConnection, CursorType, LockType, Options
rs.Open SQL, cnn
'If not, write the recordset values in the sheet.
Sheet2.Range("A2").CopyFromRecordset rs 'PROBLEM: The pasted row is not the full one in access, but only the first 3 columns. from the 4th to the 10th there are no data, from 11th to 13th there are but are not taken
It's hard to know exactly the problem, and there are all sorts of things wrong with this code. The issues which may be related to your problem include:
SQL = "SELECT * FROM Data WHERE [PRini] or [QAini] = '" & var & "' " will return rows where either PRini is TRUE or QAini = var. Did you mean SQL = "SELECT * FROM Data WHERE [PRini] = '" & var & "' or [QAini] = '" & var & "' " - i.e. where PRini = var or QAini = var?
the autofilter is applied to the table "Table1", but there is nothing to say this table has the same dimensions as the recordset in either direction (copyFromRecordset does not create or populate a table, it just pastes the values straight in to the worksheet). If you need the data in a table, use the QueryTable.Connection, QueryTable.CommandType and QueryTable.CommandText properties to connect the table to the SQL server directly (see the MSDN docs). Or apply the autofilter to the range containing the data (Sheet2.Range("A2").CurrentRegion will do).
there is nothing in the code that references the current date. The code from 'Filter for the date onwards just copies the visible cells from the first two columns into a listBox control.
Why not include the date condition in the SQL? That would be the approach I would use (e.g. SELECT * FROM Data WHERE ([PRini] = 'something' OR [QAini] = 'something') AND [MyDateColumn] < DATE();)

Ms Access 2007 queries returns Boolean values false when it should be true

This kind of hard to explain specially since english is not my first language, let's see if can make myself understand, im trying to perform a Select query to get the records within a time frame(column ContactDate contains the date/time values) the query is as follow:
SELECT Val([ACD_ID] & Format(DateValue([ContactDate]),'0')) AS SEARCH_CODE, CFinal, 1 AS Expr1,
COPCFCR, FCRPossible, RecordName
FROM [YTD-Daily_Report]
WHERE ((([YTD-Daily_Report].[ContactDate])>=#9/01/2014#
And ([YTD-Daily_Report].[ContactDate])<=#10/01/2014#));
In the source Table(YTD-Daily_Report) COPCFCR and FCRPossible are define as Checkboxes(true or false), when i run this query using Access within the database it all works well i get a column with the concatenated value of the ID + Date, a column containing the score, a column with a 1 in it, a column with the COPCFCR value(true or false), a column with the FCRPossible value(true or false), and column with the RecordName, at this point if i compared with the values on the table they match 100%.
Now, i took this query and put it on an Excel workbook but when it runs it returns the values for the columns COPCFCR and FCRPossible wrong, sometimes a false is returned as true or viceversa and other times the values match 100% with the corresponding values on the source table, for example in some rows COPCFCR is returned as true when it should be false according to the source table.
Here is the Excel VBA code I'm using:
Dim rsSource As New Recordset
Dim m_Connection As New Connection
Dim rngTarget as range
dim result as long
m_Connection.Provider = "Microsoft.ACE.OLEDB.12.0"
m_Connection.Open "Path and name of the Database"
strQuery = "SELECT Val([ACD_ID] & Format(DateValue([ContactDate]),'0')) AS SEARCH_CODE, CFinal, 1 AS Expr1, COPCFCR, FCRPossible, RecordName" & Chr(13) & _
"FROM [YTD-Daily_Report]" & Chr(13) & _
"WHERE ((([YTD-Daily_Report].[ContactDate])>=#" & Format(START_DATE, "m/dd/yyyy") & "# And ([YTD-Daily_Report].[ContactDate])<=#" & Format(STOP_DATE + 1, "m/dd/yyyy") & "#));"
rsSource.Open strQuery, m_Connection, adOpenForwardOnly, adLockReadOnly
Set rngTarget = Range("A2")
result = rngTarget.CopyFromRecordset(rsSource)
If rsSource.State Then rsSource.Close
Set rsSource = Nothing
If m_Connection.State Then m_Connection.Close
Set m_Connection = Nothing
Any ideas what could be happening?
It seems the database file was corrupted and this caused the data to be exported in a different way that it was call for. The query is working fine as it is.

Query every table in an Access Database?

All tables in a certain database have the exact columns, so I'm wondering if there is a way I can query all of them at once for a specific few columns that I know every table will have. The reason I want to do this is that the number of tables in the database will constantly be growing, and I don't want to have to every day go and change my query to accommodate the names of the new tables.
Help is appreciated as always
In that case, try ADO:
Function ListTablesContainingField(SelectFieldName) As String
'Tables returned will include linked tables
'I have added a little error coding. I don't normally do that
'for examples, so don't read anything into it :)
Dim cn As New ADODB.Connection
Dim rs As ADODB.Recordset
Dim strTempList As String
On Error GoTo Error_Trap
Set cn = CurrentProject.Connection
'Get names of all tables that have a column called <SelectFieldName>
Set rs = cn.OpenSchema(adSchemaColumns, _
Array(Empty, Empty, Empty, SelectFieldName))
'List the tables that have been selected
While Not rs.EOF
'Exclude MS system tables
If Left(rs!Table_Name, 4) <> "MSys" Then
strTempList = strTempList & "," & rs!Table_Name
End If
rs.MoveNext
Wend
ListTablesContainingField = Mid(strTempList, 2)
Exit_Here:
rs.Close
Set cn = Nothing
Exit Function
Error_Trap:
MsgBox Err.Description
Resume Exit_Here
End Function
From: http://wiki.lessthandot.com/index.php/ADO_Schemas
You might like to consider a table of tables, if you have not already got one, that lists the linked Excel tables and holds details of archive dates etc, because you will run into limits at some stage.