How to return random records in a table based on query results? - sql

I have a table named Values with thousands of records (sample is a lot less). The data itself is unique except that some records share the same ID.
So I need a query to return random records depending on the total count of TestQ1. For example, the query has a total of 9 records for ID 120 so there should be 3 random records each time this query is run because that's what the Test table indicates (this table changes the "Test" numbers weekly).
Pictured:
The "Values" table is the raw data.
The "TestQ1" query has a total count for that specific "ID"
and to the right, is the number of records that should be returned.
This is as far as I've been able to get:
SELECT TOP 5 Values.ID, Values.Test, Values.State, Rnd([Values]![ID]) AS [Random No], * FROM [Values] ORDER BY Rnd([Values]![ID]);

TOP N cannot be dynamic in a query object.
Can calculate a group sequence ID and use that in criteria to return a number of records for each ID group. That requires a unique identifier field which can be provided with an autonumber. Set it as random so the selection can be different as records are added to dataset.
Consider SQL:
SELECT Values.PKID, Values.ID, Values.Test, Values.State, DCount("*","Values","ID=" & [Values].[ID] & " AND PKID<" & [PKID])+1 AS GrpSeq
FROM TestQ2 INNER JOIN [Values] ON TestQ2.ID = Values.ID
WHERE (((DCount("*","Values","ID=" & [Values].[ID] & " AND PKID<" & [PKID])+1)<=[TestQ2].[Test]));
However, if you truly need to return randomized set of records with each query run, I expect VBA will be needed. Either to populate a field in Values table with a randomized sequence number for each ID group or to populate a temp table with randomized dataset. Consider VBA to populate field:
Sub RandomSeq()
Dim rs1 As DAO.Recordset, rs2 As DAO.Recordset, x As Integer
Set rs1 = CurrentDb.OpenRecordset("SELECT DISTINCT ID FROM [Values]")
Do While Not rs1.EOF
Set rs2 = CurrentDb.OpenRecordset("SELECT * FROM [Values] WHERE ID=" & rs1!ID & " ORDER BY Rnd([ID]);")
Do While Not rs2.EOF
rs2.Edit
x = x + 1
rs2!GrpSeq = x
rs2.Update
rs2.MoveNext
Loop
rs2.Close
x = 0
rs1.MoveNext
Loop
End Sub
Now run query:
SELECT Values.ID, Values.Test, Values.State, Values.GrpSeq
FROM TestQ2 INNER JOIN [Values] ON TestQ2.ID = Values.ID
WHERE (((Values.GrpSeq)<=[TestQ2].[Test]));
Be aware this will not be practical in a split database with multiple simultaneous users. Then a temp table (located in frontend) approach may be needed.

Related

SQL query to display rows of 2 different tables

I'm trying to figure out how to pull all rows from two different tables with the OutageID = X. The purpose of this is to view the current outage and all the revisions in one statement to see all of the changes. Below is an example I was trying. However, it puts it all in one row. I want it to display all rows separately like you would if you were to query SELECT * From Table WHERE X = Y.
The Current Outages are in one table and the history is in another so they are not written over and not to change the design of the current DB.
Outages Table
`strSQL = "SELECT Outages.OutageID, Outages.Outage, Outages.Building,
Outages.OutageType, Outages.OutageStart, Outages.OutageStartTime,
Outages.OutageEnd, Outages.OutageEndTime, Outages.Duration,
Outages.Reason, Outages.Areas, Outages.Comment, Outages.ORN,
Outages.Contact, Outages.Phone, Outages.Job, Outages.Timestamp
FROM Outages
WHERE (((Outages.OutageID)=3305));"`
Outage History Table
`strSQL = "SELECT OutageHistory.RevisonID, OutageHistory.OutageID,
OutageHistory.Outage, OutageHistory.Building,
OutageHistory.OutageType,
OutageHistory.OutageStart, OutageHistory.OutageStartTime,
OutageHistory.OutageEnd, OutageHistory.OutageEndTime,
OutageHistory.Duration, OutageHistory.Reason, OutageHistory.Areas,
OutageHistory.Comment, OutageHistory.ORN, OutageHistory.Contact,
OutageHistory.Phone, OutageHistory.Job, OutageHistory.Timestamp
FROM OutageHistory
WHERE (((OutageHistory.OutageID)=3305));"`
`Private Sub All_Revision_Histoy_Click()
Dim strSQL As String
strSQL = "SELECT * From OutageHistory WHERE OutageHistory.OutageID = " &
Me.OutageID & ";"
Debug.Print strSQL
ShowDataSheet strSQL`
I think that I might need to create a temp table and insert both rows for the results and then Delete the table when its closed. However, I am not sure how to do that. I already feel I may of bitten off more than I can chew with this one. Thank you in advance.
select * from (
select 1 as revisionID, Outages.* FROM Outages
WHERE (((Outages.OutageID)=3305))
union
select OutageHistory.* FROM OutageHistory
WHERE (((OutageHistory.OutageID)=3305))
) order by revisionID desc

Update access table (which are available in different backend) with values from another table using VBA

I need help in VBA code for access.
I have two tables of the same name and same number of fields located in two different backends. Two of the fields of the table indicates when was that particular record set has been Created and Modified (Date and Time). I need to compare all the record sets present in the Tables based on the fields Created and Modified and include the latest record set values in the current databank. If the record set has the same Created field values then it should check the Modified field values. The latest values present in the modified fields should be updated in the final table. Final table is what I am trying to reproduce. Table_1 from xxx_BE.accdb should resemble Final table after update. Table sample is shown below:
Table_1 from xxx_BE.accdb
Article Price Status Created Modified
A 500 Bad 10.07.2019 10:30 14.02.2020 15:45
B 6000 Good 21.05.2019 15:45
C 1500 Good 24.03.2018 08:30 25.03.2019 08:30
Table_1 from yyy_BE.accdb
Article Price Status Created Modified
A 5000 Bad 10.07.2019 10:30 19.05.2020 16:45
B 6000 Good 21.01.2019 15:45
C 9000 Bad 24.03.2018 08:30
D 14000 Bad 30.06.2018 08:30
Final Table
Article Price Status Created Modified
A 5000 Bad 10.07.2019 10:30 19.05.2020 16:45
B 6000 Good 21.01.2019 15:45
C 1500 Good 24.03.2018 08:30 25.03.2019 08:30
D 14000 Bad 30.06.2018 08:30
Please note:
Table_1 is present in xxx_BE.accdb and Table_2 is present in yyy_BE.accdb. I want the final table to appear in xxx_BE.accdb.
Assuming that you have the two source tables available in the front-end, then you can create a copy of one of them in the correct back-end. You can then use some VBA to use aUNION query as the basis for a recordset to get a list of all of the distinct Articles from the two source tables. You would then loop this recordset, creating a second UNION-based recordset to get the corresponding data from the two tables. This latter recordset would be sorted by the two date fields. You would then write all of this data to a recordset that is based on the final table.
Something like this works on the data supplied:
Sub sMergeData()
On Error GoTo E_Handle
Dim db As DAO.Database
Dim rsSteer As DAO.Recordset
Dim rsLookup As DAO.Recordset
Dim rsFinal As DAO.Recordset
Dim strSQL As String
Set db = CurrentDb
db.Execute "DELETE * FROM tblFinal;"
Set rsFinal = db.OpenRecordset("SELECT * FROM tblFinal WHERE 1=2;")
strSQL = "SELECT Article FROM Table1 " _
& " UNION SELECT Article FROM Table2;"
Set rsSteer = db.OpenRecordset(strSQL)
If Not (rsSteer.BOF And rsSteer.EOF) Then
Do
strSQL = "SELECT Price, Status, Created, Modified FROM Table1 WHERE Article='" & rsSteer!Article & "' " _
& " UNION SELECT Price, Status, Created, Modified FROM Table2 WHERE Article='" & rsSteer!Article & "' " _
& " ORDER BY Created DESC, Modified DESC;"
Set rsLookup = db.OpenRecordset(strSQL)
With rsFinal
.AddNew
!Article = rsSteer!Article
!Price = rsLookup!Price
!Status = rsLookup!Status
!Created = rsLookup!Created
!Modified = rsLookup!Modified
.Update
End With
rsSteer.MoveNext
Loop Until rsSteer.EOF
End If
sExit:
On Error Resume Next
rsFinal.Close
rsSteer.Close
rsLookup.Close
Set rsSteer = Nothing
Set rsLookup = Nothing
Set rsFinal = Nothing
Set db = Nothing
Exit Sub
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "sMergeData", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume sExit
End Sub
Regards,
Consider a pure SQL solution with multiple steps since you can directly query other Access database tables with period qualifying references or IN reference. The other needed steps are required since correlated aggregates in Access have performance issues on union queries. All can be run from the database holding final table.
Union Query (combine data sources)
SELECT Article, Price, Status, Created, Modified
FROM [C:\Path\To\xxx_BE.accdb].Table_1
UNION ALL
SELECT Article, Price, Status, Created, Modified
FROM [C:\Path\To\yyy_BE.accdb].Table_1
Alternatively:
SELECT Article, Price, Status, Created, Modified
FROM Table_1 IN "C:\Path\To\xxx_BE.accdb"
UNION ALL
SELECT Article, Price, Status, Created, Modified
FROM Table_1 IN "C:\Path\To\yyy_BE.accdb"
Make-Table Query (create a new local table)
SELECT q.Article, q.Price, q.Status, q.Created, q.Modified
INTO myTempTable
FROM myUnionQuery q
Correlated Aggregate Subquery (add rank by descending create/modified fields)
SELECT t.Article, t.Price, t.Status, t.Created, t.Modified,
(SELECT COUNT(*) FROM myTempTable sub
WHERE sub.Article = t.Article
AND sub.Created >= t.Created
AND sub.Modified >= t.Modified) AS [rank]
FROM myTempTable t
Final Insert-Select Query (filter using rank)
INSERT INTO myFinalTable (Article, Price, Status, Created, Modified)
SELECT q.Article, q.Price, q.Status, q.Created, q.Modified
FROM myCorrelAggQuery q
WHERE q.[rank] = 1

Microsoft Acess retrieving count rows in a table

In Acess how i can select a number of rows in a table from some number count that a user specifies.
For example, this DB is prompting to a user introduces a given number, p.e: 10, and the table retrives 10 records, given a table from 100 or 10000 records
Use dynamic SQL:
Dim rs As DAO.Recordset
Dim Top As Integer
Top = 10 ' User input.
Set rs = CurrentDb.OpenRecordset("Select Top " & Str(Top) & " * From YourTable")

Multiple 'AND' conditions on same column

I'm using an Access 2007 database in ASP.Net where I need to extract data from a table if an item meets multiple 'AND' clauses.
For example:
Select * from tableA
where tableA.column1 = myvalue1
and (tableA.column2 = myvalue2
and tableA.column2 = myvalue3)
(The '(' and ')' parenthesis around the 'and' clauses are an Access requirement)
myvalue1 exists multiple times in column1 because column2 stores many different pieces of data for the column1 value.
However, I only want the results to show those column1 values which meet all of the column2 search criteria.
For example, column1 contains employee surnames, column2 contains the qualifications of the employee.
One employee in column1 may hold many qualifications in column2.
Searching with the 'OR' clause for employees who hold all the required qualifications for an assignment would produce a table with multiple rows for each employee.
What is required is a single row for each employee who holds every one of the required qualifications.
Let's say employee A has qualifications X, Y and Z. The employee's name will be in a row in column 1 each time a qualification is added to column2, so the employee's name appears in column1 3 times. Assume now employee B also has qualifications X, Y and Z but employee C has W, X and Y. If an assignment needs qualifications X,Y and Z I don't want employee C appearing in the results of a search as employee C won't hold the relevant qualifications.
When I use the above 'select' command with just one 'and' clause the search works fine, but with two 'and' clauses nothing is returned, even though I know there are items in column1 that meet both of the 'and' criteria.
What am I missing in the concatenation of the 'and' clauses?
The following solution will work, but performance will suffer. This will return 1 row per person, I can rewrite it to return both rows.
Select * from tableA
where tableA.column1 = myvalue1
and (tableA.column2 = myvalue2
and DCount("column2", "TableA", "column1 = """ & column1 & """ AND column2 = """ & myvalue3 & """" ) <> 0)
Your fundamental problem is that a select query without a group by or pivot clause only evaluates 1 row at a time. I'd probably pivot the data, concatenate it, and then evaluate it for better performance in the end. But that's more complicated, and requires more information on the table structure and what you want to do.
Based on new information, I'll submit this answer:
My gut feeling is that you can't do this in one simple query. This sounds cludgy, but I think you're going to need one query created that's a SELECT DISTINCT query, and that query will pull one record for each employee:
Select DISTINCT Column1 from tableA
Call this query something like qryEmployees
Next you're going to need to create a new table. Call it tblQualifications. It will contain 2 fields; EName and EQualifications. We're going to fill that in a minute.
Next you're going to need to loop through each record in qryEmployees and write the employee name and their qualifications into tblQualifications.
'Run through every Employee name
Do While qryEmployees.EOF = False
'Set up a temp variable, MyQual, and set it equal to Empty
MyQual = ""
'Pull all qualifications from TableA for the current Employee
Set rec = db.OpenRecordset ("Select Column1, column2 from TableA WHERE Column1 = '" & qryEmployees.Column1 & "'")
'Looping through the qualifications
Do While rec.EOF = False
'Add the qualification to the MyQual string
MyQual = MyQual & rec("Column2") & ", "
rec.MoveNext
Loop
'Now that we have all the qualifications in a string, trim off the last ", "
MyQual = left(MyQual, len(MyQual)-2)
'Open up tblQualifications and fill it with the Employee and a string of all of their qualifications
tblQualifications.AddNew
tblQualifications(0) = qryEmployees.Column1
tblQualifications(1) = MyQual
tblQualifications.Update
'Move on to the next Employee and repeat the process
qryEmployees.MoveNext
Loop
Now you have one table with Employee Name in one field, and all of his qualifications in the next. If you use the LIKE operator on this table, you should get your results.
Select * from tblQualifications
where tblQualifications.EName = myvalue1
and (tblQualifications.EQualifications LIKE myvalue2
and tblQualifications.EQualifications LIKE myvalue3)
It's not pretty, but it will work (with a little putzing with the code above, as I'm writing it off the top of my head and it's untested).
Thanks Johnny, your suggestion inspired me to write a slightly different approach to the solution.
I swapped the 'AND' to an 'OR' as others have suggested to extract any employee into a table if they have any of the qualifications.
The result is a table with every required qualification for every employee who has one of those qualifications.
I then did a count elsewhere of the number of qualifications required for the assignment and compared this to whether or not the employee had the required number of qualifications, as follows:
Dim objSearchTable As DataTable = DSSearch.Tables("Employees")
Dim i As Integer
If QualificationsCount > 0 Then
For i = 0 To objSearchTable.rows.count - 1
strEmployee = objSearchTable.Rows(i).Item("column1")
Dim foundRows As DataRow() = objSearchTable.[Select]("column1 = '" & strEmployee & "'")
Dim numberOfRecords As Integer = foundRows.count
If numberOfRecords < QualificationsCount Then
objSearchTable.Rows(i).Delete
End If
Next
End If
objSearchTable.AcceptChanges
This deletes every instance of an employee from the table if the count of qualifications is less than the number required.
The solution isn't as elegant as extracting only the correct employees from the database to begin with.
There is also an overhead on extracting every employee from the database, but the end result is a table with just one row for each employee with all the qualifications, which does what I need.

ASP Retrieving database records, and then retrieving more records from another table using the first records

bit of a weird one. I have got a table in a database that stores ID's for records in another table. I need to retrieve and somehow store the information from table1.
Information:
Product, Image ID, Quantity
So the Image ID will be the ID of the record in table2. Which I will then use to get that record. With that record I will find the save location of the image, and write the image onto the document the same number of times that is stored in the quantity value for that product.
Hope you understand how I need this to work. Here is some example data.
-Product 1-
Product -> "KR"
Image ID -> 772
Quantity -> 2
-Product 2-
Product -> "KR"
Image ID -> 774
Quantity -> 5
-Product 3-
Product -> "LR"
Image ID -> 776
Quantity -> 1
Now using the above data, get data from table2 using the Image ID as the rows Unique ID and store the save location.
This is what i'm trying at the moment, but it doesn't seem to work.
<!--#include virtual="nightclub_photography\asp\functions.asp"-->
<%
'Connect to database
set conn=Server.CreateObject("ADODB.Connection")
conn.Provider="Microsoft.ACE.OLEDB.12.0"
conn.Open Server.MapPath("/nightclub_photography/data/database/jamsnaps.mdb")
'Get the current date
today = ISODate(Request.Cookies("sdate") & " 00:00:00")
'Query the database for sales
sql = "SELECT * FROM sales WHERE DATEVALUE(saleDate) = " & today & " AND printed = 0 ORDER BY product"
Set rs = conn.Execute(sql)
Set sales = Server.CreateObject("Scripting.Dictionary")
if rs.EOF then
response.write "No sales found!"
else
do until rs.EOF
'response.write rs("product")&":"&rs("quantity")&", "
if sales.Exists(rs("product")) then
sales.Item("product") = ","&rs("jpgId")&":"&rs("quantity")
else
sales.Add rs("product"), rs("jpgId")&":"&rs("quantity")
end if
'Move to next sale
rs.MoveNext
loop
end if
rs.close
conn.close
%>
Update 1
Getting an error, simplified it a bit for now, just want to get it getting some results first.
Error:
Type mismatch in expression.
Query:
sql = "SELECT * FROM images WHERE ID IN (SELECT jpgId FROM sales WHERE printed = 0)"
So, using the jpgId from row numbered "2." will return the row with the same ID labeled "1.". It will do this for each sale row.
I am not sure I am understanding but you might try something like this
select id,* from mytable where id in (select id from mytable2 where salesdate = date and printed= 0)
update mytable2 printed = 1 where id = " & myid