I never asked any questions on stackoverflow but it already brought me tons of answers !
But this time, after some extended research, I have to ask it myself.
I'm using VB.Net with Sqlite and my query doesn't return any value when I execute it with parameters. I guess this has something to do with the fact SituationString contains commas but I really can't figure it out.
Here's is my code :
dim ChildCtx as Integer
dim SituationString as String
SituationString="968,970,978,979,980,981,995,1022,1099,1119"
With DataBase
.SQL_CMD.Parameters.Clear()
.SQL_CMD.CommandText = "SELECT SERVCTX_NO FROM SERVCTX WHERE SERVCTX_NO IN (#situationstring) AND MASTER = '1'"
.SQL_CMD.Parameters.Add("#situationstring", SqlDbType.VarChar, 255).Value = SituationString
ChildCtx = .SQL_CMD.ExecuteScalar
.SQL_CMD.Parameters.Clear()
End with
Connection is open and query works out fine if I write the whole query into one string.
Thanks,
You are mixing two techincs: merging constant data into SQL command and using parameters to pass data.
I suppose SituationString is a list of integer you expect for SERVCTX_NO.
So, you must merge it into statement:
.SQL_CMD.CommandText = "SELECT SERVCTX_NO FROM SERVCTX WHERE SERVCTX_NO IN ("+SituationString+") AND MASTER = '1'"
ChildCtx = .SQL_CMD.ExecuteScalar
Using parameters, as you did, SERVCTX_NO would be expected to be a string with 968,970,978,979,980,981,995,1022,1099,1119 exact content!
Related
first post here. I'm getting my app development feet wet with some PowerShell scripting; I know it's not the best for developing GUI applications but it's what I'm familiar with and the best way I know of to interact with Office 365 applications, which my employees have to do a lot of.
I'm trying to build functions to make it easy to populate combo boxes, read user input from the combobox, and then query an Access database for specific results based on that input.
I've got another function that queries the database to pull a list that populates a combobox. now, i want to build a separate function that
"reads" the user's input from the combobox
opens an OleDB connection to query the access database
scans the database table for the row corresponding to the user's input
returns, as a string, the cell in a different column from the same row the user chose
this is what i have so far:
function Read-BoxSelection ($sourceBox, $sourceTable, $sourceColumn, $targetColumn){
$conn = New-Object System.Data.OleDb.OleDbConnection
$conn.ConnectionString = $connString
$conn.Open() | Out-Null
$cmd = New-Object System.Data.OleDb.OleDbCommand
$cmd.Connection = $conn
$selectedID = $sourceBox.SelectedItem
[string]$writeQuery = ("SELECT * FROM $($sourceTable) WHERE $($sourceColumn) = $($selectedID)")
$cmd.CommandText = "$writeQuery"
$reader = $cmd.ExecuteReader()
while ($reader.read()){
$readerResult = $reader.getValue($reader.GetOrdinal("$targetColumn"))
return $readerResult
}
$reader.close()
$conn.close()
}
I am sure the while() loop will need to change; it's pulled over from the earlier function that populates the combobox with the contents of the $sourceColumn.
The issue: my first function was called Get-BoxData. it opens the connection, runs a query, and uses the while() loop to Items.Add each cell from the $targetColumn to the combo box. for Get-BoxData function, the following code worked fine to execute the SQL query:
[string]$readQuery = ("SELECT * FROM $($targetTable)")
$cmd.CommandText = "$readQuery"
$reader = $cmd.ExecuteReader()
but when I change the query for Read-BoxSelection - namely, to filter the result based on user input with WHERE - the command doesn't get passed to ExecuteReader no matter what I do. This is very strange, because I placed a breakpoint at the ExecuteReader line, and Write-Host confirms that both $writeQuery and $cmd.CommandText have successfully picked up the query exactly as written. stranger still is that previously, debugging ExecuteReader issues would involve a syntax error in the SQL query; here, I'm getting the following error:
Exception calling "ExecuteReader" with "0" argument(s): "No value given for one or more required parameters."
Not sure how to proceed here!
String literals in SQL must be enclosed in quotes whether used in SELECT, JOIN, or WHERE clauses. Otherwise the database engine will consider the object an identifier (table, column, etc.) or parameter. MS Access treats any unquoted, named object not recognized in table as a parameter.
Therefore, the short answer is to wrap WHERE condition value in single quotes since as you comment is a string value:
[string]$writeQuery = ("SELECT * FROM $($sourceTable) WHERE $($sourceColumn) = '$($selectedID)'")
However, the preferred answer is to use parameterization which can easily be done since you already set up the command object:
# PREPARED STATEMENT WITH ? PLACEHOLDER
[string]$writeQuery = ("SELECT * FROM $($sourceTable) WHERE $($sourceColumn) = ?")
$cmd.CommandText = $writeQuery
# ADD AND BIND PARAMETER
$cmd.Parameters.Add("#param", [System.Data.OleDb.OleDbType]::VarChar, 255)
$cmd.Parameters["#param"].Value = $selectedID
$reader = $cmd.ExecuteReader()
I'm using npgsql as a nuget package in visual studio 2017 with visual basic.
Various commands do work very well but an ExecuteScalar allways returns 'nothing' although it should give a result.
The command looks like this:
Dim ser As Integer
Dim find = New NpgsqlCommand("SELECT serial from dbo.foreigncode WHERE code = '#code';", conn)
Dim fcode = New NpgsqlParameter("code", NpgsqlTypes.NpgsqlDbType.Varchar)
find.Parameters.Add(fcode)
find.Prepare()
fcode.Value = "XYZ"
ser = find.ExecuteScalar() ==> nothing
When the command string is copied as a value during debugging and pasted into the query tool of PGADMIN it delivers the correct result. The row is definitely there.
Different Commands executed with ExecuteNonQuery() work well, including ones performing UPDATE statements on the row in question.
When I look into the properties of the parameter fcode immediately before the ExecuteScalar it shows 'fcode.DataTypeName' caused an exception 'System.NotImplementedException'.
If I change my prepared statement to "SELECT #code" and set the value of the parameter to an arbitrary value just this value is returned. There is no access to the table taking place because the table name is not part of the SELECT in this case. If I remove the WHERE CLAUSE in the SELECT and just select one column, I would also expect that something has to be returned. But again it is nothing.
Yes there is a column named serial. It is of type bigint and can not contain NULL.
A Query shows that there is no single row that contains NULL in any column.
Latest findings:
I queried a different table where the search column and the result column happen to have the same datatype. It works, so syntax, passing of parameter, prepare etc. seems to work in principal.
The System.NotImplementedException in the DataTypeName property of the parameter occurs as well but it works anyway.
I rebuilt the index of the table in question. No change.
Still: when I copy/paste the CommandText and execute it in PGAdmin it shows the correct result.
Modifying the Command and using plain text there without parameter and without prepare still does yield nothing. The plain text CommandText was copy/pasted from PGAdmin where it was successfully executed before.
Very strange.
Reverting search column and result column also gives nothing as a result.
Please try these two alternatives and post back your results:
' Alternative 1: fetch the entire row, see what's returned
Dim dr = find.ExecuteReader()
While (dr.Read())
Console.Write("{0}\t{1} \n", dr[0], dr[1])
End While
' Alternative 2: Check if "ExecuteScalar()" returns something other than an int
Dim result = find.ExecuteScalar()
... and (I just noticed Honeyboy Wilson's response!) ...
Fix your syntax:
' Try this first: remove the single quotes around "#code"!
Dim find = New NpgsqlCommand("SELECT serial from dbo.foreigncode WHERE code = #code;", conn)
Update 1
Please try this:
Dim find = New NpgsqlCommand("SELECT * from dbo.foreigncode;", conn)
Q: Does this return anything?
Dim dr = find.ExecuteReader()
While (dr.Read())
Console.Write("{0}\t{1} \n", dr[0], dr[1])
End While
Q: Does this?
Dim result = find.ExecuteScalar()
Q: Do you happen to have a column named "serial"? What is it's data type? Is it non-null for the row(s) with 'XYZ'?
Please update your original post with this information.
Update 2
You seem to be doing ":everything right":
You've confirmed that you can connect,
You've confirmed that non-query updates to the same table work (with npgsql),
You've confirmed that the SQL queries themselves are valid (by copying/pasting the same SQL into PGAdmin and getting valid results).
As Shay Rojansky said, "System.NotImplementedException in the DataTypeName property" is a known issue stepping through the debugger. It has nothing to do with your problem: https://github.com/npgsql/npgsql/issues/2520
SUGGESTIONS (I'm grasping at straws)::
Double-check "permissions" on your database and your table.
Consider installing a different version of npgsql.
Be sure your code is detecting any/all error returns and exceptions (it sounds like you're probably already doing this, but it never hurts to ask)
... and ...
Enable verbose logging, both client- and server-side:
https://www.npgsql.org/doc/logging.html
https://www.postgresql.org/docs/9.0/runtime-config-logging.html
... Finally ...
Q: Can you make ANY query, from ANY table, using ANY query method (ExecuteReader(), ExecuteScalar(), ... ANYTHING) from your npgsql/.Net client AT ALL?
I finally found it. It's often the small things that can have a big impact.
When the value was assigned to the parameter a substring index was incorect.
Now it works perfectly.
Thanks to everybody who spent his time on this.
I am working with Unidata, and ADO.NET using the U2 .NET Provider. This may be a shot in the dark as there are not many resources for Unidata and .NET these days.
Currently I can only return a single MV record 153926þIþ and parse it using MV_To_DataTable. I'd like to return multiple records like 153926þIþÿ153926þIþÿ. Is there any built in mechanism for doing this? I fear I will have to write the extension to best accomodate me.
I retrieve a single record in a unidata subroutine this way:
SUBROUTINE GETITEMS(results)
EXECUTESQL "SELECT ID, STATUS, DESC FROM ITEMS TO GETITEM_LIST;"
DONE = 0
RECCNT = 0
LOOP
RECCNT += 1
READNEXTTUPLE REC FROM "GETITEM_LIST" ELSE DONE = 1
results := REC
IF RECCNT EQ 1 THEN EXIT
UNTIL DONE
REPEAT
results
CLEARSQL
RETURN
Simple subroutine that returns one record without any record marks. This works when I use the U2Parameter method called MV_To_DataTable to parse it into an existing datatable.
However when I change the subroutine line:
results:= REC to results:= REC : #RM to append the record marks and remove the limit of 1, the MV_To_DataTable no longer is able to parse it correctly. In fact it will throw System.IndexOutOfRangeException: Cannot find column 3.
VB.NET Code:
' ... Open database connection called U2Connection ...
Dim cmd = U2Connection.CreateCommand
cmd.CommandText = "CALL GETITEMS(?)"
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Clear()
cmd.Parameters.Add(New U2Parameter("#arg1", "") With {.Direction = ParameterDirection.InputOutput})
cmd.ExecuteNonQuery()
Dim tb As New DataTable
tb.Columns.Add("ID")
tb.Columns.Add("STATUS")
tb.Columns.Add("DESC")
cmd.Parameters.Item(0).MV_To_DataTable(tb) ' Error happens here
' System.IndexOutOfRangeException: Cannot find column 3.
It appears the method does not separate records. I could be interpretting this incorrectly.
*****UPDATE 2/9/2019
I went ahead and wrote my own extension method to support my return format with the record markers. It populates a datatable with records allowing me to continue as I normally would.
You are kind of straddling the Multivalue/System.Data divide here. If you have not already done so, I would suggest looking into the U2 Toolkit for .NET, which I believe is generally readily available if you are current on maintenance. It comes with some samples of how to do things like this in C# and VB as well some Entity Framework stuff.
But as to what is going on here, You are trying to put a U2Type.DynArray into a System.DataTable is kind of tricky as the DynArray is a Record state, which could contain multiple rows from multiple tables within a DataSet. As #RM is the terminator for a record so it turns DynArray into DynArray[] and you can't have that as a parameter as such.
To fix this with the minimum refactoring, you can still use MV_To_DataTable, but note that it is expecting your data to be tabular and in in a single record. These example assume a newline is an Attribute mark (#FM/#AM)
Here is the contents of what you are returning
Row1Column1
Row1Column2
Row1Column3:#RM
Row2Column1
Row2Column2
Row2Column3:#RM
Row13olumn1
Row13olumn2
Row13olumn3:#RM
And here is what MV_To_DataTable expects
Row1Column1:#VM:Row1Column2:#VM:Row1Column3
Row2Column1:#VM:Row2Column2:#VM:Row2Column3
Row3Column1:#VM:Row3Column2:#VM:Row3Column3
If you adjust your U2 sub to output that, it should work.
Additionally, you could try using your SQL command directly for .net, but that becomes perilous for other reasons depending on your data.
Good Luck!
I have a matrix called "final_set" which gets created in my R code. Using some of the columns from this final set, I want to create a database table. I'm using the RJDBC package to make this happen.
However, for some reason its not recognizing "final_set" . I know my connection is okay because I've tried out other sql queries using that.
Could anyone help me with this please?
SqlStr = paste("SELECT",
S_Vars, ",", #Global Variable
final_set$pub_idx, ",",
final_set$qty_idx
into dbo.temp1
"from",
final_set,
sep = ""
)
dbSendUpdate(conn,SqlStr)
Error: Error in paste(**): object final_set not found
I think you want your query to be:
SqlStr = paste("SELECT",
S_Vars, #Global Variable
", pub_idx, qty_idx into dbo.temp1 from final_set")
R objects that are not strings shouldn't go in your query as R objects, as their values (not their names) will be coerced to strings.
I'm still a little confused as to your goal. If you're trying to create a table out of an R object, (i.e., final_set is not already a table in your database), then the database won't be able to select columns from final_set. Rather, you should use a function like dbWriteTable. If I'm correct about that, then I think what you're looking for is
dbWriteTable(conn, "temp1", final_set[, c(S_Vars, "pub_idx", "qty_idx")]
I have following code.
string DB_PATH = Path.Combine(ApplicationData.Current.LocalFolder.Path, "Questions.sqlite");
SQLiteConnection dbConn = new SQLiteConnection(DB_PATH);
dbConn.CreateTable<QuestionModel>();
// Some code which insert the records in database from webservices.
List<QuestionModel> questionsList = dbConn.Table<QuestionModel>().ToList();
System.Diagnostics.Debug.WriteLine("List Count " + dbConn.Table<QuestionModel>().ToList().Count);
The List Count gives me 0 always. But When I use WP POWER TOOLS and get the Questions.sqlite file from emulator. It gives me records in SQLite table.
I also check the query in http://sqlitestudio.pl/ on the same Questions.sqlite but that gives me records as it should.
I tried other way to get the records as following code but none them were working.
String query = "Select * from QuestionModel;";
questionsList = dbConn.Query<QuestionModel>(query);
System.Diagnostics.Debug.WriteLine("List Count " + questionsList.Count);
With your analysis seems like only the row List<QuestionModel> questionsList = dbConn.Table<QuestionModel>().ToList(); is not working.
I helped someone in SQLiteDB on WP8 a couple of days ago, here is his question : SQLite WP8 StackOverflow
If you compare his code with your code, you are missing the Model bindind :
db.GetTableInfo("QuestionModel");
And
db.Table<QuestionModel>().ToList<QuestionModel>();
Not important but use your list variable to get count in debug write to not retrieve twice the list questionsList.Count
Hope it helps.