How to select MONTH() and YEAR() using SELECT query - sql

Basically, I want to run a query to pull data entered into a VB form (specifically MONTH and YEAR).
This is what I currently have:
SELECT * FROM orders WHERE MONTH(date_ordered) = ? AND YEAR(date_ordered) = ? ;
When I run this in my database, it doesn't work. I get no results.
However, if I put it like this:
SELECT * FROM orders WHERE MONTH(date_ordered) = 08 AND YEAR(date_ordered) = 1989;
It works fine and pulls the expected results. Obviously, as I am using a form where the user is supposed to input the 'month' and 'year' themselves, this makes things a bit tricky.
What am I missing here? Cheers for any thoughts.
Note: the date_ordered field is a Date/Time field with a Short Date format.

This may help you..
Dim sql As String = "SELECT * FROM orders WHERE MONTH(date_ordered) = #mon and YEAR(date_ordered) = #year"
Using cn As New SqlConnection("Your connection string here"), _
cmd As New SqlCommand(sql, cn)
cmd.Parameters.Add("#mon", SqlDbType.VarChar, 50).Value = textBox1.text
cmd.Parameters.Add("#year", SqlDbType.VarChar, 50).Value = textBox2.text
Return cmd.ExecuteScalar().ToString()
End Using

Related

VB.NET - Best practice for handling complex SQL queries with optional parameters

In my application, the user should have the option to browse for orders that have been placed by customers - and it should be possible to apply several filters to the search. That means that I need a dynamic SQL query where a variable amount of parameters can be applied.
In a standard WinForms application, what would be the best way to handle this?
So far I've been working with TableAdapters and stored procedures but as far as I know, I can not use these with optional parameters. So for example if a user wants to see all customer orders, this is no problem. But it should also be possible to say for example "Show all orders that have been placed in the last 2 weeks and where at least one product contains the word 'gift code'". So date and product-name would be optional parameters but if I leave those empty in a stored procedure, I get an error.
To fix this, I started building my own queries in a separate class using SqlCommands and parameters. I dynamically generate the commandText for each command depending on the parameters passed into the function, then I add parameters to the SqlCommand, execute it and loop through the SqlDataReader to build a list of items that I will return to my program.
For example (simplified):
Dim cmd As New SqlCommand With {.Connection = con}
cmd.commandText = "SELECT o.id, o.customer_name, o.date, p.productName FROM orders o JOIN order_positions p ON o.id = p.order_id WHERE o.date >= #pDate"
cmd.Parameters.Add("#pDate", SqlDbType.DateTime).Value = searchDate
Dim reader As SqlDataReader = cmd.ExecuteReader()
Dim lstOrderItems As New List(Of OrderDisplayItem)
while reader.read
dim orderId as Integer = reader.Item(0)
dim customerName as String = reader.Item(1)
dim date as Date = reader.Item(2)
dim productName as String = reader.Item(3)
lstOrderItems.add(New OrderDisplayItem With{.id = orderId, .customerName = customerName, .date = date, .productName = productName})
End While
return lstOrderItems
Now obviously this is just to show how I proceed. In reality, I have to create additional loops because one order might contain one or multiple products etc.
My question would be: is this the right way to handle this? It feels like this whole class will grow really big because I have other queries too like looking up invoices, store sales and so on - and for every query I have to write these reader loops which I would have to modify all over again if a slight thing in my database changes.
Is it really not possible to handle this within Visual Studio tableAdapters?
That means that I need a dynamic SQL query where a variable amount of parameters can be applied.
No it doesn't. You can use a single query with a single set of parameters and simply provide NULL for those parameters you want to ignore if you structure your SQL like this:
SELECT *
FROM MyTable
WHERE (#Column1 IS NULL OR Column1 = #Column1)
AND (#Column2 IS NULL OR Column2 = #Column2)
Your VB code might then look something like this:
Using connection As New SqlConnection("connection string here"),
command As New SqlCommand(query, connection)
command.Parameters.Add("#Column1", SqlDbType.VarChar, 50).Value = If(TextBox1.TextLength = 0, CObj(DBNull.Value), TextBox1.Text)
command.Parameters.Add("#Column2", SqlDbType.VarChar, 50).Value = If(TextBox2.TextLength = 0, CObj(DBNull.Value), TextBox2.Text)
'...
End Using
When you provide NULL for a parameter, that effectively matches every record and that parameter is effectively ignored. You can do that with as many parameters as you like of whatever data type that you like.

Filter between dates VB.NET and Access database

As the title says, I'm unable to filter an SQL sentence from access database with vb.net
Dim data1 As String = DateTimePicker1.Value.ToShortDateString
Dim data2 As String = DateTimePicker2.Value.ToShortDateString
Dim sql As String = "SELECT totais.* From totais Where totais.data Between #" + data1 + "# And #" + data2 + "#;"
It gives me random values. If i put 1-10(October)-2019 it gives me all the records in system, if i put 12-10(October)-2019 it only gives today's record (doesn't show yesterday and before records). I'm not finding the problem, can you please help?
Thanks
I would use Parameters instead of concatenating a string for the Sql statement. It makes the statement much easier to read and avoids syntax errors.
With OleDb the order that parameters appear in the sql statement must match the order they are added to the parameters collection because OleDb pays no attention to the name of the parameter.
Private Sub OPCode()
Dim sql As String = "SELECT * From totais Where data Between #StartDate And #EndDate;"
Using dt As New DataTable
Using cn As New OleDbConnection("Your connection string"),
cmd As New OleDbCommand(sql, cn)
cmd.Parameters.Add("#StartDate", OleDbType.Date).Value = DateTimePicker1.Value
cmd.Parameters.Add("#EndDate", OleDbType.Date).Value = DateTimePicker2.Value
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
DataGridView1.DataSource = dt
End Using
End Sub
You need to use single quotes and convert type in SQL like this:
SELECT totais.* FROM totais WHERE totais.data Between CDATE('" + data1 + "') And CDATE('" + data2 + "');"
You should use parameters as per Mary's answer BUT for completeness...
Ms/Access requires dates specified as #mm/dd/yy# so your SQL will only work properly where the local date time format is mm/dd/yy. i.e. mostly the US. Otherwise you will have to format your date string.

SQL Selecting without parameters?

Im trying to select all records from a database table. Each record has a date in it i want to select all records where that date matches todays date
i created a variable called todaydate and used it within the query but i get No value provided for one or more required parameters error. What possible parameters would i use
Here is the code
Any help would be appreciated
Dim todaydate As Date = Date.Today()
If DbConnect() Then
Dim SQLCmd As New OleDbCommand
With SQLCmd
.Connection = cn
.CommandText = "Select * from Tbl_Rental Where DateOfHire = todaydate"
'parameters????
You're not using the variable. However, you should always use sql-parameters not concatenate strings(one reason: avoiding SQL-Injection). I'd also suggest to use the Using-statement for the connection and everything else that implements IDisposable:
Using cn As New OleDbConnection(connectionString)
cn.Open()
Using cmd As New OleDbCommand("Select * from Tbl_Rental Where DateOfHire = #DateOfHire", cn)
dim hireDateParameter As new OleDbParameter("#DateOfHire", OleDbType.Date)
hireDateParameter.Value = Date.Today
cmd.Parameters.Add(hireDateParameter)
' ... '
End Using
End Using
If it's always Date.Today you could do that also without a parameter because every database has date functions which return the current date. But since you haven't told us which DB you are using it's hard to show an example.
You need to actually use your variable, not include it as part of the string. Try this:
.CommandText = "Select * from Tbl_Rental Where DateOfHire = '" & todaydate.ToString("dd/MM/yy") & "'"
From a slightly different angle, would it suffice that the date was simply "greater than yesterday"?
.CommandText = "Select * from Tbl_Rental Where DateOfHire >= cast(getdate() as date)"
This strips the time off the date and anything at or later than midnight today is included.

Pass parameter to a query from another query in Access

I have a parameterized query GET_CUSTOMER:
SELECT * FROM Customer WHERE id = [customer_id]
I want to call this query from another query and pass it a parameter:
SELECT * FROM GET_CUSTOMER(123)
Note the above code is not valid, it is here to give you an idea of what I'm trying to do. Is it possible to do this in MS Access?
UPDATE 1:
The queries I posted are for example. The actual queries are much more complex. I know I can use table joins, but in my specific case it would be much easier if I could run parameterized queries inside other queries (that are parameterized as well). I can't use access forms because I'm using access with my .NET application.
This is how I end up solving this with help of https://stackoverflow.com/a/24677391/303463 . It turned out that Access shares parameters among all queries so there is no need to specifically pass parameters from one query to another.
Query1:
SELECT * FROM Customer WHERE ID > [param1] AND ID < [param2]
Query2:
SELECT * FROM Query1
VB.NET code:
Dim ConnString As String = "Provider=Microsoft.Jet.OleDb.4.0;Data Source=Database.mdb"
Dim SqlString As String = "Query2"
Using Conn As New OleDbConnection(ConnString)
Using Cmd As New OleDbCommand(SqlString, Conn)
Cmd.CommandType = CommandType.StoredProcedure
Cmd.Parameters.AddWithValue("param1", "1")
Cmd.Parameters.AddWithValue("param2", "3")
Conn.Open()
Using reader As OleDbDataReader = Cmd.ExecuteReader()
While reader.Read()
Console.WriteLine(reader("ID"))
End While
End Using
End Using
End Using
You can build the SQL on the fly.
MyID = prompt or get from user some ID
strSQl = "Select * from tblCustomer where ID in " & _
"(select * from tblTestCustomers where id = " & MyID
So you can nest, or use the source of one query to feed a list of ID to the second query.

how to insert data through VB.NET

I am trying to pass my query string into database using VB.NET, but I am seeing a syntax error. I don't know where it is, please help me!
Me.str = String.Concat(New String()
{"Insert into Sales values('",
Me.txtVoucherNo.Text, "','", dtpDate.Value, "','",
dtpMonth.Value, "','", POSPage.txtPatientNo.Text, "','",
POSPage.txtPatientName.Text, "','",
POSPage.txtAddress.Text, ",'--',", POSPage.txtsubtotal.Text, "','",
POSPage.txtTax.Text, ",'--',", POSPage.txtdiscount.Text, "','",
POSPage.txtGrandTotal.Text, "')"})
Nooooooooooooo!
String edits like that leave you vulnerable to sql injection attacks. It's practically begging to get hacked.
You want something more like this:
Using cn As New SqlConnection(" connection string here "), _
cmd As New SqlCommand(
"Insert into Sales VALUES ( #VoucherNo, #Date, #Month, #PatientNo, #PatientName, #Address, '--', #SubTotal, #Tax, '--', #Discount, #GrandTotal )"
, cn )
'change this to use the actual column types and lengths in your database
cmd.Parameters.Add("#VoucherNo", SqlDbType.NVarChar, 10).Value = Me.txtVoucherNo.Text
cmd.Parameters.Add("#Date", SqlDbType.DateTime).Value = dtpDate.Value
cmd.Parameters.Add("#Month", SqlDbType.DateTime).Value = dtpMonth.Value
cmd.Parameters.Add("#PatientNo", SqlDbType.NVarChar, 10).Value = POSPage.txtPatientNo.Text
cmd.Parameters.Add("#PatientName", SqlDbType.NVarChar, 50).Value = POSPage.txtPatientName.Text
cmd.Parameters.Add("#Address", SqlDbType.NVarChar, 250).Value = POSPage.txtAddress.Text
cmd.Parameters.Add("#SubTotal", SqlDbType.Decimal).Value = Convert.ToDecimal(POSPage.txtsubtotal.Text)
cmd.Parameters.Add("#Tax", SqlDbType.Decimal).Value = Convert.ToDecimal(POSPage.txtTax.Text)
cmd.Parameters.Add("#Discount", SqlDbType.Decimal).Value = Convert.ToDecimal(POSPage.txtdiscount.Text)
cmd.Parameters.Add("#GrandTotal", SqlDbType.Decimal).Value = Convert.ToDecimal(POSPage.txtGrandTotal.Text)
cn.Open()
cmd.ExecuteNonQuery()
End Using
Note that, with this code, the SQL string itself is constant. Instead of a string field in your class (Me.Str), you need the full SqlCommand object, so that you can hold both the sql statement and the parameter data.
If you still have trouble with this, try including the names of the columns before the VALUES() clause.
That out of the way, original syntax error was because of this sequence in your string array:
"','", POSPage.txtAddress.Text, ",'--',"
Note that this would open a quoted field in your query, but not close it until after the comma. What comes next is a comment marker in Sql Server. In short, if you actually enter the name of the field as the address, you'd get this:
'POSPage.txtAddress.Text,'--
Everything after the two hyphens would be commented out, including the closing parentheses for your VALUES clause, meaning the query is not valid SQL syntax... assuming someone hasn't already used sql injection on another field to include put whatever sql statement they want as part of the query.
I won't tell you how to just fix that error, because it should be obvious now, and well... there's that pesky injection problem again. I will say that you made the same mistake with the other ",'--'," string later in the query.