I am using vb.net.
I have a database set with following table and three columns. So user can add their event start date/time and end date/time.
Table = "Eventable"
|----|------------------------|-----------------------|
| ID | StartBy | EndBy |
|----|------------------------|-----------------------|
| 1 | 7/1/2015 2:30:00 PM | 7/1/2015 4:00:00 PM |
| 2 | 1/22/2013 8:00:00 AM | 1/22/2013 3:00:00 PM |
| 3 | 10/22/2014 10:25:00 AM | 10/22/2014 6:20:00 PM |
| 4 | 4/5/2010 5:00:00 PM | 4/5/2010 8:00:00 PM |
| 5 | 7/3/2015 12:00:00 PM | 77/2/2015 8:00:00 PM |
|----|------------------------|-----------------------|
The user will next enter a new StartBy Event from textbox(7/1/2015 3:00:00 PM):
Dim getNewStartEventDateTime As String = getNewStartEventDateTimeTB.Text
Then the user will enter a new EndBy Event from textbox(7/1/2015 7:00:00 PM):
Dim getNewEndEventDateTime As String = getNewEndEventDateTimeTB.Text
Now, how can I write a query that will test to see if the new event is not between the database timing? In other words, a test to see if the new event timing isn't taken.
This is what I have so far.
Dim query As String = "SELECT * FROM Eventable WHERE StartBy not Between #" & getNewStartEventDateTime.Text & "# AND #" & getNewEndEventDateTime.Text & ";"
If error then
// Error - This time is taken. Please enter a different time.
else
// No errors - Add a new event
end if
Try the below query:
SELECT * FROM Eventable
where EndBy < '"& getNewStartEventDateTime .Text &"'
or StartBy > '"& getNewEndEventDateTime & "'
Query using between :
SELECT * FROM Eventable WHERE StartBy not Between '" & getNewStartEventDateTime .Text & "' AND '" & getNewEndEventDateTime &"';
Try this way
Dim query As String = "SELECT * FROM Eventable WHERE StartBy not Between '" & getNewStartEventDateTime .Text & "' AND '" & getNewEndEventDateTime & "';"
Related
Description of the current situation:
I have an excel file of approximately 315 columns and 4000 rows. The file contains the answers to a 300-question questionnaire. The data format is as follows:
(Headers) A | B | C | D | E | F | Q.1 | Q.2 | ... | Q.300 |
(FirstRow) Info of first participant | AnswerCode for every Q |
The columns A to F contain contain info on every participant, while the columns Q.1 to Q.300 contain the respective answer code to each question. After storing the file as a large DataTable:
I need to load all 4000 rows on an existing database table, but before I do that I must edit the data format. The end result must become:
ParticipantCode | QuestionCode | AnswerCode | DateOfRegistration
00001 | 0001 | 1234567 | yyyy-MM-dd HH:mm:ss
... | ... | ... | ...
00001 | 0300 | 1234567 | yyyy-MM-dd HH:mm:ss
00002 | 0001 | 1234567 | yyyy-MM-dd HH:mm:ss
... | ... | ... | ...
04000 | 0300 | 1234567 | yyyy-MM-dd HH:mm:ss
So every row of the original ExcelDataTable is transformed into 300 rows in the FinalDataTable. In this way, the FinalDataTable will have about 1.2 million rows.
What Have I implemented so far:
Private Function MyFunction()
For Each ExcelRow As DataRow In ExcelDataTable.Rows
For Each ExcelColumn As DataColumn In ExcelDataTable.Columns
QuestionCodeFound = False
ExcelColumnNameRaw = ExcelColumn.ColumnName.ToString.Trim
If ExcelColumnNameRaw.StartsWith("Q") Then
' Correct the headers
ExcelColumnSplit = ExcelColumnNameRaw.Split("#")
ExcelColumnName = String.Concat(ExcelColumnSplit(0), ExcelColumnSplit(1))
SelectedRowFromDT = QuestionCodeAndQuestionIDDataTable.Select("QuestionID = '" + ExcelColumnName + "'")
' Search for "_", because some questions are different
If SelectedRowFromDT.Length > 0 Then
QuestionCodeFound = True
Else
Dim ExcelColumnSplitForMult As String()
ExcelColumnSplitForMult = ExcelColumnName.Split("_")
SelectedRowFromDT = QuestionCodeAndQuestionIDDataTable.Select("QuestionID = '" + ExcelColumnSplitForMult(0).ToString + "'")
If SelectedRowFromDT.Length > 0 Then
QuestionCodeFound = True
End If
End If
If QuestionCodeFound Then
Dim QuestionCode As String
Dim QuestionTypeDataTable As DataTable
Dim QuestionType As String
' Get the Question Type from the respective table
QuestionType = String.Empty
QuestionCode = SelectedRowFromDT(0).Item("QuestionCode").ToString
QuestionTypeDataTable = SearchInSql(My.Settings.ConnectionString, SQLString)
If QuestionTypeDataTable.Rows.Count > 0 Then
QuestionType = QuestionTypeDataTable.Rows(0).Item(0).ToString.Trim
End If
' Fix the Date Format
DateRaw = ExcelRow.Item(1).ToString
DateSplit = DateRaw.Split("/")
If DateSplit(0).Length = 1 Then
DateSplit(0) = String.Concat("0", DateSplit(0))
End If
If DateSplit(1).Length = 1 Then
DateSplit(1) = String.Concat("0", DateSplit(1))
End If
DateText = String.Concat(DateSplit(0), "/", DateSplit(1), "/", DateSplit(2))
DateRegistration = DateTime.ParseExact(DateText, "MM/dd/yyyy", CultureInfo.InvariantCulture)
DateRegistrationReformed = DateRegistration.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)
DateRegFinal = DateTime.ParseExact((DateRegistrationReformed + " " + "10:00:00").ToString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)
Dim AnswerValue As String
Dim AnswerCode As String
Dim AnswerCodeDataTable As DataTable
Dim QuestionWasAnswer As String
Dim AnswerValueRow() As DataRow = ExcelDataTable.Select("ParticipantCode = '" + ExcelRow.Item(2).ToString + "'")
AnswerCodeDataTable = New DataTable
AnswerValue = ""
QuestionWasAnswer = "0"
' Complete "QuestionWasAnswer" field for all questions and retrieve the AnswerCode for the answer given by each participant
If AnswerValueRow.Length > 0 And AnswerValueRow(0).Item(ExcelColumnNameRaw).GetType IsNot GetType(DBNull) Then
If Not (QuestionType.Equals("02") Or QuestionType.Equals("03")) Then
AnswerValue = AnswerValueRow(0).Item(ExcelColumnNameRaw)
QuestionWasAnswer = "1"
ElseIf QuestionType.Equals("02") Or QuestionType.Equals("03") Then
Dim ExcelColumnSplitForMultSecond As String()
Dim MultAnswerValue As String
ExcelColumnSplitForMultSecond = ExcelColumnName.Split("_")
MultAnswerValue = AnswerValueRow(0).Item(ExcelColumnNameRaw).ToString.Trim
AnswerValue = ExcelColumnSplitForMultSecond(1).ToString
If MultAnswerValue.Equals("1") Then
QuestionWasAnswer = "1"
ElseIf MultAnswerValue.Equals("2") Then
QuestionWasAnswer = "2"
End If
End If
' Search in the Answers table for the existing AnswerCode
SQLString = String.Format("SELECT Answers.AnswerCode
FROM Answers
WHERE Answers.QuestionCode = '{0}'
AND (Answers.AnswerNumber = '{1}' OR Answers.Answer = '{1}')", QuestionCode, AnswerValue)
AnswerCodeDataTable = SearchInSql(My.Settings.ConnectionString, SQLString)
If AnswerCodeDataTable.Rows.Count > 0 Then
AnswerCode = AnswerCodeDataTable.Rows(0).Item(0).ToString
FormattedDataTable.Rows.Add(ParticipantAnswerCode, ExcelRow.Item(2), QuestionCode, AnswerCode, QuestionWasAnswer, DateRegFinal)
ParticipantAnswerCode = Convert.ToInt32(ParticipantAnswerCode + 1).ToString.PadLeft(ParticipantAnswerCodeFieldLength, "0")
Else
' If a given answer does not exist, save it in the respective table and then try again
Dim AnswerCodeLength = GetLengthFromSqlDataBase(My.Settings.ConnectionString, "Answers", "AnswerCode")
Dim NextAnswerCode = CalculateNextAnswerCode(AnswerCodeLength)
Dim NestAnswerNumber = CalculateNextAnswerNumber(QuestionCode)
SaveNewAnswer(NextAnswerCode, QuestionCode, NestAnswerNumber, AnswerValue)
SQLString = String.Format("SELECT Answers.AnswerCode
FROM Answers
WHERE Answers.QuestionCode = '{0}'
AND Answers.Answer = '{1}'", QuestionCode, AnswerValue)
AnswerCodeDataTable = SearchInSql(My.Settings.ConnectionString, SQLString)
If AnswerCodeDataTable.Rows.Count > 0 Then
AnswerCode = AnswerCodeDataTable.Rows(0).Item(0).ToString
FormattedDataTable.Rows.Add(ParticipantAnswerCode, ExcelRow.Item(2), QuestionCode, AnswerCode, QuestionWasAnswer, DateRegFinal)
ParticipantAnswerCode = Convert.ToInt32(ParticipantAnswerCode + 1).ToString.PadLeft(ParticipantAnswerCodeFieldLength, "0")
End If
End If
End If
End If
End If
Next
Next
Return FormattedDataTable
End Function
After that, I bulk insert the FinalDataTable on the DB.
The problem I am facing:
Using the current program I built, every row in the ExcelDataTable takes about 40 seconds to transform into 300 rows in the FinalDataTable. If I try to load all 4000 rows, it will take more than 40 hours to transform the entire datatable. I need to find a faster way to do this.
As mentioned, there isn't much to go off of on this with what has been provided.
I'm sure there are more helpful fixes to consider but I wanted to put my two cents in about the For Loops.
I recommend switching the
For Each
statements with
For i as integer = 0 to ExcelDataTable.Rows.Count - 1
I've read that For Each is not as performance-friendly as it gathers each "row" as a collection, therefore increasing the overhead per loop.
Here is a SO post about this subject:
Major difference between 'for each' and 'for' loop in .NET
Not sure if that will make a difference for you but thought I would recommend it anyway.
I want to make a list look like below to insert into a table between two date range:
make_intervals_list ('2016-01-01','2020-12-31');
+----------------+--------------+--------+
| interval_start | interval_end | rate |
+----------------+--------------+--------+
| 2016-01-01 | 2016-12-31 | 95 |
| 2017-01-01 | 2017-12-31 | 105 |
| 2018-01-01 | 2018-12-31 | 115 |
| 2019-01-01 | 2019-12-31 | 125 |
| 2020-01-01 | 2020-12-31 | 135 |
+----------------+--------------+--------+
What I'm trying to get:
Dim stDate As Date
Dim nxDate As Date
Dim enDate As Date
Dim rate As Integer
stDate = "01/01/2016"
enDate = "31/12/2020"
rate = Me.initial_rate
Do While stDate < enDate
nxDate = DateAdd("yyyy", 1, stDate)
stDate = nxDate
rate = rate + 10
Debug.Print stDate, nxDate, rate
Loop
Output:
01/01/2018 01/01/2018 115
01/01/2019 01/01/2019 125
01/01/2020 01/01/2020 135
01/01/2021 01/01/2021 145
Any help would be appreciated.
You were close. You needed two extra temp dates to help you through the loop:
Dim stDate As Date
Dim nxstDate As Date
Dim nxenDate As Date
Dim nxyrDate As Date
Dim enDate As Date
Dim rate As Integer
stDate = "01/01/2016"
enDate = "31/12/2020"
rate = Me.initial_rate
nxyrDate = stDate
Do While nxyrDate < enDate
nxstDate = nxyrDate
nxyrDate = DateAdd("yyyy", 1, nxstDate)
nxenDate = DateAdd("d", -1, nxyrDate)
Debug.Print nxstDate, nxenDate, rate
rate = rate + 10
Loop
Output:
1/1/2016 12/31/2016 95
1/1/2017 12/31/2017 105
1/1/2018 12/31/2018 115
1/1/2019 12/31/2019 125
1/1/2020 12/31/2020 135
Hope that helps :)
** EDIT **
Additional code to answer request for placing results into a table:
First you need to create the table in your Access database
I called my table: tblIntervals_List
But you can call yours whatever you want, just change tblIntervals_List to your table name in the code below.
In Table tblIntervals_List you need three fields. You can name the fields whatever you want. But the first two fields must be of data type Date/Time and the third of data type Number.
Such as:
tblIntervals_List
Field Name Data Type
Interval_Start Date/Time
Interval_End Date/Time
Rate Number
Once you have created your table correctly, you can modify your code.
First You'll need to add another Dim statement for your SQL Insert Text:
Dim strSQLText As String
Then you'll need to turn off Warnings so you don't have to press the space bar after each record insert.
DoCmd.SetWarnings (WarningsOff)
Then in your loop, you need to create your SQL Insert code:
strSQLText = "INSERT INTO tblIntervals_List VALUES ('" & _
nxstDate & "', '" & _
nxenDate & "', " & _
rate & ") "
And run it with a Docmd statement:
DoCmd.RunSQL strSQLText
Then after the loop is finished, you need to reset your warnings on:
DoCmd.SetWarnings (WarningsOn)
And if you want, give your user a message box to let them know the query actually did something:
MsgBox "Records added to tblIntervals_List"
Plus, don't forget to comment out your Debug.Print
All of these steps are in the code below:
Dim stDate As Date
Dim nxstDate As Date
Dim nxenDate As Date
Dim nxyrDate As Date
Dim enDate As Date
Dim rate As Integer
Dim strSQLText As String
DoCmd.SetWarnings (WarningsOff)
stDate = "01/01/2016"
enDate = "31/12/2020"
rate = Me.initial_rate
nxyrDate = stDate
Do While nxyrDate < enDate
nxstDate = nxyrDate
nxyrDate = DateAdd("yyyy", 1, nxstDate)
nxenDate = DateAdd("d", -1, nxyrDate)
' Debug.Print nxstDate, nxenDate, rate
strSQLText = "INSERT INTO tblIntervals_List VALUES ('" & _
nxstDate & "', '" & _
nxenDate & "', " & _
rate & ") "
DoCmd.RunSQL strSQLText
rate = rate + 10
Loop
DoCmd.SetWarnings (WarningsOn)
MsgBox "Records added to tblIntervals_List"
And that code will add records to your Access table with your dates and rates.
Hope that helps :)
This is what I would do to make it easy for you to print out:
Dim stDate As Date
Dim nxDate As Date
Dim enDate As Date
Dim rate As Integer
Dim array_var As Variant
' additional variables
Dim coll_temp As Collection
Set coll_temp = New Collection
Dim array_temp(2) As Variant
' initialize initial variables
stDate = "01/01/2016"
nxDate = DateAdd("yyyy", 1, stDate)
nxDate = DateAdd("d", -1, nxDate)
enDate = "31/12/2020"
rate = 95 ' for you this would be Me.initial_rate
Do While stDate < enDate
' load array
array_temp(0) = stDate
array_temp(1) = nxDate
array_temp(2) = rate
' add to collection
coll_temp.Add Item:=array_temp
' increment dates
nxDate = DateAdd("yyyy", 1, nxDate)
stDate = DateAdd("yyyy", 1, stDate)
rate = rate + 10
Loop
To read this out this is the loop you need to do.
' print out each element in collection
For Each array_var In coll_temp
' print out each element in array
For int_element = 0 To UBound(array_temp)
' print the element
Debug.Print array_var(0); array_var(1); array_var(2)
Next int_element
Next
I hope this helps.
I got this code:
...
Dim contP as String ="0"
Dim LeftJIF as String =""
sqlquery =("select CLas1, CLas2, CLas3"+ContP+"
from CLas" + LeftJIF )
Using connection As SqlConnection = New SqlConnection("server=" & srvSQL & ";database=" & bdSQL & ";uid=" & usrSQL & ";password=" & pswSQL & ";")
connection.Open()
Using com As SqlCommand = New SqlCommand(sqlquery, connection)
Dim rs As SqlDataReader = com.ExecuteReader
Dim dt As DataTable = New DataTable
dt.Load(rs)
''Here I'm trying to do what's below.
Call clCreateCSV.CreateCSVFile(dt, strFileName)
End Using
connection.Close()
End Using
So, for each result on the query I need to fill the variable ContP with data coming from a left join. IF the field "CLas3" from each one is "472" or "477" it will assign a table field and the left join acordingly
I was thinking in something like this just following dt.Load(rs)
For Each dr As DataRow In dt.Rows
If dt.Rows(0).Item("CLas3") = "472" Then
ContP = "clients.client3"
leftJoinsif = "left join InvoiceS on CLas4 = InvoiceS.invoice4
" + "left join clients on InvoiceS.invoice5 = clients.client1"
ElseIf dt.Rows(0).Item("CLas3") = "477" Then
ContP = "providers.provider3"
leftJoinsif = "left join InvoiceV on CLas4 = InvoiceV.invoice4
" + "left join providers on InvoiceV.invoice5 = providers.provider1"
Else
contP = ""
leftJoinsif = ""
End If
Next
The tables look like this, just in case is needed.
CLas
::::::::::::::::::::::::::::::::::::::::
CLas1 | Clas2 | CLas3 | Clas4
10 R 472 I1
10 S 600 I1
10 N 129
20 S 700 I2
20 R 472 I2
...
InvoiceS
::::::::::::::::::::::::::::::::::::::::
invoice1 | invoice2 | invoice3 | invoice4 | invoice5
001 x y I1 000001
002 x y I2 000002
...
clients
::::::::::::::::::::::::::::::::::::::::
client1 | client2 | client3
000001 name V
000002 name C
...
So, after all the query should result in something like:
10,R,472,V
10,S,600,
10,N,129,
20,S,700,
20,R,472,C
All in all, it's failing, not retrieving anything. Tested the query separately on a sql server and seems to be working. I'm not sure if there is an easier way to do this or if I can operate with the dt rows on that state(Still not quite understand it yet)
Thanks in advance.
I have an issue with Access 2010.
I use transaction to encapsulate my modification in a form. This transaction is started in the Form_Load() sub.
Private Sub Form_Load()
Debug.Print "Right here"
DAO.DBEngine.Workspaces(0).BeginTrans
Debug.Print "Here too"
...
End Sub
So the transaction is started at the very first line (nothing else is running before, the Debug.Print are just here to show you the code run through the line).
When I click on the button "save" or "rollback", I run some code like this :
Private Sub BtnSauvegarder_Click()
DAO.DBEngine.Workspaces(0).CommitTrans dbForceOSFlush
DoCmd.OpenForm "F_ListeDemande", acNormal, , , acFormEdit, acWindowNormal
DoCmd.Close acForm, Me.name
End Sub
And that's here I got the error 3034, both in save or rollback code (which are similar)
BUT, the weirdest thing is here : when I entered the form, my Listbox are bugy, nothing are inside. If I entered in Design view, do nothing and then entered in the Normal view, everything run right : Listbox have the Recordset they are supposed to have and the transaction work fine.
This is not the first time I use transaction, I used the same way on other forms without any problem.
So what I am doing wrong ?
EDIT :
I made this code to output the current state of DAO.DBEngine, in case it is useful.
Public Sub DebugDBEngine()
Dim ws As Workspace
Dim db As Database
Dim p As Property
For Each ws In DAO.DBEngine.Workspaces
Debug.Print "Workspace : " & ws.name
For Each p In ws.Properties
On Error Resume Next
Debug.Print "| " & p.name & " = " & p.value
Next
For Each db In ws.Databases
Debug.Print "| Database : " & db.name
For Each p In db.Properties
On Error Resume Next
Debug.Print "| | " & p.name & " = " & p.value
Next
Next
Next
End Sub
So I use it just after the beginning of the transaction and the output is this :
Workspace : #Default Workspace#
| Name = #Default Workspace#
| UserName = admin
| IsolateODBCTrans = 0
| Type = 2
| Database : H:\Projet\05\15\10h28 - Suivi commande et fournisseur.accdb
| | Name = H:\Projet\05\15\10h28 - Suivi commande et fournisseur.accdb
| | Connect =
| | Transactions = True
| | Updatable = True
| | CollatingOrder = 1036
| | QueryTimeout = 60
| | Version = 14.0
| | RecordsAffected = 0
| | ReplicaID =
| | DesignMasterID =
| | ANSI Query Mode = 0
| | Themed Form Controls = 1
| | AccessVersion = 09.50
| | NavPane Category = 0
| | UseMDIMode = 0
| | ShowDocumentTabs = True
| | Build = 24
| | HasOfflineLists = 70
| | Picture Property Storage Format = 0
| | CheckTruncatedNumFields = 1
| | ProjVer = 119
| | NavPane Closed = 0
| | NavPane Width = 226
| | NavPane View By = 0
| | NavPane Sort By = 1
| | Show Navigation Pane Search Bar = 0
| | WebDesignMode = 0
| | Theme Resource Name = Thème Office
| | Property Sheet Label Width = 2820
| | StartUpShowDBWindow = True
| | StartUpShowStatusBar = True
| | AllowShortcutMenus = True
| | AllowFullMenus = True
| | AllowBuiltInToolbars = True
| | AllowToolbarChanges = True
| | AllowSpecialKeys = True
| | UseAppIconForFrmRpt = False
| | AllowDatasheetSchema = True
| | DesignWithData = True
| | Show Values Limit = 1000
| | Show Values in Indexed = 1
| | Show Values in Non-Indexed = 1
| | Show Values in Remote = 0
| | Auto Compact = 0
| | Track Name AutoCorrect Info = 0
| Database : H:\Projet\05\15\10h28 - Suivi commande et fournisseur.accdb
| |(same things as above, it is the same database)
So, the same DB is open twice. I verify : where the transactions are correctly runing, only one DB is open.
EDIT2 :
I tested again with this debug to enter in normal view, then design and then normal. The first time, I've got the output just above. The second time, it is the same without the second same database, there is juste one DB.
So now, I'm sure the problem is they are two databases opened. All I have to find is WHY it open twice the same DB.
With hard searching, I probably found the problem.
In Design view, I set to Listboxes some query to fill them. It use one database to do it.
In my VBA code, I use Recordset to fill the Listboxes. And they use another database, even if it is the same.
So my solution is simple : I don't define the rowsource in Design view, so only the VBA will fill the Listboxes.
I am working with a table similar to the following one:
PBName InputDate Amount
Michael Brown 07-jan-13 1391000,000 €
Mary Aspas 07-jan-13 -400000,000 €
Thomas Dand 15-feb-13 3000000,000 €
Mary Aspas 31-jul-13 3000000,000 €
Then, I am just trying to get the total amount by PBName when InputDate is previous to a given one:
Dim dd As Date
dd = 15-feb-13
This is the code I am using:
strSQL = "SELECT Rea.PBName, SUM(CASE WHEN Rea.InputDate < dd THEN Rea.AMOUNT / 1000000 ELSE 0 END) As NNARea "
When I try to run the query I get the message "invalid column name".
Could you please help me?
Thanks
This should work for you...
strSQL = "SELECT PBName, SUM(Amount)/1000000 AS NNARea " & _
"FROM Rea " & _
"WHERE InputDate < #" & dd & "# " & _
"GROUP BY PBName;"