Can I somehow query the database for a field that I have in string?
string fieldName = "Column1";
SQL:
string sql = "SELECT " + fieldName + " FROM myTable";
I need to do this using LINQ
Is there something built-in and quick for such questions or does reflection come into play?
You can implement a simple method for this:
private static IEnumerable<IDataRecord> ReadSqlRecords(string sql) {
//TODO: Put connection string here
//TODO: I've assumed you work with MS SQL; if not replace SqlConnection
using (var conn = new SqlConnection("ConnectionStringHere")) {
conn.Open();
using (var q = conn.CreateCommand()) {
q.CommandText = sql;
using (var reader = q.ExecuteReader()) {
while (reader.Read())
yield return reader;
}
}
}
}
Then you can use it
string sql = $"SELECT {fieldName} FROM myTable";
// Now you can put Linq
var result = ReadSqlRecords(sql)
.Where(record => Convert.ToInt32(record["Id"]) > 100)
.Count();
Try this:
using (var context = new MyContext())
{
// Get the object from the table (in this case I give an example to get the first row. You can use Where for the condition)
var row = context.MyTable.FirstOrDefault();
// Get the field value with reflection
response = row.GetType().GetProperty(name).GetValue(row, null).ToString();
}
Related
I am very new to database queries and even more so, Oracle. I am also new to development work and, believe it or not, am creating this an for work purely out of frustration with the current process. Anyway, I am attempting to collect input from a multi-line text box and run a query. Each line corresponds to a single string that needs to be passed into the WHERE statement and the results will be dumped into a data table. Unfortunately, Oracle has still not released its developer tools for VS2019 so I am having to do this the harder way.
UPDATE # 2:
I have completely rebuilt the query since it was not running even when using known working code from another query. Below is what I have pieced together from various places on the interwebs. While debugging, it appears to parse and format the text correctly and pass it into the OracleParameter without issue. I am getting a Missing Expression error but I don't know what I am missing.
var connString =
ConfigurationManager.ConnectionStrings["dB"].ConnectionString;
string query = "SELECT col1, col2, col3, col4 FROM table WHERE col5 IN (";
using (OracleConnection conn = new OracleConnection(connString))
try
{
var input = "";
input = uniLookup.UniList;
var uniList = string.Join(",", Regex.Split(input, #"(?:\r\n|\n|\r)"));
string allParams = uniList;
string formattedParams = allParams.Replace(" ", string.Empty);
string[] splitParams = formattedParams.Split(',');
List<OracleParameter> parameters = new List<OracleParameter>();
using (OracleCommand cmd = new OracleCommand(query, conn))
{
for (int i = 0; i < splitParams.Length; i++)
{
query += #":Uni" + i + ",";
parameters.Add(new OracleParameter(":Uni" + i, splitParams[i]));
{
query = query.Substring(0, (query.Length - 1));
query += ')';
conn.Open();
using (OracleDataReader reader = cmd.ExecuteReader()) <==ERROR
{
if (!reader.HasRows)
{
while (reader.Read())
{
reader.Read();
{
MessageBox.Show(reader.GetString(1));
}
}
}
You can use IN in your where clause in this way to get rows from multiple values as:
string query = "SELECT dummyCol FROM dummytable WHERE altCol IN ("+text+");";
where you just have to change your text as text="'value1','value2','value3'"; this will not produce any syntax error.
You can convert your multi line text into same comma separated values using this :
foreach (String s in textBox1.Text.Split('\n'))
{
text +="'"+ s+"',";
}
text = text.TrimEnd(',');
this will help you achieve what you need. you can ask If there is any confusion.
Your final code will become :
public void GetData()
{
if (string.IsNullOrWhiteSpace(textbox1.Text) || textbox1.Text == "")
{
MessageBox.Show("Please Enter at least 1 Value and Try Again!");
}
else
{
System.Data.DataTable dt = new System.Data.DataTable();
// string[] lines = textbox1.Text.Split('\n');
string text = "";
foreach (String s in textBox1.Text.Split('\n'))
{
text += "'" + s + "',";
}
text = text.TrimEnd(',');
//Connection Credentials
string credentials = "Credentials";
string query = "SELECT dummyCol FROM dummytable WHERE altCol IN ("+text+");";
OracleConnection conn = new OracleConnection(credentials);
try
{
//Open The Connection
conn.Open();
using (OracleCommand cmd = new OracleCommand(query, conn))
{
//Call the Oracle Reader
using (OracleDataReader reader = cmd.ExecuteReader())
{
if (!reader.HasRows)
{
MessageBox.Show("Unable to Retrieve Data");
return;
}
else if (reader.HasRows)
{
reader.Read();
DataRow row = dt.NewRow();
// create variables to accept reader data for each column
// insert data from query into each column here
dt.Rows.Add(row);
}
}
}
}
}
}
I am using the following Access query on C# MVC to compare two tables and return records that fall within the date range and machine selected by the user. The query code runs perfectly on the actual Access database but I guess something is wrong with the connection string and the code to return the results. I am not sure what's wrong with the code and I would appreciate if someone could help me determine what's wrong. Thanks!
C# MVC Controller code:
public ActionResult MissingChecksheets(string startDate, string endDate, string machine)
{
var query = $#"SELECT * FROM [TrackingLog]
WHERE [TrackingLog].[Workcenter] = '{machine}' AND
[TrackingLog].[Complete Date] > #{startDate}# AND
[TrackingLog].[Complete Date] < #{endDate}# AND
[TrackingLog].[Order Item] NOT IN (SELECT [OrderNum] FROM [dbo_Checksheet])";
var sheets = new List<Checksheet>();
using (var con = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Checksheets.accdb;"))
{
using (var command = new OleDbCommand(query, con))
{
con.Open();
using (var reader = command.ExecuteReader())
{
while (reader.NextResult())
{
sheets.Add(new FabChecksheet
{
OrderNum = reader.GetString(0),
PartNum = reader.GetString(1)
});
}
}
}
}
return PartialView(sheets);
}
OleDbDataReader.NextResult() method used to move between result set if the query string has multiple result sets (e.g. more than two SELECT statements, not counting SELECT inside aggregate functions). Since your query has single result set, OleDbDataReader.Read() must be used to move between records:
using (var con = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Checksheets.accdb;"))
{
using (var command = new OleDbCommand(query, con))
{
con.Open();
using (var reader = command.ExecuteReader())
{
// Only single result set, use 'Read' here
while (reader.Read())
{
sheets.Add(new FabChecksheet
{
OrderNum = reader.GetString(0),
PartNum = reader.GetString(1)
});
}
}
}
}
Note that if NextResult() is used, the data reader will move to next result set which has empty data.
Related issue:
Difference between SqlDataReader.Read and SqlDataReader.NextResult
C# SQLite Query
String sql = #"SELECT user FROM '" + channel + "' ORDER BY currency DESC LIMIT 10";
You have a problem with your query. The SELECT extracts only one column from the table represented by the variable channel. So your GetString(1) in the reader loop fails because there is no field at index 1 (arrays start at index zero). You need to change that GetString index.
Then there is a problem in the return value. You say that you want to return a single string but there is no return statement and you don't have any single string to return
You could write
public string top10()
{
List<string> toplist = new List<string>();
String sql = "SELECT user FROM '" + channel + "' ORDER BY currency DESC LIMIT 10";
using (cmd = new SQLiteCommand(sql, myDB))
{
using (SQLiteDataReader r = cmd.ExecuteReader())
{
while (r.Read())
{
toplist.Add(r.GetString(0));
}
}
}
return string.Join(",", toplist);
}
or change the return type of the method to
public List<string> top10()
{
.....
return toplist;
}
or to
public string[] top10()
{
.....
return toplist.ToArray();
}
I have changed your internal array to a List<string> because if you have less than 10 records your array will have empty strings instead a list will return just the rows found.
You may also try this answer.
public string getTop10()
{
List<string> Toplist = new List<string>();
string connection = "YourConnectionString";
using (var con = new SQLiteConnection { ConnectionString = connection })
{
using (var command = new SQLiteCommand { Connection = con })
{
con.Open();
command.CommandText = #"SELECT user FROM #channel ORDER BY currency DESC LIMIT 10";
command.Parameters.AddWithValue("#channel", channel);
using (var r = command.ExecuteReader())
{
while(r.Read())
{
Toplist.Add(r.GetString(0));
}
}
}
}
return string.Join(",", Toplist);
}
At the moment i have a textbox and a button and i can read the textbox fine and it searches the databse for say "apple"
but if there is a result called "red apple" it will not return it.
I have tried
string getTheBox = (this.searchBox.Text);
string request = "%" + getTheBox + "%";
But it doesn't seem to be working. This is with "request" being the string variable.
EDIT to include the SQL request part
SqlDataSource2.SelectCommand = "SELECT Recipe_Name FROM New_Recipe WHERE [ingredient1]=#request
SqlDataSource2.SelectParameters.Add(newParameter("request",System.TypeCode.String));
SqlDataSource2.SelectParameters["request"].DefaultValue = request;
The adding of % is correct, but you need to change your sql query
you need to use the LIKE operator
for example THE QUERY could be
"SELECT Recipe_Name FROM New_Recipe WHERE ingredient1 LIKE #request"
and your code
string request = "%" + getTheBox + "%";
string sqlText = "SELECT Recipe_Name FROM New_Recipe WHERE ingredient1 LIKE #request";
using(SqlConnection cn = GetSqlConnection())
{
cn.Open();
using(SqlCommand cmd = new SqlCommand(sqlText, cm);
{
cmd.Parameters.AddWithValue("#request", request);
SqlDataReader dr = cmd.ExecuteReader();
while(dr.Read())
{
......
}
}
}
Please post your SQL query too. Perhaps you need to change WHERE FruitName = #FruitName to WHERE FruitName LIKE #FruitName
This is a horrible idea, as anyone can run sql injection. You probably want something akin to
Sqlcommand.Prepare
As it will let you set safer arguements. And have two words.
I usually have a few helper functions to add like to my queries depending on what I need done.
public List<T> GetRecipesThatContain<T>(string ingredient)
{
const string commandText = "SELECT Recipe_Name FROM New_Recipe WHERE ingredient1 LIKE #SearchTerm";
var searchTerm = Contains(ingredient);
using(var connection = GetSqlConnection())
{
connection.Open();
using(var command = new SqlCommand(commandText, connection);
{
command.Parameters.AddWithValue("#SearchTerm", searchTerm);
using(var reader = command.ExecuteReader())
{
var results = new List<T>();
while(reader.Read())
{
// Get results
// results.Add(result);
}
return results;
}
}
}
}
private string StartsWith(string searchTerm)
{
return string.Format("{0}%", searchTerm);
}
private string EndsWith(string searchTerm)
{
return string.Format("%{0}", searchTerm);
}
private string Contains(string searchTerm)
{
return string.Format("%{0}%", searchTerm);
}
I tried below code for cheking SP is alredy exist or not. if not exist i am creating..
But every time it is showing sp is not created.....But my database already have this sp.
Let me know where i am doing mistake.
string checkSP = String.Format(
"IF OBJECT_ID('{0}', 'U') IS NOT NULL SELECT 'true' ELSE SELECT 'false'",
"GP_SOP_AdjustTax");
SqlCommand command = new SqlCommand(checkSP, myConnection);
command.CommandType = CommandType.Text;
if (myConnection == null || myConnection.State == ConnectionState.Closed)
{
try
{
myConnection.Open();
}
catch (Exception a)
{
MessageBox.Show("Error " + a.Message);
}
}
bool Exist = false;
Exist = Convert.ToBoolean(command.ExecuteScalar());
if (Exist == false) //false : SP does not exist
{
// here i am writing code for creating SP
}
Try:
if exists(select * from sys.objects where type = 'p' and name = '<procedure name>' )
Also you can check that with c#:
string connString = "";
string query = "select * from sysobjects where type='P' and name='MyStoredProcedureName'";
bool spExists = false;
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand command = new SqlCommand(query, conn))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
spExists = true;
break;
}
}
}
}
For those who use Entity Framework and a DbContext:
create an extension class for DbContext:
internal static class DbContextExtensions
{
public static bool StoredProcedureExists(this DbContext context,
string procedureName)
{
string query = String.Format(
#"select top 1 from sys.procedures " +
"where [type_desc] = '{0}'", procedureName);
return dbContext.Database.SqlQuery<string>(query).Any();
}
}
As robIII remarked, this code should not be published to the outside world as it makes the database vulnerable for hackers (thank you RobIII!). To prevent this use a parameterized statement. The problem with the above mentioned method is described here
The solution is to put procedureName as a parameter in an SQL statement. SQL will check if the string parameter has the desired format, thus inhibiting malicious calls:
public static bool ImprovedExists(this DbContext dbContext, string procedureName)
{
object[] functionParameters = new object[]
{
new SqlParameter(#"procedurename", procedureName),
};
const string query = #"select [name] from sys.procedures where name= #procedurename";
return dbContext.Database.SqlQuery<string>(query, functionParameters).Any();
}
I found this on MSDN
select * from sys.objects where type_desc = 'SQL_STORED_PROCEDURE' AND name = 'Sql_PersonInsert'
Try:
SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'GP_SOP_AdjustTax') AND type in (N'P', N'PC')
My stab at it:
Reusable extension method
Minimal Sql / Minimal C#
Called from .Net as the OP implicitly requested
Could be faster because of the object_id function
public static bool StoredProcedureExists(this string source)
{
using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
{
conn.Open();
using (var cmd = new SqlCommand($"select object_id('{source}')", conn))
return !cmd.ExecuteScalar().ToString().IsNullOrWhiteSpace();
}
}
You can check with following tsql query (suitable for SQL Server):
select * from sysobjects where ytype='P' and name='MyStoredProcedureName'
If query returns row then stored procedure named 'MyStoredProcedureName' exists.
And here is how you can use it in code:
//TODO: set connection string
string connString = "";
string query = "select * from sysobjects where ytype='P' and name='MyStoredProcedureName'";
bool spExists = false;
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand command = new SqlCommand(query,conn))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
spExists = true;
break;
}
}
}
}
string checkSP = String.Format(
"IF OBJECT_ID('{0}', 'U') IS NOT NULL SELECT 'true' ELSE SELECT 'false'",
"GP_SOP_AdjustTax");
is fine if you change the 'U' to 'P'.
With 'U' you query for user-tables, where 'P' gives you stored-procedures.
private static bool StoredProcedureExists(string sp)
{
var connString = #"<your string here>";
var query = string.Format("SELECT COUNT(0) FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = '{0}'", sp);
using (var conn = new SqlConnection(connString))
{
conn.Open();
using (var cmd = new SqlCommand(query, conn))
{
return Convert.ToInt32(cmd.ExecuteScalar()) > 0;
}
}
}
Handles procedure names with different schemas
Names with and without brackets ([])
Uses parameter to avoid SQL injection
Note: Caller owns SQL Connection
public static class SqlConnectionExtensions
{
public static Task<bool> StoredProcedureExistsAsync(this SqlConnection sqlConnection, string storedProcedureName)
{
string query = "SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(#storedProcedureName) AND type in (N'P', N'PC')";
using (SqlCommand command = new SqlCommand(query, sqlConnection))
{
command.Parameters.AddWithValue("#storedProcedureName", storedProcedureName);
using (SqlDataReader reader = command.ExecuteReader())
{
return reader.ReadAsync();
}
}
}
}
The following works with MySQL, SQL Server, and Oracle I think:
SELECT * FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_TYPE='PROCEDURE'
AND (ROUTINE_SCHEMA='questionnaire' OR ROUTINE_CATALOG = 'questionnaire')
AND SPECIFIC_NAME='create_question';
Usage:
string procedureName = "create_question";
using (DbConnection conn = new SqlConnection("Server=localhost;Database=questionnaire;Trusted_Connection=True;")) // Connection is interchangeable
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = $"SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE='PROCEDURE' AND (ROUTINE_SCHEMA='{conn.Database}' OR ROUTINE_CATALOG = '{conn.Database}') AND SPECIFIC_NAME='{procedureName}';";
return cmd.ExecuteScalar() != null;
}
}
If you use Microsoft.SqlServer.Management.Smo, try
private static bool CheckIfStoredProcedureExists(Database db, string spName, string schema)
{
db.StoredProcedures.Refresh();
return (db.StoredProcedures[spName, schema] != null);
}
Try this;
if object_id('YourStoredProcedureName') is null
exec ('create procedure dbo.YourSp as select 1')
go
alter procedure dbo.YourStoredProcedure
as