Access VBA: Calculating Median on data using GROUP BY on two columns - sql

I am trying to find a way to calculate the median of a dataset in access, that is grouped by two columns, typeA, typeB.
This is a sample of the table:
ID (autonumber)
typeA (large number)
typeB (large number)
total (large number)
1
1
1
15
2
2
1
15
3
1
1
45
4
2
1
44
5
1
2
19
6
1
2
4
7
1
2
34
8
2
2
19
9
2
2
18
Using Access 2016
Currently I am using the following code snippet:
Function fMedian(SQLOrTable, GroupFieldName, GroupFieldValue, GroupFieldName2, GroupFieldValue2, MedianFieldName)
DoCmd.SetWarnings False
Dim rs As DAO.Recordset
Set db = CurrentDb
Set rs1 = db.OpenRecordset(SQLOrTable, dbOpenDynaset)
If IsDate(GroupFieldValue) Then
GroupFieldValue = "#" & GroupFieldValue & "#"
ElseIf Not IsNumeric(GroupFieldValue) Then
GroupFieldValue = "'" & Replace(GroupFieldValue, "'", "''") & "'"
End If
If IsDate(GroupFieldValue2) Then
GroupFieldValue2 = "#" & GroupFieldValue2 & "#"
ElseIf Not IsNumeric(GroupFieldValue) Then
GroupFieldValue2 = "'" & Replace(GroupFieldValue2, "'", "''") & "'"
End If
rs1.Filter = GroupFieldName & "=" & GroupFieldValue
rs1.Sort = MedianFieldName
Set rs = rs1.OpenRecordset()
rs.Move (rs.RecordCount / 2)
If rs.RecordCount Mod 2 = 0 Then
varMedian1 = rs.Fields(MedianFieldName)
rs.MoveNext
fMedian = varMedian1 + rs.Fields(MedianFieldName) / 2
Else
fMedian = rs.Fields(MedianFieldName)
End If
End Function
As it stands, this works great for grouping by one column, but I cannot figure out how to allow it to group by on both typeA and typeB. I have by editing the rs1.filter line but to no avail.
Any help with the code, or a better approach would be appreciated.
Thank you!
NOTE: solved using parfaits solution below. added line medianVBA = fmedian before the end of the function.

Consider an extension of #Fionnuala's great answer to calculate median in MS Access by accommodating an open-ended number of grouping variables.
VBA (save below in a standard module of Access project)
Code builds a dynamic SQL string for DAO recordset call for later median calculation. Special handling required for groupings with 0-2 records and null values for groupings.
Public Function MedianVBA(ParamArray Arr() As Variant) As Double
On Error GoTo ErrHandle
Dim N As Long
Dim tblName As String, numCol As String, grpVals As String
Dim strSQL As String
Dim db As DAO.Database, rs As DAO.Recordset
Dim varMedian As Double, fMedian As Double
'BUILD DYNAMIC SQL
tblName = Arr(0)
numCol = Arr(1)
grpVals = " WHERE " & numCol & " IS NOT NULL "
For N = 2 To UBound(Arr) Step 2
If Arr(N + 1) = "" Or IsNull(Arr(N + 1)) Then
grpVals = grpVals & " AND " & Arr(N) & " IS NULL"
ElseIf IsDate(Arr(N + 1)) Then
grpVals = grpVals & " AND " & Arr(N) & " = #" & Arr(N + 1) & "#"
Else
grpVals = grpVals & " AND CStr(" & Arr(N) & ") = '" & Arr(N + 1) & "'"
End If
Next N
strSQL = "SELECT " & numCol _
& " FROM " & tblName _
& grpVals _
& " ORDER BY " & numCol
'CALCULATE MEDIAN
Set db = CurrentDb
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
If rs.RecordCount = 0 Then
MedianAcc = fMedian
GoTo ExitHandle
ElseIf rs.RecordCount = 1 Then
MedianAcc = rs.Fields(numCol)
GoTo ExitHandle
End If
rs.Move (rs.RecordCount / 2)
rs.MovePrevious
If rs.RecordCount Mod 2 = 0 Then
varMedian = rs.Fields(numCol)
If rs.RecordCount = 2 Then
rs.MoveLast
Else
rs.MoveNext
End If
fMedian = (varMedian + rs.Fields(numCol)) / 2
Else
fMedian = rs.Fields(numCol)
End If
rs.Close
MedianAcc = fMedian
ExitHandle:
Set rs = Nothing: Set db = Nothing
Exit Function
ErrHandle:
MsgBox Err.Number & ": " & Err.Description, vbCritical, "RUNTIME ERROR"
Resume ExitHandle
End Function
Do note, above VBA function uses a ParamArray where first argument expects the source table and second column expects the numeric column and the remaining is open-ended for group column name and value pairs. Signature of call is as follows:
=MedianAcc("table_name",
"numeric_col",
"group1_column", "group1_value",
"group2_column", "group2_value",
...)
SQL (stored query that calls above VBA function)
Below runs a one-group and two-group median calculation.
SELECT t.typeA, t.typeB
, MedianVBA('[myTable]', '[total]', '[typeA]', t.typeA) AS MedianGrp1,
, MedianVBA('[myTable]', '[total]', '[typeA]', t.typeA, '[typeB]', t.typeB) AS MedianGrp2
FROM myTable t
GROUP BY t.typeA, t.typeB

Excuse me taking a totally different approach here...
Say you have a Table called Table1 with fields Field1.
To find the median of Field1 the SQL query would look like this:
SELECT TOP 1
((SELECT MAX(B.Field1) AS Field1 FROM
(SELECT TOP 50 PERCENT A.Field1 FROM Table1 A)
B) +
(SELECT MIN(D.Field1) AS Field1 FROM
(SELECT TOP 50 PERCENT C.Field1 FROM Table1 C ORDER BY C.Field1 DESC)
D))
/2 AS MEDIAN FROM Table1
(the above split out to make it more readable, I wrote it as only 2 lines)
From there all you have to do is write the vba to make it dynamic - replace 'Table1' with your variable SQLorTable and Field1 with the field to find the median of.

Related

Microsoft Office Access - Median function - Too few parameters

I am trying to use this code to calculate median from my query which has these criteria:
<[Form]![testForm2]![crit1] And >[Form]![testForm2]![crit2] and <[Form]![testForm2]![Age1] And >[Form]![testForm2]![Age2]
without these criteria function works well and gives for every task median based on "MP", however when I put in there my criteria I receive error:
error - Too few parameters. Expected 4 and then it says 'Object Variable or With block not set'
my input: DMedian("MP";"testForm2";"[TASK]= '" & [TASK] & "'")
*even when the Form is open it end up with the error.
*I probably need to find a different way to filter this query from the form, but I don't know how
Public Function DMedian(FieldName As String, _
TableName As String, _
Optional Criteria As Variant) As Variant
' Created by Roger J. Carlson
' http://www.rogersaccesslibrary.com
' Terms of use: You may use this function in any application, but
' it must include this notice.
'Returns the median of a given field in a given table.
'Returns -1 if no recordset is created
' You use this function much like the built-in Domain functions
' (DLookUp, DMax, and so on). That is, you must provide the
' 1) field name, 2) table name, and 3) a 'Where' Criteria.
' When used in an aggregate query, you MUST add each field
' in the GROUP BY clause into the into the Where Criteria
' of this function.
' See Help for more on Domain Aggregate functions.
On Error GoTo Err_Median
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strSQL As String
Dim RowCount As Long
Dim LowMedian As Double, HighMedian As Double
'Open a recordset on the table.
Set db = CurrentDb
strSQL = "SELECT " & FieldName & " FROM " & TableName
If Not IsMissing(Criteria) Then
strSQL = strSQL & " WHERE " & Criteria & " ORDER BY " & FieldName
Else
strSQL = strSQL & " ORDER BY " & FieldName
End If
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
'Find the number of rows in the table.
rs.MoveLast
RowCount = rs.RecordCount
rs.MoveFirst
'Determine Even or Odd
If RowCount Mod 2 = 0 Then
'There is an even number of records. Determine the low and high
'values in the middle and average them.
rs.Move Int(RowCount / 2) - 1
LowMedian = rs(FieldName)
rs.Move 1
HighMedian = rs(FieldName)
'Return Median
DMedian = (LowMedian + HighMedian) / 2
Else
'There is an odd number of records. Return the value exactly in
'the middle.
rs.Move Int(RowCount / 2)
'Return Median
DMedian = rs(FieldName)
End If
Exit_Median:
'close recordset
rs.Close
Exit Function
Err_Median:
If Err.number = 3075 Then
DMedian = 0
Resume Exit_Median
ElseIf Err.number = 3021 Then
'EOF or BOF ie no recordset created
DMedian = -1
Resume Exit_Median
Else
MsgBox Err.Description
Resume Exit_Median
End If
End Function
The parameter separation character is comma and you are using a semi-colon
CHANGE:
DMedian("MP";"testForm2";"[TASK]= '" & [TASK] & "'")
TO:
DMedian("MP", "testForm2", "[TASK]= '" & [TASK] & "'")
Solution was to refer the text boxes in SQL declaration, Thank you guys
like this:
HAVING (((Data.[REV]< " & Me.crit1 & ") And (Data.[REV])>" & Me.crit2 & ") AND ((Reg.Age)<" & Me.Age1 & " And (Reg.Age)>" & Me.Age2 & " " & SQLcritComplete & "));"
NOT like this:
"HAVING (((Data.[REV]<[Form]![testForm2]![crit1]) And (Data.[REV])>[testForm2]![crit2]) AND ((Reg.Age)<[Form]![testForm2]![Age1] And (Reg.Age)>[Form]![testForm2]![Age2] & SQLcritComplete & "));"

Is ther a Join function in vba to combine multiple fields rather than using concatenate function in access?

Thank you to all your responses.
I have a table with one id field and R1-R30 fields.
I was able to concatenate R1-R30 fields in a query using
Route: Trim([R1] & IIf([R2]="",""," ") & [R2] & IIf([R3]="",""," ") & [R3] & IIf([R4]="",""," ") & [R4] & IIf([R5]="",""," ") & [R5] & IIf([R6]="",""," ") & [R6] & IIf([R7]="",""," ") & [R7] & IIf([R8]="",""," ") & [R8] & IIf([R9]="",""," ") & [R9] & IIf([R10]="",""," ") & [R10] & IIf([R11]="",""," ") & [R11] & IIf([R12]="",""," ") & [R12] & IIf([R13]="",""," ") & [R13] & IIf([R14]="",""," ") & [R14] & IIf([R15]="",""," ") & [R15] & IIf([R16]="",""," ") & [R16] & IIf([R17]="",""," ") & [R17] & IIf([R18]="",""," ") & [R18] & IIf([R19]="",""," ") & [R19] & IIf([R20]="",""," ") & [R20] & IIf([R21]="",""," ") & [R21] & IIf([R22]="",""," ") & [R22] & IIf([R23]="",""," ") & [R23] & IIf([R24]="",""," ") & [R24] & IIf([R25]="",""," ") & [R25] & IIf([R26]="",""," ") & [R26] & IIf([R27]="",""," ") & [R27] & IIf([R28]="",""," ") & [R28] & IIf([R29]="",""," ") & [R29] & IIf([R30]="",""," ") & [R30])
My question is if the Join function I found can be applied to a query where the delimeter could be a spare, comma or slash.
Join (source_array,[delimiter])
Thanks
This would be the code to take all values of 1 single recordset into a bidimensional array, and then take those values into a unidimensional array (excluding null values, because null values cannot be joined with JOIN).
I think it would be better just looping trough every field with the loop, but in case it might help, i'll post it.
To replicate your issue, I just created a database with 1 single table with 2 records:
I'll concatenate all fields, excluding ID field. So with an easy query, I can get a recordset of 1 single record, using ID field as parameter:
SELECT Tabla1.Field1, Tabla1.Field2, Tabla1.Field3, Tabla1.Field4
FROM Tabla1
WHERE (((Tabla1.Id)=1));
And then the VBA code to Msgbox the fields joined, using a comma as delimiter.
Sub JOIN_RST()
Dim rst As Recordset
Dim vArray As Variant
Dim SingleArray() As Variant
Dim i As Long
Dim MySQL As String
Dim STRJoined As String
MySQL = "SELECT Tabla1.Field1, Tabla1.Field2, Tabla1.Field3, Tabla1.Field4 " & _
"FROM Tabla1 WHERE (((Tabla1.Id)=2));" 'query to get a single recordset.
Set rst = Application.CurrentDb.OpenRecordset(MySQL, 2, 4)
DoEvents
If rst.RecordCount > 0 Then
rst.MoveLast
rst.MoveFirst
vArray = rst.GetRows
ReDim SingleArray(UBound(vArray))
For i = 0 To UBound(SingleArray)
If IsNull(vArray(i, 0)) = True Then
SingleArray(i) = ""
Else
SingleArray(i) = vArray(i, 0)
End If
Next i
Debug.Print vArray(0, 0) 'Field 1
Debug.Print vArray(1, 0) 'Field 2
Debug.Print vArray(2, 0) 'Field 3
Debug.Print vArray(3, 0) 'Field 4
STRJoined = Join(SingleArray, ",")
Debug.Print STRJoined
End If
Set rst = Nothing
Erase vArray
Erase SingleArray
DoEvents
End Sub
If I execute this code using as WHERE parameter ID=1 , in debugger Window I get:
First Record
1
Null
My first record. Got a null value in Field 3 (it's empty)
First Record,1,,My first record. Got a null value in Field 3 (it's empty)
With ID=2 I get:
Second Record
2
Not null
Second Record
Second Record,2,Not null,Second Record
So this kinda works. I hope you can adapt it to your needs. but as i said. looking at the code, I think it would be easier just looping trough fields in a single query with all records. something like this:
Sub LOOPING_TROUGHT_FIELDS()
Dim RST As Recordset
Dim Joined_Records() As Variant
Dim i As Long
Dim MySQL As String
Dim STRJoined As String
Dim FLD As Field
MySQL = "SELECT Tabla1.Field1, Tabla1.Field2, Tabla1.Field3, Tabla1.Field4 " & _
"FROM Tabla1;" 'query to get all recordset you want to join
Set RST = Application.CurrentDb.OpenRecordset(MySQL, 2, 4)
DoEvents
If RST.RecordCount > 0 Then
RST.MoveLast
RST.MoveFirst
i = 0
ReDim Joined_Records(RST.RecordCount)
Do Until RST.EOF = True
For Each FLD In RST.Fields
If IsNull(FLD.Value) = True Then
STRJoined = STRJoined & "" & ","
Else
STRJoined = STRJoined & FLD.Value & ","
End If
Next FLD
Joined_Records(i) = Left(STRJoined, Len(STRJoined) - 1) 'we get 1 minus because there is an extra comma at end
i = i + 1
STRJoined = ""
RST.MoveNext
Loop
End If
Set RST = Nothing
Set FLD = Nothing
For i = 0 To UBound(Joined_Records) Step 1
Debug.Print Joined_Records(i)
Next i
Erase Joined_Records
End Sub
I don't know how many records you got. Try both and check how long does each option takes, and then choose 1.
Hope you can adapt all this to your needs. Welcome to SO.

Insert values from one table to another, better performance - Access 2000, VBA?

I have made this method:
Public Sub Proba()
Dim CPANonEmptyColumns As Integer
CPANonEmptyColumns = 0
Dim Max As Integer
Max = 0
Dim Koloni As String
Koloni = ""
Dim strSQL As String
Dim intI As Integer
Dim rsCPA As DAO.Recordset
Dim rsCPANezbirni As DAO.Recordset
Dim dbs_t1t2 As DAO.Database
On Error GoTo ErrorHandler
Set dbs_t1t2 = CurrentDb
'Open a recordset on all records from the Employees table that have
'a Null value in the ReportsTo field.
strSQL = "SELECT * FROM CPA_t1t2"
Set rsCPA = dbs_t1t2.OpenRecordset(strSQL) '//, dbOpenDynaset)
'If the recordset is empty, exit.
If rsCPA.EOF Then Exit Sub
intI = 1
With rsCPA
Do Until .EOF
DoCmd.RunSQL "INSERT INTO CPA_nezbirni (tipprod, promet) VALUES ('" & ![tipprod] & "', '" & ![promet] & "');"
' check individual column if it has a value and increment max if CPANonEmptyColumns
If ![t4k1] <> Null Or ![t4k1] <> "" Then
CPANonEmptyColumns = CPANonEmptyColumns + 1
Koloni = Koloni & "t4k1,"
End If
If ![t4k2] <> Null Or ![t4k2] <> "" Then
CPANonEmptyColumns = CPANonEmptyColumns + 1
Koloni = Koloni & "t4k2,"
End If
If ![t4k3] <> Null Or ![t4k3] <> "" Then
CPANonEmptyColumns = CPANonEmptyColumns + 1
Koloni = Koloni & "t4k3,"
End If
If CPANonEmptyColumns > Max Then
Max = CPANonEmptyColumns
End If
Debug.Print "Red: " & Str(intI) & " Max: " & Str(Max) & ", Koloni: " & Koloni
.Edit
.MoveNext
CPANonEmptyColumns = 0
Koloni = ""
intI = intI + 1
Loop
End With
rsCPA.Close
dbs_t1t2.Close
Set rsCPA = Nothing
Set dbs_t1t2 = Nothing
ErrorHandler:
MsgBox "Error #: " & Err.Number & vbCrLf & vbCrLf & Err.Description
End Sub
Basically, I open two tables, CPA_t1t2 and CPA_nezbirni. I want to copy the appropriate values for the appropriate columns, tipprod and promet from CPA_t1t2 to CPA_nezbirni.
The problem is, the source table CPA_t1t2 has 18000 rows and it needs time to run all those "INSERT" queries with the statement:
DoCmd.RunSQL "INSERT INTO CPA_nezbirni (tipprod, promet) VALUES ('" & ![tipprod] & "', '" & ![promet] & "');"
I am always suspicions when it comes SQL about performance. Since it needed 3-4 minutes to finish the procedure and insert values into CPA_nezbirni, is the SQL more slower way to copy value from one table to another?
Is there better, faster way by using the procedure above and some VBA, trough the same "Do Until" loop?

Checkboxes for taking input for a sql query in VBA (userform-excel)

I am trying to create a userform - which will have checkboxes for different years and command buttons for different queries. So if for example a user choses three checkboxes -1990,1993, 1995 and then the user clicks on a particular query. Then that query must be executed with that year in going into the "where part of that query"
This is my code :-
*
Private Sub CommandButton1_Click()
Dim connection As New ADODB.connection
Dim rst As New Recordset
Dim strConnectionStr As String
Dim Qry As String
strConnectionStr = "Provider=SQLOLEDB;" & "DATA SOURCE=" & _
"INITIAL CATALOG=;" & _
"UID=; PWD="
Qry = " SELECT d.Year,d.[University name],d.[School name], COUNT(distinct d.Title) 'Number of paper published'from [dbo].[Ashish$] d where [Business/Non-business]='1'group by d.Year,d.[University name],d.[School name] order by d.[Year], [Number of paper published] desc;"
ActiveSheet.Cells.ClearContents
connection.Open strConnectionStr
rst.Open Qry, connection
For iCols = 0 To rst.Fields.Count - 1
Sheets("Query1").Cells(1, iCols + 1).Value = rst.Fields(iCols).Name
Next
Sheets("Query1").Range("A2").CopyFromRecordset rst*`
rst.Close
connection.Close
End Sub
Above is the code for normal command buttons without check box . Below is the code for taking user inputs by checkboxes ...
Private Sub CommandButton1_Click()
Dim connection As New ADODB.connection
Dim rst As New Recordset
Dim strConnectionStr As String
Dim Qry As String
Dim ctl As Control
Dim i As Integer
i = 0
strConnectionStr = "Provider=SQLOLEDB;" & "DATA SOURCE=;" & _
"INITIAL CATALOG=;" & _
"UID=; PWD="
If CheckBox6.Value = True Then
year1 = CheckBox6.Caption
i = i + 1
End If
If CheckBox5.Value = True Then
year2 = CheckBox5.Caption
i = i + 1
End If
Qry = " SELECT d.Year,d.[University name],d.[School name], COUNT(distinct d.Title) 'Number of paper published'from [dbo].[Ashish$] d where [Business/Non-business]='1' and d.Year=CheckBox6.Caption group by d.Year,d.[University name],d.[School name] order by d.[Year], [Number of paper published] desc;"
ActiveSheet.Cells.ClearContents
connection.Open strConnectionStr
rst.Open Qry, connection
For iCols = 0 To rst.Fields.Count - 1
Sheets("Query1").Cells(1, iCols + 1).Value = rst.Fields(iCols).Name
Next
Sheets("Query1").Range("A2").CopyFromRecordset rst
rst.Close
connection.Close
End Sub
ub
Basically I am unable to take values from checkboxes and use them inside query statement for the purpose.
I need help . Can anyone guide me on this?
edit: the following was originally posted as an answer:
If CheckBox1.Value = True Then
y1 = CheckBox1.Caption
i = i + 1
End If
If CheckBox2.Value = True Then
y2 = CheckBox2.Caption
i = i + 1
End If
If CheckBox3.Value = True Then
x1 = CheckBox3.Caption
j = j + 1
End If
If CheckBox4.Value = True Then
x2 = CheckBox4.Caption
j = j + 1
End If
If CheckBox5.Value = True Then
x3 = CheckBox5.Caption
j = j + 1
End If
If i = 0 Then
MsgBox "Select at least one year "
End If
If j = 0 Then
MsgBox "Select at least one journal "
End If
strConnectionStr = "Provider=SQLOLEDB;" & "DATA SOURCE=;" & _
"INITIAL CATALOG=;" & _
"UID=; PWD="
Qry = " SELECT d.Year,d.[University name],d.[School name], COUNT(distinct d.Title) 'Number of paper published'from [dbo].[Ashish$] d where [Business/Non-business]='1' and "
Qry = Qry & "[Year] IN (" & y1 & "," & y2 & ") and [Name] IN (" & x3 & "," & x4 & ") & vbCrLf"
Qry = Qry & "group by d.Year,d.[University name],d.[School name] order by d.[Year], [Number of paper published] desc;"
ActiveSheet.Cells.ClearContents
connection.Open strConnectionStr
rst.Open Qry, connection
For iCols = 0 To rst.Fields.Count - 1
Sheets("Query1").Cells(1, iCols + 1).Value = rst.Fields(iCols).Name
Next
Sheets("Query1").Range("A2").CopyFromRecordset rst
rst.Close
connection.Close
End Sub
Above is my code and the question is posted in my last comment
It's as simple as ...and d.Year=" & CheckBox6.Caption & " group by...
If you want to use the value of a variable then it has to be outside of the double quotes. You can then use the & operator to join the pieces back together.
BUT: constructing an SQL query from user input by joining strings together is asking for trouble. SQL injection can be a very real possibility - see here and here
You can use an ADODB Command object in conjunction with the Parameters collection to execute a paramaterized query in a safe manner. See this answer for a demonstration of how to do so
edit: if some of the values are text strings then they should be enclosed in single quotes like this:
and [Name] IN ('" & x3 & "','" & x4 & "')
which will produce output like this:
and [Name] IN ('Academy of Science','Foo')
If only some of the variables might have values then you need to construct the IN clause differently:
Dim yearsChosen As String
If CheckBox1.Value = True Then
yearsChosen = yearsChosen & "," & CheckBox1.Caption
i = i + 1
End If
If CheckBox2.Value = True Then
yearsChosen = yearsChosen & "," & CheckBox2.Caption
i = i + 1
End If
' Check to see if anything was selected - if it was, remove the
' leading comma and add the AND [Year] IN part
If Len(yearsChosen <> 0) Then
yearsChosen = " AND [Year] IN (" & Mid$(yearsChosen, 2) & ")"
End If
The Names part would work similarly except you need single quotes around the values:
namesChosen = namesChosen & ",'" & CheckBox5.Caption & "'"
Building the SQL query is quite simple:
Qry = " SELECT d.Year,d.[University name],d.[School name], COUNT(distinct d.Title) 'Number of paper published'from [dbo].[Ashish$] d where [Business/Non-business]='1' "
Qry = Qry & yearsChosen & namesChosen & vbCrLf
Qry = Qry & "group by d.Year,d.[University name],d.[School name] order by d.[Year], [Number of paper published] desc;"

Inserting every OTHER ROW from one table to another (VBA MS Access 2010)

I am working with manually created empty copy of table Products, which I named Products_Backup. What I want to do is to insert every other row from "Spices" category of products into this empty Products_Backup table, since there would be only 6 rows from total of 12 rows, that are in Products table under "Spices" category. The problem is that I don't know how to do that. I tried to use MOD operator for newly created ProductID, but my mentor told me that it is not a proper solution, since he could easily change this ProductID's value and I would get odd rows instead of even.
Private Sub CommandButton0_Click()
Dim db As Database, rst As Recordset
Dim I As Integer, s, s1 As String
Set db = CurrentDb
s = "SELECT Products.* FROM Products WHERE (((Products.CategoryNumber)=2));" ' This value is for Spices
Set rst = db.OpenRecordset(s)
I = 1
While Not rst.EOF
s1 = "INSERT INTO Products_Backup (ProductName, ProductID, CategoryNumber, OrderedUnits) VALUES ('" & rst!ProductName & "', " & I & " , '" & rst!CategoryNumber & "', '" & rst!OrderedUnits & "');"
MsgBox ("Record inserted")
db.Execute s1
I = I + 1
rst.MoveNext
If I Mod 10 = 0 Then
MsgBox ("Inserted " & I & ".record")
End If
Wend
rst.Close
db.Close
End Sub
So with this I can insert all 12 records into Products_Backup, with MsgBox telling me when 10th record was inserted.
But I still have no idea what to do to insert every other row into Products_Backup to get 6 records.
Dim booEveryOther as Boolean
booEveryOther = False
While Not rst.EOF
If booEveryOther Then
s1 = "INSERT INTO ...
End If
booEveryOther = Not booEveryOther
Just use a Boolean value that is set to Not itself with every new record.
i think this should do it better
While Not rst.EOF
s1 = " INSERT INTO Products_Backup (ProductName, ProductID, CategoryNumber, OrderedUnits) " & _
" VALUES ('" & rst!ProductName & "', " & I & " , '" & rst!CategoryNumber & "', '" & rst!OrderedUnits & "');"
db.Execute s1
If I Mod 10 = 0 Then
MsgBox ("Inserted " & I & ".record")
Else
MsgBox ("Record inserted")
End If
I = I + 1
rst.MoveNext
Wend