I want to select a certain field from a datatable in VB based on the value of another field in the same row.
In SQL, it would easily be done by writing this query:
select error_message from table_errors where error_case="condition"
How do I do this if I have my SQL table filled in a datatable in VB?
How do I select the item("error_message") in the datatable based on the item("error_Case") field?
Any help would be appreciated
You can use Linq-To-DataSet:
Dim matchingRows As IEnumerable(Of DataRow) =
From row In table
Where row.Field(Of String)("error_case") = "condition"
If you just want one column (of course that works also in one step):
Dim errorMessages As IEnumerable(Of String) =
From row In matchingRows
Select row.Field(Of String)("error_message")
For Each error In errorMessages
Console.WriteLine(error)
Next
If you expect it to be just a single row use First or Single(throws an exception if there is more than one row):
Dim error As String = errorMessages.First()
Since First throws an exception if the sequence is empty you can use FirstOrDefault:
Dim error As String = errorMessages.FirstOrDefault() ' is null/Nothing in case of an empty sequence
All in one line (note that both Linq and DataTable.Select needs to use loops):
Dim ErrMessage As String = errorTable.AsEnumerable().
Where(Function(r) r.Field(Of String)("Error_Case") = TextCase.Text).
Select(Function(r) r.Field(Of String)("Error_Message")).
FirstOrDefault()
here is a worker version of the rough code
Dim connString As String = "select error_message from table_errors where error_case='condition'"
Dim conn As SqlClient.SqlConnection = New SqlClient.SqlConnection(connString)
conn.Open()
Dim cmd As SqlClient.SqlCommand = New SqlClient.SqlCommand(connString, conn)
Dim dTable As DataTable = New DataTable()
Dim dAdapter As SqlClient.SqlDataAdapter = New SqlClient.SqlDataAdapter(cmd)
dAdapter.Fill(dTable)
conn.Close()
Dim text As String
Dim dReader As DataTableReader = dTable.CreateDataReader()
While dReader.Read()
text = dReader.GetValue(0)
End While
dReader.Close()
Related
I'm having trouble with code that loops through the tables that contain TRelationCode. When it finds one it has to get the RelationCode from it and then convert it into the new RelationCode and update it to the new one.
To create the new RelationCode I've made a function Called MakeRelationCode(OldRelation). I have this code to loop through the tables:
Dim query As String = "use fmsStage; SELECT * FROM INFORMATION_SCHEMA.columns WHERE COLUMN_NAME = 'TRelationcode'"
Dim myCmd As SqlDataAdapter = New SqlDataAdapter(query, con)
Dim myData As New DataSet()
myCmd.Fill(myData)
For Each table As DataTable In myData.Tables
For Each row As DataRow In table.Rows
For Each col As DataColumn In table.Columns
Next
Next
Next
But now I need to update the old codes to the new ones.
I prefer simple SQL commands and a little vb logic thus I skipped the SqlDataAdapter part. This will only cost performance and is only necessary if you display something in a grid and want two-way-binding.
The following code is untested and typed blind so please check for typos etc.
I put everything in one method.
Dim tableNames As New List(Of String)
'Key: Old code, Value: New code'
Dim trelationcodes As New Dictionary(Of String, String)
Using conn As New SqlClient.SqlConnection("YourConnectionString") 'Change connection string to your needs'
Dim qTableNames = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.columns WHERE COLUMN_NAME = 'TRelationcode'"
conn.Open()
'Get table names with TRelationcode column'
Using commTableNames As New SqlClient.SqlCommand(qTableNames, conn)
Dim dataReader = commTableNames.ExecuteReader()
While dataReader.Read()
tableNames.Add(dataReader.GetString(0))
End While
End Using
'Select all distinct old TRelationcode which will be updated'
Dim qTrelationcodesOld = "SELECT DISTINCT TRelationcode FROM {0}"
For Each tableName In tableNames
'Get all old TRelationcodes from table found previuosly'
Using commTrelationcodesOld As New SqlClient.SqlCommand()
commTrelationcodesOld.Connection = conn
commTrelationcodesOld.CommandText = String.Format(qTrelationcodesOld, tableName)
Dim dataReader = commTrelationcodesOld.ExecuteReader()
While dataReader.Read()
Dim code = dataReader.GetString(0)
If Not trelationcodes.ContainsKey(code) Then
trelationcodes.Add(code, "") 'Value will be set later'
End If
End While
End Using
'Get new TRelationcodes'
For Each tRelCodeOld In trelationcodes.Keys
trelationcodes(tRelCodeOld) = MakeRelationCode(tRelCodeOld)
Next
'Set new TRelationcodes'
Dim uTRelationcode = "UPDATE {0} SET TRelationcode = #newCode WHERE TRelationcode = #oldCode"
For Each tRelCodes In trelationcodes
Using commTrelationcodesNew As New SqlClient.SqlCommand()
commTrelationcodesNew.Connection = conn
commTrelationcodesNew.CommandText = String.Format(uTRelationcode, tableName)
commTrelationcodesNew.Parameters.Add("#oldCode", SqlDbType.VarChar).Value = tRelCodes.Key 'Varchar correct?'
commTrelationcodesNew.Parameters.Add("#newCode", SqlDbType.VarChar).Value = tRelCodes.Value 'Varchar correct?'
commTrelationcodesNew.ExecuteNonQuery()
End Using
Next
Next
End Using
The code is far away from being optimal, e.g. I skipped exception handling.
The most concerning part is your MakeRelationCode function. If the logic inside could be written in T-SQL in a Stored Procedure, the overall coding would also be simplified.
database name is 'randomTable'
first col name is 'id'
2nd col name is 'name'
How do I get the value of 'name' col, same way I am getting the rows count?
Protected Sub BindGridData()
' Connect to databse and open database file
Dim da As SqlDataAdapter
Dim ds As DataSet = New DataSet()
Dim query As String = "SELECT * FROM [randomTable]"
Dim sqlConn As New SqlConnection(myCon)
Try
sqlConn.Open()
Dim cmd = New SqlCommand(query, myCon)
da = New SqlDataAdapter(cmd)
Dim builder As SqlCommandBuilder = New SqlCommandBuilder(da)
da.Fill(ds, "randomTable")
Dim a As Integer = ds.Tables("randomTable").Rows.Count
If a = 0 Then
e.Text = "empty"
End If
'this line is wrong - ???
Dim s As String = ds.Tables("randomTable").Columns("name")
if s = "value1"
'do something
end if
GridView1.DataSource = ds.Tables("randomTable").DefaultView
GridView1.DataBind()
sqlConn.Close()
Catch ex As Exception
End Try
End Sub
If you want the rows Count, you can execute a query tu Database "SElect Count() from randomTable". But in specific what do you want to do?
Either index by a specific row or iterate the row collection e.g.
Dim s As String = ds.Tables("randomTable").Rows(0).Field(Of String)("name")
If s = "value1" Then
'do something
End If
' or
For row As Integer = 0 To ds.Tables("randomTable").Rows.Count
If ds.Tables("randomTable").Rows(row).Field(Of String)("name") = "value1" Then
' do something
End If
Next
I have a SQL table called "Customers". In it is a CustomerNumber field with values like "0001234567", i.e. they are made up of numbers only, but some include leading 0s. So, when I try to run something like
sqlFetch(channel=myconn, sqtable="Customers", stringsAsFactors=FALSE)
it returns my customers table where the CustomerNumber field is numeric (instead of character), and consequently I lose all those leading 0s.
Is there a way I can specify the fieldtype for a column or an alternative solution that won't truncate all my leading 0s?
You can control the types of columns more fully using the as.is argument, which is documented in the Details section of ?sqlFetch as well as at the linked documentation for ?sqlQuery and ?sqlGetResults.
Basically, it is either a vector of logicals or a vector of numeric or character indices specifying which columns to leave untouched. This vector will be recycled as necessary.
(Note that RODBC will clobber columns stored in the database with type.convert even if the C API correctly returns char or varchar as the data type of the column in the database. The maintainer has not responded to any of my 4-5 emails on this issue over the past year, and I have since simply used a forked version of RODBC with the needed one line modification ever since.)
You could try specifying a query string and you could even cast the field if you're still having problems.
Sub Main()
Dim myConn As String = System.Configuration.ConfigurationSettings.AppSettings.Get("ConnStr")
Dim sqlConnection As SqlConnection = New SqlConnection(myConn)
Dim strSQL As String = "select cast(CustomerNumber as varchar(30)) as CustomerNumber_varchar, * from Customers"
Dim myds As DataSet
sqlConnection.Open()
Dim cmd As SqlCommand = New SqlCommand(strSQL, sqlConnection)
cmd.CommandTimeout = 60
Dim myReader As SqlDataReader = cmd.ExecuteReader()
myds = ConvertDataReaderToDataSet(myReader)
myReader.Close()
End Sub
Public Function ConvertDataReaderToDataSet(ByVal reader As SqlDataReader) As DataSet
Dim dataSet As DataSet = New DataSet()
Dim schemaTable As DataTable = reader.GetSchemaTable()
Dim dataTable As DataTable = New DataTable()
Dim intCounter As Integer
For intCounter = 0 To schemaTable.Rows.Count - 1
Dim dataRow As DataRow = schemaTable.Rows(intCounter)
Dim columnName As String = CType(dataRow("ColumnName"), String)
Dim column As DataColumn = New DataColumn(columnName, _
CType(dataRow("DataType"), Type))
dataTable.Columns.Add(column)
Next
dataSet.Tables.Add(dataTable)
While reader.Read()
Dim dataRow As DataRow = dataTable.NewRow()
For intCounter = 0 To reader.FieldCount - 1
dataRow(intCounter) = reader.GetValue(intCounter)
Next
dataTable.Rows.Add(dataRow)
End While
Return dataSet
End Function
I was trying to set DevExpress Chart Series from Data inside SQL Table.
Everything went fine except that the chart takes only the last attribute from the last series.
My code is:
con.Open() 'it opens SQL Connection
For i = 0 To (CheckedListBoxControl1.CheckedItems.Count - 1) 'list from ListBox
Lst.Add(CheckedListBoxControl1.CheckedItems(i).ToString) 'Putting Data in Array List
Dim Strl As String = String.Format("Select * from VPRogressCumulative where fname like '{0}' and lname like '{1}' order by id, no, CAST('1.' + date AS datetime)", ComboBox1.Text, Lst(i))
Dim sqlCom As New SqlCommand(Strl)
sqlCom.Connection = con
Dim myDA As SqlDataAdapter = New SqlDataAdapter(sqlCom)
Dim myDataSet As DataSet = New DataSet()
myDA.Fill(myDataSet, "VPRogressCumulative")
ChartControl1.DataSource = myDataSet
ChartControl1.DataAdapter = myDA
Dim ser As New Series(Lst(i), ViewType.Line)
ChartControl1.Series.Add(ser)
ser.ArgumentDataMember = "VPRogressCumulative.Date"
ser.ValueDataMembers.AddRange(New String() {"VPRogressCumulative.Cumulative"})
Next
con.Close()
I believe my Problem is in:
Dim ser As New Series(Lst(i), ViewType.Line)
ChartControl1.Series.Add(ser)
ser.ArgumentDataMember = "VPRogressCumulative.Date"
ser.ValueDataMembers.AddRange(New String() {"VPRogressCumulative.Cumulative"})
Last two lines are giving the same series new attributes which I wasn't able to resolve the issue.
Your problem is here:
ChartControl1.DataSource = myDataSet
ChartControl1.DataAdapter = myDA
In each iteration of cycle you are creating the new DataSet and it's overrides previous DataSource in your ChartControl1. Your must use Series.DataSource instead of ChartControl.DataSource. Also you can use DataTable instead of DataSet.
Here is example:
'Your code:
'Dim myDataSet As DataSet = New DataSet()
'myDA.Fill(myDataSet, "VPRogressCumulative")
'ChartControl1.DataSource = myDataSet
'ChartControl1.DataAdapter = myDA
'Replace with this:
Dim myDataTable As DataTable = New DataTable("VPRogressCumulative")
myDA.Fill(myDataTable)
Dim ser As New Series(Lst(i), ViewType.Line)
ChartControl1.Series.Add(ser)
'Your code.
'ser.ArgumentDataMember = "VPRogressCumulative.Date"
'ser.ValueDataMembers.AddRange(New String() {"VPRogressCumulative.Cumulative"})
'Replace with this:
ser.DataSource = myDataTable
ser.ArgumentDataMember = "Date"
ser.ValueDataMembers.AddRange(New String() {"Cumulative"})
The result of my sql-query is a single value i want display that in a lable but dont know how. I have a solution creating a dataset put the result of the query into that dataset and get it by row(0),column(0) but i guess there is a smarter way doing it.
Private myquery As String
Sub New(ByVal query As String)
myquery = query
End Sub
Public Sub query_Send()
Dim myconn As New SqlConnection("Data Source=DB;Integrated Security=TRUE")
Dim mycmd As SqlCommand = New SqlCommand(Me.myQuery, myconn)
Dim myTable As New DataTable
Dim previousConnectionState As ConnectionState = myconn.State
Try
If myconn.State = ConnectionState.Closed Then
myconn.Open()
Dim myDA As New SqlDataAdapter(mycmd)
myDA.Fill(myTable)
tb.text = **...**
End If
If previousConnectionState = ConnectionState.Closed Then
myconn.Close()
End If
End Try
End Sub
You can use SqlCommand.ExecuteScalar Method
Dim querystr as String = "select value from MyTable where ID=5"
Dim mycmd As New SqlCommand(querystr, connection)
dim value as Object = mycmd.ExecuteScalar()
The value you can put to your textbox. ExecuteScalar returns first value of first row of the resultset (equivalent of row(0).column(0) ) When no record is returned the value is nothing.
Try something more along the lines of:
Using myconn As New SqlConnection("Data Source=DB;Integrated Security=TRUE")
Dim myDA As New SqlDataAdapter()
myDA.SelectCommand = New SqlCommand(myQuery, myconn)
myDA.Fill(myTable)
Return myTable
End Using
Or you can just get ahold of the first item in the first row with
myTable.Rows(0).ItemArray(0).ToString()