Convert Access Query to VB.net SQL Statement - sql

I have a table in my Access database called Historical_Stock_Prices that is filled with various companies historical stock prices. I need to run a query that will convert the raw data (the stock prices) into quarterly growth rates and display the quarterly growth rates in a DataGridView.
I've already written the the following query in the SQL View of my Access database and it works within Access.
SELECT MinMaxYrQtrDates.YrQtr, MinMaxYrQtrDates.Ticker, MinMaxYrQtrDates.MaxDate, [Historical Prices].Close, MinMaxYrQtrDates.MinDate, [Historical Prices_1].Open, ([Historical Prices].[Close]/[Historical Prices_1].[Open]-1)*100 AS GrowthRate
FROM [Historical Prices] AS [Historical Prices_1] INNER JOIN ([Historical Prices] INNER JOIN [SELECT Year([Date]) & "-" & DatePart("q",[Date]) AS YrQtr, [Historical Prices].Ticker, Max([Historical Prices].Date) AS MaxDate, Min([Historical Prices].Date) AS MinDate
FROM [Historical Prices]
GROUP BY Year([Date]) & "-" & DatePart("q",[Date]), [Historical Prices].Ticker]. AS MinMaxYrQtrDates ON ([Historical Prices].Date = MinMaxYrQtrDates.MaxDate) AND ([Historical Prices].Ticker = MinMaxYrQtrDates.Ticker)) ON ([Historical Prices_1].Ticker = MinMaxYrQtrDates.Ticker) AND ([Historical Prices_1].Date = MinMaxYrQtrDates.MinDate);
I need to be able to call it from within my program and display the results in a DataGridView. I've tried to copy the SQL statement from Access and use it as the SQL statement in my code but it doesn't work. I don't get any errors, the DataGridView is just blank. Here is my code so far:
Imports System.IO
Imports System.Data.OleDb
Public Class Historical_Growth_Rates_Annual
Public tblName As String = "Historical_Stock_Prices"
Private Sub Historical_Growth_Rates_Annual_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If (File.Exists(Nordeen_Investing_3.databaseName)) Then
Nordeen_Investing_3.con.Open()
Dim restrictions(3) As String
restrictions(2) = tblName
Dim dbTbl As DataTable = Nordeen_Investing_3.con.GetSchema("Tables", restrictions)
If dbTbl.Rows.Count = 0 Then
MessageBox.Show("Historical Stock Prices tables does not exist in the database. Please Update")
Else
Dim da As OleDbDataAdapter = New OleDbDataAdapter("SELECT MinMaxYrQtrDates.YrQtr, MinMaxYrQtrDates.Ticker, MinMaxYrQtrDates.MaxDate, [Historical_Stock_Prices].Close1, MinMaxYrQtrDates.MinDate, [Historical_Stock_Prices_1].Open1, ([Historical_Stock_Prices].[Close1]/[Historical_Stock_Prices_1].[Open1]-1)*100 AS GrowthRate FROM [Historical_Stock_Prices] AS [Historical_Stock_Prices_1] INNER JOIN ([Historical_Stock_Prices] INNER JOIN [SELECT Year([Date1]) & " - " & DatePart('q',[Date1]) AS YrQtr, [Historical_Stock_Prices].Ticker, Max([Historical_Stock_Prices].Date) AS MaxDate, Min([Historical_Stock_Prices].Date) AS MinDate FROM [Historical_Stock_Prices] GROUP BY Year([Date1]) & " - " & DatePart('q',[Date1]), [Historical_Stock_Prices].Ticker]. AS MinMaxYrQtrDates ON ([Historical_Stock_Prices].Date = MinMaxYrQtrDates.MaxDate) AND ([Historical_Stock_Prices].Ticker = MinMaxYrQtrDates.Ticker)) ON ([Historical_Stock_Prices_1].Ticker = MinMaxYrQtrDates.Ticker) AND ([Historical_Stock_Prices_1].Date = MinMaxYrQtrDates.MinDate);", Nordeen_Investing_3.con)
'create a new dataset
Dim ds As New DataSet()
'fill the datset
da.Fill(ds)
'attach dataset to the datagrid
DataGridView1.DataSource = ds.Tables(0)
ds = Nothing
da = Nothing
Nordeen_Investing_3.con.Close()
End If
Else
MessageBox.Show("Database does not exist. Please update.")
End If
End Sub
End Class
I'm really stuck and could use some help! Thanks!

You want that VB.Net code to recreate the same SELECT statement which works in Access. However, looking at the syntax highlighting with Vim, I think you may actually be creating something else. (It may be like creating a string as the difference of 2 other strings: "string 1" - "string 2").
But whether or not I guessed correctly, use a string variable to hold your SELECT statement. Then print that string to the console or write it to a text file so that you can examine the actual statement you're giving to the db engine.
Or save the working query in Access as a named query object and use that query name from your VB.Net code --- that would absolutely guarantee using the same SQL which is confirmed to work in Access.

Related

Select value and display in a combobox if the datetimepicker value lies between two extreme dates in a table in database

I am creating an attendance management system in vb.net and using MS access as my database. I created a leave form in which the student on leave has a roll number and his details along with the from date and to date field.
What I'm trying to do is to show all the roll numbers of students in the ComboBox on leave if the DateTimePicker value is in between the to date and from date, the command that I created as MS access query is selecting the from date and to date ie., extreme dates matching with the DateTimePicker value but not showing the values if date is between the to and from date.
this is the code and query:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
con.Open()
Dim cmd1 As New OleDbCommand("Select roll_no From leaves Where semester= " + ComboBox3.SelectedItem + " and (from_date<= #" & DateTimePicker1.Value.ToShortDateString & "# and to_date >= #" & DateTimePicker1.Value.ToShortDateString & "#)", con)
Dim da1 As New OleDbDataAdapter
da1.SelectCommand = cmd1
Dim dt1 As New DataTable
dt1.Clear()
da1.Fill(dt1)
ComboBox4.DataSource = dt1
ComboBox4.DisplayMember = "roll_no"
ComboBox4.ValueMember = "roll_no"
con.Close()
End Sub
Is there any modification in query through which I can get my desired results to get all the roll no if DateTimePicker value is between dates in database?
Well, you probably do want to wrap the code in a using block - that way if you have a error, it will STILL close the connection. Also, it means you don't have to close the connection - a using block ALWAYS will (so, this costs you ONLY one extra line of code, but it more robust - will not leave stray connections open.
Next up:
While everyone warns and suggests to try and avoid string concertation for reasons of SQL injection?
Actually, the BETTER case is that string concatenation is tricky, messy, and you have to remember to use quotes to surround strings, maybe "#" for dates, and for numbers no surrounding delimiters. And one tiny missing single quote or whatever, and your sql is now wrong. So, this is a BETTER case and reason to use parameters - to allow you to write code, and write code that is easer to fix, read, maintain, and even add more parameters to without complex string concatenations.
So, I would suggest this:
Using conn As New OleDbConnection(My.Settings.AccessDB)
Dim strSQL As String =
"Select roll_no From leaves Where from_date >= #cboDate and to_date <= #cboDate " &
"AND semester = #Semester"
Using cmd = New OleDbCommand(strSQL, conn)
cmd.Parameters.Add("#cboDate", OleDbType.DBDate).Value = DateTimePicker1.Value
cmd.Parameters.Add("#Semester", OleDbType.Integer).Value = ComboBox3.SelectedValue
conn.Open()
ComboBox4.DisplayMember = "roll_no"
ComboBox4.ValueMember = "roll_no"
ComboBox4.DataSource = cmd.ExecuteReader
End Using
End Using
And note how I dumped the need for a data adaptor - don't' need it.
And note how I dumped the need for a data table - don't' need it.
However, you do OH SO VERY often need a data table. So, since we humans do things over and over without thinking - memory muscle - then I would suggest that it is ok to create and fill a data table and shove that into the "on leave".
So since we "often" will need a data table, then for the sake of learning, then you could write it this way (so we now learn how to fill a data table).
Using conn As New OleDbConnection(My.Settings.AccessDB)
Dim strSQL As String =
"Select roll_no From leaves Where from_date >= #cboDate and to_date <= #cboDate " &
"AND semester = #Semester"
Using cmd = New OleDbCommand(strSQL, conn)
cmd.Parameters.Add("#cboDate", OleDbType.DBDate).Value = DateTimePicker1.Value
cmd.Parameters.Add("#Semester", OleDbType.Integer).Value = ComboBox3.SelectedValue
conn.Open()
Dim dt1 As New DataTable
dt1.Load(cmd.ExecuteReader)
ComboBox4.DisplayMember = "roll_no"
ComboBox4.ValueMember = "roll_no"
ComboBox4.DataSource = dt1
End Using
End Using
But, either way? Note how I did not have to remember, think about, worry about, and try to figure out the delimiters. Is that a " # " we need for dates, or is that a " ' " we need around the date?
Of course this code would be placed in the timepicker value changed event.

How to Condition the two Date and time from database into label current date and time

How to compare the date from MS Access Column "Time" in Time in my label form.
heres my code
Dim sql = "Select CompanyCode From LAPostingCoCode where CompanyCode = '" + ComboBox1.text"' AND User = '" & txtuser.text & "' AND Time = '" & LblTime.text & "'"
Using Olecon As New OleDbConnection(cons)
Using command as new OleDbDCommand(sql,olecon)
Using adapter as New OleDbDataAdapter(command)
Dim Table As New DataTable()
adapter.Fill(table)
If (table.Rows.Count > 0 ) Then
btnSave.Enabled = false
Else
btnSave.Enabled = true
End If
End Using
End Using
End using
I want to compare the date and time from database Column into my Form Label Current Date and Time. So that if the date and time in the database is 02-02-18 4:42:01, and in my label is 02-02-18 05:02:31. the button save will be enabled = true because the time is almost 5pm. when 4:42:01 is equal into time label. the save button still enabled = false.
I am using vb.net and MS access. help me please. thanks
The code will let you compare two dates , please modify the code as required :
'Assuming your date is formatted as : dd/mm/yyyy
Dim date1 = DateTime.Parse("02/05/2018")
Dim date2 = DateTime.Parse("03/07/2018")
If date1.Date >date2.Date Then
End if
Now for example , for example , you want to compare dateTime column of your table with your label's date(i mean .text),do this "
Dim dt1 = DateTime.Parse(yourDataTable(0)(3)) 'Here 0 is the row count and 3 is the column count
'Follow the first code block's code now :)
Suggestion: Please don't use direct values in your Select statement as it opens doors to Sql-Injection.
Read more about SQL-Injection
Rather,pass parameters and use your SqlCommand to pass values :
Dim cmd as new SqlCommand("Select CompanyCode From LAPostingCoCode where CompanyCode = #code",connection)
cmd.Parameters.Add("#code",SqlDbType.VarChar).Value = ComboBox1.text
And please use Parameter.Add method , most people use AddWithValue which not the proper way.Because at points, it may not cause errors/may not conflict with data but in most cases it'll corrupt the data.The reason is that , it infers the database type to query parameter.
Read more here
Hope this helps :)

Why is the value extracted from database not showing what is intended?

I have the following SQL Statement:
SELECT StockChild.ProductId, Sum(StockChild.Qty) AS SumOfQty,
PRODUCTDETAILS.Title, Sum(SALESORDERchild.Stockout) AS SumOfStockout
FROM (PRODUCTDETAILS
INNER JOIN SALESORDERchild
ON PRODUCTDETAILS.productID = SALESORDERchild.ProductId)
INNER JOIN StockChild
ON PRODUCTDETAILS.productID = StockChild.ProductID
WHERE (((StockChild.ProductID)=[Forms]![StockChild]![ProductId])
AND ((SALESORDERchild.ProductID)=[Forms]![StockChild]![ProductId]))
GROUP BY StockChild.ProductId, PRODUCTDETAILS.Title;
I'm trying to get the summation of values from 2 different tables using the above SQL Statement in access:
1) Sum of StockChild quantity based on productID
2) Sum of Salesorderchild Stockout based on productID
If i query it separately, i managed to get the values that i needed but i'm unable to put it into a single form.
but when i query it together as above, the values jump all over the place and i can't seem to understand why.
And if i add another record in the salesorderchild, of the already existing isbn, all the values will jump as well.
is there something that i am doing wrongly? or how should i go about to tackle this matter.
I added some explanations in the image attached.
Update:
I was trying another method whereby i just did a normal query for the initial stock to be displayed(which worked fine getting the numbers i need)
and over in the Total stockout i was trying out a
=DSum("[stockout]","[SALESORDERchild]","[ProductId]=" & [Forms]!
[StockChild]![ProductId])
but it was returning me a #Name? did i use this correctly?, should i do a vba code instead or is there a way to do it this way?
i tried the following vba code function as an alternative to select out the value but it was telling me the user-defined type not defined. am i missing out something? - (fixed this part by defining the reference of active x data object)
Private Sub Form_Current()
Dim intI As Integer
Dim fld As Field
Dim rst As ADODB.Recordset
Dim pid As String
pid = ProductID.Value
Set rst = New ADODB.Recordset
rst.Open "SELECT Sum(SALESORDERchild.Stockout) AS SumOfStockout FROM
SALESORDERchild WHERE SALESORDERchild.ProductID ='" & pid & "';",
CurrentProject.Connection, adOpenKeyset, adLockOptimistic
tb_stockout.Value = rst.Fields("SumOfStockout")
End Sub
Done Thanks everyone :)

Datagridview - Oracle Update error "Dynamic SQL generation failed."

I'm using Datagridview to show me joined records from 2 tables. Data that is showing is from one of the tables + data that are in joined table (Table3). SQL query returns results in Datagridview (works fine in Oracle too), but update fails with "Dynamic SQL generation failed. Either no base tables were found or more than one base table was found". Here is my table design:
Table1:
ID_TABLE1
ITEM_NAME
ITEM_DESCRIPTION
Table3: (this is a joined view for Table1 and Table2)
ID_TABLE3
ID_TABLE1_FK
ID_TABLE3_FK
VALIDITY
DATE_CONNECTION
My code (exactly as Oracle recommends):
Public Class Form2
Private da As OracleDataAdapter
Private cb As OracleCommandBuilder
Private ds As DataSet
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Saving.Enabled = False 'this deals with error with updating (from Oracle site)
Dim SQL As String = "SELECT ID_TABLE1, ID_TABLE3, SERIAL_NO, ITEM_NAME, ITEM_DESCRIPTION, VALIDITY, DATE_CONNECTION from TABLE1, TABLE2 WHERE TABLE3.ID_TABLE1_FK=" & Form1.DataGridView1.CurrentRow.Cells(0).Value.ToString
Try
Oracleconn() 'connection to my DB
Dim cmd = New OracleCommand(SQL, Oracleconn)
cmd.CommandType = CommandType.Text
da = New OracleDataAdapter(cmd)
cb = New OracleCommandBuilder(da)
ds = New DataSet()
da.Fill(ds)
My_DGV.DataSource = ds.Tables(0)
Saving.Enabled = True
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
'No closing of connection here because of working with Dataset (Oracle suggestion)
End Try
End Sub
Private Sub Saving
da.Update(ds.Tables(0))
Saving.Enabled = True
End Sub
End Class
So, Is my SQL query wrong or what ? Any help would be much appreciated !
P.S.: In actual case only column "VALIDITY" from Table3 will be allowed to change for users, so I need to update only that field.
This is too complicated for me, looks like Oracle-provided suggestion for working with Datasets just isn't easy when you want to perform Update on join table records. So I tried a different approach and It worked for me. Since what I need is to update only 1 column from SQL query which returns to Datagridview I did this :
For Each row As DataGridViewRow In My_.Rows
cmd.Parameters.Add(New OracleParameter("validity", row.Cells(6).Value))
cmd.CommandText = "UPDATE TABLE3 SET VALIDITY= : validity WHERE ID_TABLE1_FK='" & row.Cells(1).Value & "'"
cmd.ExecuteNonQuery()
cmd.Parameters.Clear()
Next
If anyone knows the answer to my original question - so how to do same with just da.Update(ds.Tables(0)), then please let me know. I reckon that SQL query needs to be properly changed, using JOIN method.

Datagrid Duplication due to Select Statement VB

I am using an Access database, I believe the problem lies in my SQL statement. I have a relational database, with two tables -
StaffDetails [columns(
StaffID,
FirstName,
LastName)]
and
StaffTraining [columns(
StaffID,
Month)].
I have a combobox (cbMonth) and dependent on what month is chosen if the user selects 'January' then I would like the datagrid (DGTraining) to show the First Name and Last Name of the members of staff whose ID are within the chosen month. Sorry if this is not the clearest explanation, hopefully my code below makes my issue clearer:
Dim SqlQuery As String = "SELECT [StaffDetails.StaffID], [StaffDetails.FirstName], [StaffDetails.LastName], [StaffTraining.StaffID] FROM [StaffDetails], [StaffTraining] WHERE StaffTraining.TrainingMonth='" & cbMonth.Text & "'"
Dim da As OleDbDataAdapter = New OleDbDataAdapter(SqlQuery, conn)
Dim ds As DataSet = New DataSet
da.Fill(ds, "Training")
Dim dt As DataTable = ds.Tables("Training")
With DGTraining
.AutoGenerateColumns = True
.DataSource = ds
.DataMember = "Training"
End With
You are missing your join and are getting a cross join. 2 ways of addressing:
FROM [StaffDetails] inner join [StaffTraining] on [StaffDetails].staffID = [StaffTraining].staffID
That is the join logic thats more common and easier to read. You could add to your where clause (old method, harder to read and not as commonly accepted:
...where [StaffDetails].staffID = [StaffTraining].staffID and ...
Your last comment needs amending like this...
Dim SqlQuery As String = "SELECT [StaffDetails.StaffID], [StaffDetails.FirstName],
[StaffDetails.LastName], FROM [StaffDetails]
INNER JOIN [StaffTraining] ON [StaffDetails].StaffID = [StaffTraining].StaffID
WHERE [StaffTraining].TrainingMonth='" & cbMonth.Text & "'"
Also... dependant on how you have set up cbMonth you may want cbMonth.SelectedValue or cbMonth.SelectedText