I'm working with Windows Forms - VB.NET.
Here's what I have:
A ListView with checkboxes set to True
A Button (triggers the update)
A database table with similar fields as the ListView
What I want to happen:
when the user clicks the Button, all items on the ListView with checkbox checked will be updated.
My progress:
I've already collected the ID of the checked items and stored them in an array. I'll be using this to update the database table.
The problem:
I don't know how to put them in the SqlCommand.Parameters
Also, I don't know the update command for such scenario (where in/exist (#parameters))
Thanks in advance!
If you're using SQL Server 2008 or later, you can use table-valued parameters. These let you continue to deal with the separate IDs on separate rows, perform SQL joins, etc. There are plenty of examples on the page I've linked to, e.g.:
Using connection
' Create a DataTable with the modified rows.
Dim addedCategories As DataTable = _
CategoriesDataTable.GetChanges(DataRowState.Added)
' Define the INSERT-SELECT statement.
Dim sqlInsert As String = _
"INSERT INTO dbo.Categories (CategoryID, CategoryName)" _
& " SELECT nc.CategoryID, nc.CategoryName" _
& " FROM #tvpNewCategories AS nc;"
' Configure the command and parameter.
Dim insertCommand As New SqlCommand(sqlInsert, connection)
Dim tvpParam As SqlParameter = _
insertCommand.Parameters.AddWithValue( _
"#tvpNewCategories", addedCategories)
tvpParam.SqlDbType = SqlDbType.Structured
tvpParam.TypeName = "dbo.CategoryTableType"
' Execute the query
insertCommand.ExecuteNonQuery()
End Using
You could easily replace that INSERT with an UPDATE, as shown earlier on the page:
UPDATE dbo.Categories
SET Categories.CategoryName = ec.CategoryName
FROM dbo.Categories INNER JOIN #tvpEditedCategories AS ec
ON dbo.Categories.CategoryID = ec.CategoryID;
And adjust parameter names accordingly.
It seems you want to use a single call to the database, for that you would need to build a string with the command, I don't think you can pass a list as parameter to a command / sp.
The update command:
UPDATE [table] SET [field1] = value1, [field2] = value2
WHERE [ID] IN (id1, id2, ..., idN)
Related
I have a column called "product-code". These are all populated. I am wanting to do a query that will insert a ' at the start of each field and then another query to add a ' at the end of the field.
So for example at the moment a product code might be fmx-2, after the query I would want it to look like 'fmx-22'
I am looking to do this for all the data sets within the table. I am using Microsoft Access
Thanks
In Microsoft Access you can use & char to concatenate string, and your query could be something similar:
update my_table set product_code = "'" & product_code & "'";
Try
Using connection As New SqlConnection(ConnectionString)
connection.Open()
SQL = "SELECT #PARAM FROM SystemOps"
sqlCmd = New SqlClient.SqlCommand(SQL, connection)
sqlCmd.Parameters.Add(New SqlClient.SqlParameter("#PARAM", SqlDbType.VarChar)).Value = "SystemNavn"
' .. and so on...
When I run the code, it returns with a result of "SystemNavn" (which is the name of the column in the table), instead of the value of that column in the current row. What am I doing wrong?
You cannot use parameter names for column names, or any other SQL syntax. You can only use parameters as placeholders for literal values. Parameters always get replaced with the literal form for the value, so in your example, the command which is being run, essentially, gets evaluated as:
SELECT 'SystemNavn` FROM SystemOps
In order to have a variable column name, like that, I would recommend dynamically building the SQL string, like this:
Dim columnName As String = "SystemNavn"
SQL = "SELECT [" & columnName & "] FROM SystemOps"
However, by doing so, you are opening yourself up to potential SQL-injection attacks, so you need to be careful. The safest way, that I'm aware of, to avoid an attack in a situation like this is to get the list of column names from the database and compare the columnName variable against that list to ensure that it is actually a valid column name.
Of course, if the column name never changes, then there's no reason to make it a variable at all. In that case, just hard-code it directly into the SQL command, thereby avoiding the necessity for parameters or variables at all:
SQL = "SELECT SystemNavn FROM SystemOps"
Your query doesn't need any parameters in this case. just do
SQL = "SELECT SystemNavn FROM SystemOps"
This is secure. If later you need to filter this, you can do something like:
SQL = "SELECT SystemNavn FROM SystemOps WHERE COL_A = #ColA"
FYI, for your code above, since it is a VARCHAR type, it is being executed like so:
SELECT 'SystemNavn' FROM SystemOps
That is why you're getting 'SystemNavn' back.
You cannot use a parameter to specify the name of a column or a table.
The parameters collection are used to specify the values to search for, to insert, to update or delete.
Your code should be changed to something like this
Using connection As New SqlConnection(ConnectionString)
connection.Open()
SQL = "SELECT SystemNavn, <other fiels if needed> " & _
"FROM SystemOps WHERE <keyfield_name> = #PARAM"
sqlCmd = New SqlClient.SqlCommand(SQL, connection)
sqlCmd.Parameters.AddWithValue("#PARAM", paramValue)
......
End Using
Of course the example above assumes that you have a WHERE clause, if you want to retrieve every value of the column SystemNavn without condition, then you don't need a parametrized query because every part of your sql command is provided by you and there is no worry for sql injection.
I have been trying to find this. I am using access 2010 and I have some data in a few tables and I want to select the last row from each one and add them to a new database. All the databases have random ID so I can't use the Sort by ID function.
If the table is small, you can pass it to a datatable in the frontend and use something like this,
lastRow = datatable.rows(datatable.rows.count-1)
Else, You can add a 'created_datetime' field in database which holds the inserted datetime and retrieve its maximum date since your ID field has random number...
open vba (alt + F11)
dim rst as recordset
set rst = docmd.runsql (sql statement here) e.g. (select * from tablename)
rst.movelast
you've gotten to your last record in vba
you can add it to a new table database by using an insert statement.
I am having trouble writing a VBA macro within Microsoft Access. What I am trying to do is use SQL to create an output table, but I want to write to multiple columns simultaneously.
This gets me all the values I need for one column:
Docmd.RunSQL “INSERT INTO Output (TargetCol1) SELECT [Field1] FROM [Table1] WHERE [Criteria1] = ‘Value’ GROUP BY Field1”
When I try to run this multiple times to get the values I need for other columns. INSERT INTO writes the data as new records, so I end up with blank spaces, like this:
Field1----Field2
Value----<Null>
Value----<Null>
Value----<Null>
<Null>----Value
<Null>----Value
What I want is:
Field1----Field2
Value---- Value
Value---- Value
Value----<Null>
I tried to create variables and create kind of a nested statement but I receive a ‘Compile error, object required’ on my first line when I try to run what I have written:
Set x = Docmd.RunSQL “INSERT INTO Output (TargetCol1) SELECT [Field1] FROM [Table1] WHERE [Criteria1] = ‘Value’ GROUP BY Field1”
Set y = Docmd.RunSQL “INSERT INTO Output (TargetCol2) SELECT [Field2] FROM [Table1] WHERE [Criteria2] = ‘Value’ GROUP BY Field2”
Docmd.runsql “INSERT INTO Output (TargetCol1, TargetCol2) Values (x,y)”
Why not:
INSERT INTO Output (TargetCol1,TargetCol2) SELECT [Field1,Field2] FROM [Table1] [Criteria1] = 'Value'"
Set is used for objects, and you do not have one in Set x = Docmd.RunSQL. Order by is irrelevant for a table.
The easiest way to set up queries is using the query design window. it will guide you through creating the query and you can then switch to SQL view to get SQL.
I suggest you do not use RunSQL : What's the difference between DoCmd.SetWarnings and CurrentDB.Execute
I would like to use a query to loop through tables that are similar in structure but have different names (ie. tableJan2011, tableFeb2011, tableMar2011 etc.)
Is there a way in MS Access and in SQL Server to use the same query statement while varying the table name within it. (similar to using parameter values) (need this to add different input to each different month's table)
This is a bad table design. You should have a singe table, where you have a column(s) to indicate month/year. You would then just query this single table and add a WHERE month='X' and YEAR='Y' to limit your results to what you need.
without a table redesign use UNION and clever WHERE clause parameters, which will cause rows to only come from the table that applies.
SELECT
..
FROM tableJan2011
where...
UNION
SELECT
..
FROM tableFeb2011
where...
UNION
SELECT
..
FROM tableMar2011
where...
First off, listen to the people who are telling you to use one table. They know of which they speak.
If you can't do that for some obscure reason (such as inheriting the design & not being allowed to change it), then you're stuck writing VBA code. There's no way that I know of, in Access, to substitute source tables (or even source columns--values only), in a saved QueryDef.
You'll need something like this:
Private Function QueryTable (strTableName as String) As DAO.Recordset
Const theQuery as String = "SELECT tbl.* FROM [table] As tbl"
Dim sSql As String
Dim db As DAO.Database
Dim rs As DAO.Recordset
sSql = Replace(theQuery, "[table]", strTableName)
Set db = CurrentDb()
Set rs = db.OpenRecordset(sSql)
Set QueryTable = rs
End Function
Note that this is simplified code. There's no error handling, I haven't released the objects (which I usually do, even though they'll go out of scope), and SELECT * is almost always a bad idea.
You'd then call this function wherever you need it, passing in the name of the table.
consider moving the year and month out of the table name and into columns in one table.
you can create a table with query or table names to use at runtime, but you have to be able to write Access BASIC code in a module.
Here's an example, assuming you have a query built on a table with the query names you want to execute:
Set db = CurrentDb
Set rsPTAppend = db.OpenRecordset("qry_PTAppend")
rsPTAppend.MoveFirst
Do Until rsPTAppend.EOF
qryPT = rsPTAppend("PT")
Set qdef = db.QueryDefs(qryPT)
sqlOld = qdef.sql
sqlNew = sqlOld
' manipulate sql
If sqlNew <> sqlOld Then
qdef.sql = sqlNew
End If
db.QueryDefs(rsPTAppend("append")).Execute
If sqlNew <> sqlOld Then
qdef.sql = sqlOld
End If
rsPTAppend.MoveNext
Loop
Don't know what is possible in Access but in SQL Server you could create a view that use union to get all tables together and then build your queries against the view.
One other option you have could be to build your queries dynamically.
In sql server you can execute a string as sql.
http://msdn.microsoft.com/en-us/library/ms175170.aspx
I'm not aware of anything similar in MS Access (though my experience is limited). You could however dynamically generate your sql in code to accomplish this. Perhaps you could create a function to take the table suffix and parameters and build the desired sql that way.