Microsoft Access: How to create new table that has 1 of every 5 records from the original? - ms-access

I have a large table and want to create a smaller table that systematically picks out one of every 5 records from the original. How best to do this?
This means it should have every row with id ending in 0 and 5 for example.
Thanks.

Assuming that your IDs as auto-incremented and continuous (with no deleted records), the simplest way could something like:
SELECT *
FROM BigTable
WHERE ID Mod 5 = 0
You would insert that into the small table like this:
INSERT INTO SmallTable
SELECT *
FROM BigTable
WHERE ID Mod 5 = 0
If your primary key ID is not sequential you can do this:
SELECT BigTable.*
FROM (SELECT ID,
(SELECT COUNT(ID) + 1
FROM BigTable AS A
WHERE A.ID < B.ID) AS RowNum
FROM BigTable AS B) AS C
INNER JOIN BigTable
ON C.ID = BigTable.ID
WHERE RowNum Mod 5 = 0
Note though that this is OK for a one-time thing as it is quite slow if you have a lot of records.
Better do it in code if you have lots of records (or maybe you have no primary key, which is usually bad btw).
The code below is generic code to copy all records from one table into another (existing) table:
Public Sub CreateSmallTable(largeTableName As String, _
smallTableName As String, _
interval As Integer)
Dim rsL As DAO.RecordSet
Dim rsS As DAO.RecordSet
Dim db As DAO.Database
Dim rowNum As Integer
Set db = CurrentDb()
' Open the LargeTable in read-only mode '
Set rsL = db.OpenRecordset(largeTableName, dbOpenSnapshot)
If Not (rsL Is Nothing) Then
Set rsS = db.OpenRecordset(smallTableName, dbOpenTable, dbAppendOnly)
With rsL
' We'll use a generic way to copy all fields from the BigTable '
Dim fd As DAO.field
Dim flds As DAO.Fields
Set flds = rsL.Fields
.MoveFirst
' For each record in the BigTable '
Do While Not .EOF()
If rowNum Mod interval = 0 Then
rsS.AddNew
' Copy all fields from BigTable to SmallTable '
For Each fd In flds
rsS.Fields(fd.Name) = .Fields(fd.Name)
Next fd
rsS.Update
End If
rowNum = rowNum + 1
.MoveNext
Loop
.Close
End With
rsS.Close
Set rsS = Nothing
Set rsL = Nothing
End If
End Sub
And call it like that (assuming that both BigTable and SmallTable have the same structure and that there are no existing records in SmallTable that could create a primary key violation when trying to inster duplicate records):
CreateSmallTable "Bigtable", "Smalltable", 5
Edit: following HansUp response, changed SQL queries to use Mod instead of its functional version: (Round(ID/5) = ID/5). He's right, no need to make it more complex than it needs to be.

Consider id Mod 5, and select only those where the remainder is zero.
SELECT f.id, f.foo_text
FROM tblFoo AS f
WHERE (id Mod 5) = 0;

Related

how to get attachment files using union query in ms access

I have two independent tables in ms access now i want to get all data from both tables and show as one table using union query.
all is work but the problem is the attachment fields doesn't not loaded and its Empty.
SELECT *
FROM Table1
UNION ALL select * from Table2;
--This is my query which gets all records from both table but the attachment type field is empty
This example may be usefull
Set rsChild = rsDocs.Fields("DocText").Value
rsChild.Fields("FileData").SaveToFile newFileName
rsChild.Close
where rsDocs - ADO (or DAO) recordset as query result
DocText - attachment field name
rsChild.Fields("FileData") - stream object
SaveToFile - method of attachment field
rsDocs.Fields("DocText").Value.Fields("FileData").SaveToFile
The below example uses an attachment field named AttachmentField. You can pass the name of the file you're looking through the parameter.
If you run only the SQL, the parameter window will pop-up asking for the parameter value. To search, find the file and open it, you will need to use VBA.
See an example:
PARAMETERS [FileNameParam] Text (255);
SELECT T.ID, T.FileName
FROM (
SELECT ID, AttachmentField.FileName AS FileName
FROM Table1
UNION ALL
SELECT ID, AttachmentField.FileName AS FileName
FROM Table2
) AS T
WHERE T.FileName Like '*' + [FileNameParam] + '*'
Dim q As DAO.QueryDef
Set q = CurrentDb().QueryDefs("Query1")
q.Parameters("[FileNameParam]").Value = "Blank.pdf"
Dim r As DAO.Recordset
Set r = q.OpenRecordset(dbOpenSnapshot)
'nothing found
If r.EOF Then
MsgBox "File not found."
Exit Sub
End If
Dim filepath As String
filepath = r![FileName]
'open
Application.FollowHyperlink filepath
'clean up
If Not r Is Nothing Then r.Close
If Not q Is Nothing Then q.Close

ACCESS sql code to multiply record with calculated value from previous cell

I am using Access Database to get a value. I am fairly new to access as I usually use SQLServer and I am having trouble in getting what I want.
I have the following table, with column TARGET and incremental Target as the target column that I need to get:
Category|Period|Value| TARGET |
A | 4 | 1 | 1/1 =1 |
A | 3 | 3 | 1/(3*1)=0.33 | (1/value at period 3 * previous target)
A | 2 | 6 |1/(0.33*6)=0.505|
A | 1 | 9 |1/(0.505*9)=0.22|
The data is partitioned by Category and ordered in descending order by Period.
For the first row the Target should be: (1/value at current period)
For the next rows the Target should be: (1/value at current period * value of previous target)
As you can see this is somehow complex as I need to evaluate a cell value and then for the next row I need to use the value in the cell above.
Plus I need to get the incremental value for this column as well.
Any help will be very much appreciated as I am new to Access and need to get this done soon!
Here is a function placed in general module that can be called from query. Value is a reserved word so I used Data for that field name.
Option Compare Database
Option Explicit
Global dblTar As Double
Global strCat As String
____________
Function CalcTarget(strC As String, dblT As Double) As Double
If strCat <> strC Then
strCat = strC
dblTar = dblT
End If
dblTar = 1 / (dblT * dblTar)
CalcTarget = dblTar
End Function
Calling function in query:
SELECT Category, Period, Data, CalcTarget([Category],[Data]) AS Target FROM Table1;
Normally I advise not to save calculated data to table when a query can work, but if you prefer to save, then options are:
An UPDATE action: UPDATE Table1 SET Target = CalcTarget([Category],[Data]);
Or VBA:
Sub CalcTarget()
Dim rs As DAO.Recordset
Dim strCat As String
Dim dblTar As Double
Set rs = CurrentDb.OpenRecordset("SELECT * FROM table1 ORDER BY Category, Period DESC")
strCat = rs!Category
dblTar = rs!Data
Do While Not rs.EOF
If rs!Category = strCat Then
dblTar = 1 / (rs!Data * dblTar)
rs.Edit
rs!Target = dblTar
rs.Update
rs.MoveNext
Else
strCat = rs!Category
dblTar = rs!Data
End If
Loop
End Sub

vb.net caching database tables

I had a program that was running fine. But I want to speed up my program's running speed.
Old code is something like this:
Public Funtion CalcSomething(Byval IncID as int16) as double
Dim rs as adodb.recordset()=cn.execute("SELECT A,B,C,D,.....(around 10 values) FROM table1 t1 LEFT JOIN table2 t2 ON t1.A=t2.A LEFT JOIN ………………(around 10 tables join together WHERE t1.ID=" & IncID)
Dim Cost1 as double = rs.fields.item("B").value
Dim AryCost2(19) as double
For i as int16=0 to 19
AryCost2(I)=GetCost2(rsX,i,rs.fields.item("A").value,rs.fields.item("C").value)
Next I
Dim Cost2 as double = GetMinValue(AryCost2)
Return Cost1 + Cost2
End function
Public Function GetCost2(ByVal I as int16,ByVal A as int16,ByVal B as int16) as double
Value=DoSomeCalculate(I,A,B)
Dim rs as adodb.recordset()=cn.execute("SELECT X FROM tableX WHERE Value=" & Value)
Do while Not rs.EOF
if FindSuitableOne(rs.fields.item("X").value) then
Return rs.fields.item("X").value
End if
rs.movenext()
Loop
return -1
end function
I thought getting value from tableX 20 times will be a wasting of time, so I try to cache the whole table and use Filter to find the related rows:
Public Funtion CalcSomething(Byval IncID as int16) as double
Dim rs as adodb.recordset()=cn.execute("SELECT A,B,C,D,.....(around 10 values) FROM table1 t1 LEFT JOIN table2 t2 ON t1.A=t2.A LEFT JOIN ………………(around 10 tables join together WHERE t1.ID=" & IncID)
\\Cache whole table into rsX
Dim rsX as adodb.recordset()=cn.execute("SELECT X FROM tableX")
Dim Cost1 as double = rs.fields.item("B").value
Dim AryCost2(19) as double
For i as int16=0 to 19
AryCost2(I)=GetCost2(rsX,i,rs.fields.item("A").value,rs.fields.item("C").value)
Next I
Dim Cost2 as double = GetMinValue(AryCost2)
Return Cost1 + Cost2
End function
Public Function GetCost2(byval rsX as adodb.recordset,ByVal I as int16,ByVal A as int16,ByVal B as int16) as double
Value=DoSomeCalculate(I,A,B)
rsX.Filter="Value=" & Value) <----this step takes even longer than a new query, I want to ask if there
Do while Not rsX.EOF
if FindSuitableOne(rsX.fields.item("X").value) then
Return rsX.fields.item("X").value
End if
rsX.movenext()
Loop
return -1
end function
But I found that the Filter method cost longer than a new query. Is there any better method that I can loop through a table with specify value key?
Thank you very much.
You could do a single joined query, like this:
Public Sub DoSomething(Byval ClassGroup as int16)
Dim rsStudent as adodb.recordset()
rsStudent=cn.execute("SELECT tblStudent.StudentID FROM tblStudent INNER JOIN tblClass ON tblStudent.ClassID = tblClass.ClassID WHERE tblClass.ClassGroup = " & ClassGroup)
Do While Not rsStudent.EOF
DoSomethingOnStudent(rsStudent.fields.item("StudentID").value)
rsStudent.movenext
Loop
End Sub
This way, querying the DB only once, your execution should be faster. Also avoid using * in select clause, if possible, and only retrieve the columns you need (I see you only use StudentID column from the table).

Update table from table with general data

In my MySQL database (5.X) I have a table where info about all other tables is stored (next id etc).
Is it possible to update this table like this?
In my table "tables" there is a field "tableName" and "nextId". I want to do something like:
UPDATE tables SET nextId = (SELECT MAX(id) FROM tables.tableName);
EDIT:
I know now that it is not possible to dynamically determine the table name.
However, can I do it for each row? I can easily let all queries generate automatically.
Something like this then:
UPDATE tables SET nextId = (SELECT MAX(id) FROM tableX);
I will let this query generate for each row in my tables table.
I was able to let the queries generate for each row instead of in one huge query with some simple VBA in Excel:
Sub generate()
For i = 1 To 107
Cells(i, 3) = "update tables set nextId = (select max(id) from " & Cells(i, 2) & ") + 1 where soort = '" & Cells(i, 2) & "';"
Next i
End Sub
This resulted in 107 queries like this one:
update tables set nextId = (select max(id) from table_name) + 1 where tableName = 'table_name';

Add new entries into sql from ms access front end

I have two tables which can be represented by this query (I have made this query the Recordsource of the form):
SELECT tblrcmtask.id, tblrcmtask.rcmtask,tblrcmtaskoptions.id,
tblrcmtaskoptions.rcm_id,
tblrcmtaskoptions.rcmtaskoptions
FROM tblrcmtask
INNER JOIN tblrcmtaskoptions
ON tblrcmtask.id=tblrcmtaskoptions.rcm_id
I want the user to be able to add new entries into these table via a form in access 2007.
Columns tblrcmtask.id and tblrcmtaskoptions.id are the primary keys of the tables tblrcmtask and tblrcmtaskoptions respectively.
I do not understand how do I create new ID in both the tables while the user adds new entries.The user can add only tblrcmtaskoptions.rcmtaskoptions and tblrcmtask.rcmtask in the form.Also, there are multiple rows in the table tblrcmtaskoptions for each tblrcmtask.id.
I want the user to be able to add new rows in the table tblrcmtaskoptions for an existing tblrcmtask.id
I tried using dropdowns for these two but I am facing problem while creating the new ID as Maximum of the ID + 1.
Dim MyRecords As DAO.Recordset
Dim Myfield As DAO.Fields
SQL = "SELECT Max(tblRCMTASK.ID) AS MaxOf_RCMTASKID FROM tblRCMTASK;"
Set MyRecords = dbTHIS.OpenRecordset(SQL)
Set Myfield = MyRecords.Fields
Me.txtRCMTASKID = Myfield("MaxOf_RCMTASKID") + 1
Me.txtRCMTASKID.DefaultValue = Myfield("MaxOf_RCMTASKID") + 1
MyRecords.Close
End If
Dim MyRecords1 As DAO.Recordset
Dim Myfield1 As DAO.Fields
SQL = "SELECT Max(tblRCMTASKOPTIONS.ID) AS MaxOf_RCMOPTIONSID FROM tblRCMTASK;"
Set MyRecords = dbTHIS.OpenRecordset(SQL)
Set Myfield1 = MyRecords1.Fields
Me.txtRCMOPTIONSID = Myfield1("MaxOf_RCMOPTIONSID") + 1
Me.txtRCMOPTIONSID.DefaultValue = Myfield("MaxOf_RCMOPTIONSID") + 1
MyRecords1.Close
I am getting an error which says you can't asign a value to this object and points to this line: Me.txtRCMTASKID = Myfield("MaxOf_RCMTASKID") + 1
How do I do this?
Access gives you trouble when trying to do operations on an autonumber field. If you would like to do these kinds of operations, you may be better off just using a regular number as a PK.
To get a recently inserted autonumber field to insert the same number in a related table, this is the VBA:
assuming recordset and database are declared, rs and db
dim id as integer
set db = CurrentDb
set rs = db.openrecordset("firstTable", dbOpenDynaSet)
With rs
.addNew
.Fields("field1").Value = Me.control1 'adds to column1 of your table the value of control1
.Fields("field2").Value = Me.control2
.update 'updates the record. If it is an autonumber, it will be automatically assigned. I will show you how to access this for your next insert
end with
'To get the autoID of the entry we just inserted, do this
id = db.OpenRecordSet("SELECT##IDENTITY")(0)
'Now you have the autoID of the recent insertion, so you may use it for your next one.
This is a classic form/subform set up. Create a form based solely on tblrcmtask with a subform tblrcmtaskoptions. The link child and master fields should be set to the common id. The wizards will do this for you. There is no code required. The id will be automatically added by the link fields.
You can see an example for in the 2007 version of the Northwind sample database.