Distinct values with MAX and MIN from Access Database in VB NET - sql

I am trying to help HR by arranging the time attendance data from biometric readers in a more readable way. The output from the readers are summarized in a Access database. The output looks like the image bellow:
Each employee can have 1 IN and 1 EXIT daily (f_ReaderName column ). Some of them swipe the card multiple times and multiple INs or EXITs are recorded. How can I query the database or arrange this programmatically to have, per each Data column value, a single record for each f_CardNO and 2 columns: a MAX of Ora where f_ReaderName = 1-1[In] and a MIN of Ora where f_ReaderName = 1-1[Exit]?
Is it any way I can achieve this? A hint will be more than useful. Thanks a bunch!
LE: Manage to get to this query, but cannot be parsed, what am I doing wrong in the syntax:
SELECT
CR.f_CardNO,
Format(CR.f_ReadDate, 'Short Date') AS Data,
CR.f_ConsumerName,
CR.f_GroupName,
CR.f_ReaderName,
(
SELECT
ISNULL(MAX(FORMAT(CR.f_ReadDate, 'Long Time')), 0) AS Expr1
FROM
v_d_CardRecord CR1
WHERE
(
CR.f_ReadDate = CR1.f_ReadDate
AND CR.CardNO = CR1.CardNO
AND CR1.F_ReaderName = # 1 - 1[In] #
)
)
As OraIntrare,
(
SELECT
ISNULL(MIN(FORMAT(CR.f_ReadDate, 'Long Time')), 0) AS Expr1
FROM
v_d_CardRecord CR1
WHERE
(
CR.f_ReadDate = CR1.f_ReadDate
AND CR.CardNO = CR1.CardNO
AND CR1.F_ReaderName = # 1 - 1[Exit] #
)
)
As OraIesire
FROM
v_d_CardRecord CR
WHERE
(
CR.f_ReadDate > # 12 / 1 / 2016 #
)
ORDER BY
CR.f_ConsumerName,
Format(CR.f_ReadDate, 'Short Date')
GROUP BY
CR.f_CardNO,
Data,
CR.f_ConsumerName,
CR.f_GroupName,
CR.f_ReaderName,
OraIntrare,
OraIesire

This is my code in Visual Basic in Distinct Database. Correct me if i'm wrong.
You can put this on form load. I think this is for combobox only. (not sure) but it works in my combobox it distinct my database.
Dim da As New OleDbDataAdapter("select distinct [FULL NAME] from
EmpInfo", con1)
Dim table As New DataTable()
da.Fill(table)
ComboBox1.DataSource = New BindingSource(table, Nothing)
ComboBox1.DisplayMember = "FULL NAME"

Related

Using a mutiple table query to display data on an editable continuous form in MS Access

I need to use a fairly complex multiple table query as the data-source for a continuous form, but have the form remain editable. All of the form fields that I need to edit are only linked to a single table but I still need to display information from the multi-table query in a few of the fields in a non-editable fashion. I have accomplished this using DLookUp in the Record source query for the "display only" fields, but the performance is abysmal since the database is split and the backed resides on a server with linked tables. If I accomplish the same thing simply by using SELECT for the query fields I need to display the performance is fine, but the entire form becomes un-editable.
Any ideas on how to accomplish this more efficiently would be greatly appreciated. I've linked pictures of the the form, the form design page, the query design pages, and I've pasted the relevant SQL below.
Form Example
Form Design Example
ITNQuery SQL: ITNQuery
SELECT itn.id,
itn.itnnumber,
itn.portfolio,
itn.topic,
itn.itndate,
itn.statusid,
itn.notes,
itn.delivereddate,
itn.leadlinguistid,
itn.teamid AS Expr1,
itn.newversionentry,
itn.previousitn,
itn.reviewinglinguistid,
itn.itnresponse,
itn.leadresponsecoordinatorid,
itn.datesenttoleadcoordinator,
itn.responsedeadline,
itn.priority,
itn.casemanagerid,
itn.responsecoordinator2id,
itn.datesenttocoordinator2,
itn.responsecoordinator3id,
itn.datesenttocoordinator3,
itn.responsecoordinator4id,
itn.datesenttocoordinator4,
itn.coordinatinglinguistid,
Iif([itn].[statusid] <> 9
AND [itn].[statusid] <> 10
AND [itn].[statusid] <> 19
AND [itn].[statusid] <> 20
AND [itn].[statusid] <> 28
AND [itn].[statusid] <> 30, Iif([itn].[delivereddate] > 0,
Datediff("d", [itn].[itndate], [itn].[delivereddate]),
Datediff("d", [itn].[itndate], Now()))) AS ITNAge,
itn.newversionentry,
itn.teamid,
statuslist.[display order],
itn.cooraspondanceid,
itn.documenttypeid,
Dlookup("ducumentabreviation", "associateditntextquery",
"currentitnid =" & [itn].[id]) AS AssocAbrev,
Dlookup("itnnumber", "associateditntextquery",
"currentitnid =" & [itn].[id])
AS AssocNumber
AssociatedITNTextQuery: AssociatedITNTextQuery
SELECT associateditns.current_itn_id AS CurrentITNID,
associateditns.associated_itn_id,
associateddocstextquery1.maxofitndate,
documenttypes.ducumentabreviation,
itn.itnnumber,
itn.itndate
FROM (itn
INNER JOIN documenttypes
ON itn.documenttypeid = documenttypes.id)
INNER JOIN (associateditns
INNER JOIN associateddocstextquery1
ON associateditns.current_itn_id =
associateddocstextquery1.current_itn_id)
ON itn.id = associateditns.associated_itn_id
WHERE ( ( ( itn.itndate ) IN ( associateddocstextquery1 ! maxofitndate ) )
AND
( ( associateddocstextquery1.current_itn_id ) =
associateditns ! current_itn_id ) );
AssociatedITNTextQuery1: AssociatedITNTextQuery1
SELECT associateditns.current_itn_id,
Max(ITN_1.itndate) AS MaxOfITNDate
FROM itn AS ITN_1
INNER JOIN associateditns
ON ITN_1.id = associateditns.associated_itn_id
GROUP BY associateditns.current_itn_id;

Query for getting value from another record in same table and filter by difference greater than a gap threshold

I have data imported into a temporary table in MSAccess which looks like this:
to which I have added the "Gap" and "Previous/Current" columns that I need to calculate using an SQL Query. The "Gap Threshold" is User input or PARAMETER supplied to Query and for e.g. is 300. The GlobalID groups ItemID's whereas each ItemID is unique number.
What i want to do is calculate the GAP
(GAP = TEMPORARY_1![VERSION DATE] - TEMPORARY![VERSION DATE])
between ItemID's of similar GlobalID's and identify the items having GAP > GAP THRESHOLD value. Based on this GAP, for each GlobalID-grouped ItemID's, I want to determine which is the "Previous" ItemID and which is the "Current" ItemID.
i.e. determine which is Previous Item and which is Current Item, having a GAP of more than 300 days between them.
Finally, CREATE ANOTHER TABLE that will only import these Current/Previous Pairs for each GlobalID, but display them as one record each like this:
OR Is it a better design to Create 2 separate Tables AFTER CALCULATING GAP > GAP THRESHOLD, called tblPrevious & tblCurrent from the Temporary table like this?:
I need someone to point me in the right direction to have a better normalized design and achieve this using SQL query. Note: all the tables need to be generated dynamically everytime based on new data extract that is imported.
The below query gives error on Gap column and doesn't calculate Previous/Current:
PARAMETERS Threshold Long;
SELECT TEMPORARY.GlobalID, TEMPORARY.ItemID, TEMPORARY.[Version Date], IIf([TEMPORARY]![GlobalID]=
[TEMPORARY_1]![GlobalID],Max([TEMPORARY]![Version Date])-Min([TEMPORARY_1]![Version Date])=0,"Previous") AS Previous, TEMPORARY_1.ItemID, TEMPORARY_1.[Version Date], IIf([TEMPORARY]![GlobalID]=[TEMPORARY_1]![GlobalID],Max([TEMPORARY]![Version Date])-Min([TEMPORARY_1]![Version Date])>[Threshold],"Current") AS [Current], IIf(([TEMPORARY]![Version Date]-[TEMPORARY_1]![Version Date])>[Threshold],[TEMPORARY]![Version Date]-[TEMPORARY_1]![Version Date],"") AS GAP
FROM TEMPORARY, TEMPORARY AS TEMPORARY_1
GROUP BY TEMPORARY.GlobalID, TEMPORARY.ItemID, TEMPORARY.[Version Date], TEMPORARY_1.GlobalID, TEMPORARY_1.ItemID, TEMPORARY_1.[Version Date];
Any help would be most appreciated.
Will offer one more contribution - option with VBA code to get the Current/Previous pairs. This does require saving records to table. Tested and runs in a snap.
Sub GetGap()
Dim intTH As Integer, x As Integer, strGID As String
Dim rsT1 As DAO.Recordset, rsT2 As DAO.Recordset
CurrentDb.Execute "DELETE FROM Temp"
Set rsT1 = CurrentDb.OpenRecordset("SELECT * FROM Temporary ORDER BY GlobalID, ItemID DESC;")
Set rsT2 = CurrentDb.OpenRecordset("SELECT * FROM Temp;")
strGID = rsT1!GlobalID
x = 1
While Not rsT1.EOF
If strGID = rsT1!GlobalID Then
If x = 1 Then
rsT2.AddNew
rsT2!GlobalID = strGID
rsT2!CurItemID = rsT1!ItemID
rsT2!CurDate = rsT1![Version Date]
x = 2
ElseIf x = 2 Then
rsT2!GlobalID = strGID
rsT2!PreItemID = rsT1!ItemID
rsT2!PreDate = rsT1![Version Date]
x = 3
End If
If Not rsT1.EOF Then rsT1.MoveNext
Else
If x = 3 Then rsT2.Update
strGID = rsT1!GlobalID
x = 1
End If
If rsT1.EOF Then rsT2.Update
Wend
End Sub
Then a query can easily calculate the Gap and filter records.
SELECT Temp.GlobalID, Temp.CurItemID, Temp.CurDate, Temp.PreDate, Temp.PreItemID, [CurDate]-[PreDate] AS Gap
FROM Temp
WHERE ((([CurDate]-[PreDate])>Int([Enter Threshold])));
Or the code can be expanded to also calc the Gap and save only records that meet the threshold requirement, just a bit more complicated.
Review Allen Browne Subquery.
Requirements described in narrative differ from the title. Here are suggestions for both.
Queries pulling Current/Previous pairs.
Query 1:
SELECT [GlobalID], [ItemID] AS CurItemID, [Version Date] AS CurDate, (SELECT TOP 1 [Version Date] FROM Temporary AS Dupe WHERE Dupe.GlobalID=Temporary.GlobalID AND Dupe.ItemID < Temporary.ItemID ORDER BY Dupe.GlobalID, Dupe.ItemID DESC) AS PreDate, (SELECT TOP 1 [ItemID] FROM Temporary AS Dupe WHERE Dupe.GlobalID=Temporary.GlobalID AND Dupe.ItemID < Temporary.ItemID ORDER BY Dupe.GlobalID, Dupe.ItemID DESC) AS PreItemID
FROM [Temporary];
Query 2:
SELECT Query1.GlobalID, Query1.CurItemID, Query1.CurDate, Query1.PreDate, Query1.PreItemID, DateDiff("d",[PreDate],[CurDate]) AS Gap FROM Query1 WHERE ((([GlobalID] & [CurItemID]) In (SELECT TOP 1 GlobalID & CurItemID FROM Query1 AS Dupe WHERE Dupe.GlobalID = Query1.GlobalID ORDER BY GlobalID, CurItemID DESC))) AND DateDiff("d",[PreDate],[CurDate]) > Int([Enter Threshold]);
Final output:
GlobalID CurItemID CurDate PreDate PreItemID Gap
00109086 2755630 2/26/2015 3/11/2014 2130881 352
00114899 2785590 3/13/2015 3/25/2014 2093191 353
00154635 2755623 2/26/2015 4/4/2014 2176453 328
Here is query that addresses the requirement for Minimum/Maximum as stated in your title. Not as slow as the Current/Previous queries but if dataset gets significantly larger I expect it will get very slow.
SELECT Maximum.GlobalID, Maximum.ItemID AS MaxItem, Maximum.[Version Date] AS MaxItemDate, Minimum.ItemID AS MinItem, Minimum.[Version Date] AS MinItemDate, Maximum.[Version Date]-Minimum.[Version Date] AS Gap
FROM
(SELECT T1.GlobalID, T1.ItemID, T1.[Version Date] FROM [Temporary] AS T1 WHERE (((T1.ItemID) In (SELECT Min([ItemID]) AS MinItem FROM Temporary GROUP BY GlobalID)))) AS Minimum
INNER JOIN
(SELECT T1.GlobalID, T1.ItemID, T1.[Version Date] FROM [Temporary] AS T1 WHERE (((T1.ItemID) In (SELECT Max([ItemID]) AS MaxItem FROM Temporary GROUP BY GlobalID)))) AS Maximum
ON Minimum.GlobalID = Maximum.GlobalID
WHERE Maximum.[Version Date]-Minimum.[Version Date]>Int([Enter Threshold]);
Also, your dates are in international format. If you encounter issues with that, review Allen Browne International Dates

How to get Average of records from Access Database in vb.net?

I have a project where I connected an Access Database through a DataGridView. I've made some queries based on info inputed by the user through textboxes and comboboxes. Now I need to find a way to count the Average of the records found after the query from one specific column. Is there a way to do that ?
Store the counts from your queries...
Dim lstCounts As New List(Of Integer)
'Your database retrieval method: SELECT COUNT(*) FROM table WHERE field = 'Blah'
lstCounts.Add(<above result>)
'Your database retrieval method: SELECT COUNT(*) FROM table WHERE field = 'Blah1'
lstCounts.Add(<above result>)
'Your database retrieval method: SELECT COUNT(*) FROM table WHERE field = 'Blah2'
lstCounts.Add(<above result>)
'etc.
Find the average...
Dim nTotal As Integer = 0
Dim dAverage As Decimal = 0.0
For i As Integer = 0 to lstCounts.Count - 1
nTotal += lstCounts(i)
Next
'Make sure you aren't dividing by zero
If lstCounts.Count > 0
dAverage = nTotal / lstCounts.Count
End If
You could also simply just add the total as you perform each query and not bother using a List, but then you need to track how many queries you ran.

Sort a Dataset in visualbasic

I don't know what i doing wrong. I have been on several forums trying to figure out how to sort a table in visual basic.
I have treid with and with out a dataview, but noting seams to work.
I have a logg that the user can do new inserts in. It has 3 columns. "Date", "Tool", "Comment".
When my VB application loads the program reads the table from a Access database and i get my sorting just fine by the sql phrase:
"select * from Logg ORDER BY Logg.Datum DESC"
After a user have uppdated the table i whant to sort it again. I have treid the following, but nothing happens. The order is the same whatever i do.
DS is my Dataset and dw my dataview, and "Datum" the column i whant to sort
DS.Tables("hela").DefaultView.Sort = "Datum DESC"
dw = DS.Tables("hela").DefaultView
For i = 0 To antal_poss - 1
LOGG(i, 0) = dw.Table.Rows(i).Item(3)
LOGG(i, 1) = dw.Table.Rows(i).Item(1)
LOGG(i, 2) = dw.Table.Rows(i).Item(4)
Next i
What am i doing wrong?
In your code you use the DataView to retrieve the Table and then the DataRows, but you extract them following the order on the DataTable.
You need to loop following the order of the DataView.
Something like this
Dim i As Integer = 0
For Each row As DataRowView in dw
LOGG(i, 0) = row.Item(3)
LOGG(i, 1) = row.Item(1)
LOGG(i, 2) = row.Item(4)
i += 1
Next i
Of course this assume that your LOGG array contains enough entries to accomodate every row retrieved. It is the same number of the rows in the DataTable

How to sort a column in dataset VB.NET having multiple sort conditions

I have a dataset in which there is a column contains various string type values like below:
Aircraft
Crime
Package Total
Apartments
DIC - Personnel
Now the requirement is that after applying sorting logic on this colum if there is a "Package Total" value in it then it must come at the top position on the Dataset and after that all other values should be in alphabatically sorted order like below:
Package Total
Aircraft
Apartments
Crime
DIC - Personnel
We have used in Database below logic which is working fine but can't figure it out how to do it on Dataset VB.net from Fronend side:
ORDER BY
CASE WHEN UseCarrierAllocation = 0 THEN
CASE WHEN InvoiceItemLevel LIKE 'Package Total%' THEN 0 ELSE 1
END
END, InvoiceItemLevel ASC
Any reply/idea will be helpful!
Something like this might work for you:
DataView dv = sDataSet.Tables("Table1").DefaultView;
dv.Sort = "column1";
YourDatasourceName.YourDatasetName.DefaultView.Sort = "YourColumnName"
YourDataTableName = YourDatasourceName.YourDatasetName.DefaultView.ToTable(True, "YourColumnName")