how to Sql Table Data using in switch statement? - c#

I have a table in the SQL database with two columns. I want to use that data in a switch case loop as
switch(Inputvalue) {
case row1.column1:
return row1.column2;
case row2.column1:
return row2.column2;
.
.
.
case rowN.column1:
return rowN.column2;
}
if possible in view using javascript or else in controller using c#
so the program for switch loop is like
switch(Inputvalue) {
case 1:
return Hyderabad;
case 2:
return Chennai;
case 3:
return Banglore;

The question is strange, basically you are asking for a method that returns the name of a city from your table with a given ID. So why don't you use sql as tagged? Presuming sql-server:
public static string GetCityName(int cityId)
{
string sql = "SELECT Name FROM City WHERE Id = #Id";
using(var con = new SqlConnection("Insert Your Connection String"))
{
using(var cmd = new SqlCommand(sql, con))
{
con.Open();
cmd.Parameters.Add("Id", SqlDbType.Int).Value = cityId;
string name = (string) cmd.ExecuteScalar();
return name;
}
}
}

i think it is useful for you
CASE expression
WHEN value_1 THEN result_1
WHEN value_2 THEN result_2
...
WHEN value_n THEN result_n
ELSE result
END

There is no way to do it with Switch-Case, instead of it you can use dictionary for lookup like below:
var lookUp = yourDataTable.AsEnumrable().ToDictionary(r => r.column1, k => k.column2);
var result = lookUp[value];

Related

Read all record in sql table using SqlDataReader

I want to read all records from "product" table and create objects from each records.
it only gets one records from the database, any ideas might help ?
public IReadOnlyList<Product> Search(string name)
{
var result = new List<Product>();
using (var conn = new SqlConnection(connectionString))
{
if (name == null)
{
var command = new SqlCommand("SELECT * FROM Product ", conn);
conn.Open();
using var reader = command.ExecuteReader();
{
while (reader.Read())
{
var prod = new Product((int)reader["ID"], (string)reader["Name"],
(double)reader["Price"], (int)reader["Stock"], (int)reader["VATID"],
(string)reader["Description"]);
result.Add(prod);
reader.NextResult();
}
reader.Close();
conn.Close();
return result;
};
}
}
If you have several result sets, you should loop over them, i.e. you should put one more outer loop, e.g.
using var reader = command.ExecuteReader();
do {
while (reader.Read()) {
var prod = new Product(
Convert.ToInt32(reader["ID"]),
Convert.ToString(reader["Name"]),
Convert.ToDouble(reader["Price"]), // decimal will be better for money
Convert.ToInt32(reader["Stock"]),
Convert.ToInt32(reader["VATID"]),
Convert.ToString(reader["Description"])
);
result.Add(prod);
}
}
while (reader.NextResult());
Note outer do .. while loop since we always have at least one result set.
You use NextResult which advances the reader to the next result set. This makes sense if you have multiple sql queries and you'd use it after the while-loop. Here it's just unnecessary and wrong.
You are already advancing the reader to the next record with Read.
If I get rid of it, this error occur : Unable to cast object of type
'System.DBNull' to type 'System.String.
You can use IsDBNull:
int nameIndex = reader.GetOrdinal("Name");
string name = reader.IsDBNull(nameIndex) ? null : reader.GetString(nameIndex);
int descIndex = reader.GetOrdinal("Description");
string description = reader.IsDBNull(descIndex) ? null : reader.GetString(descIndex);
var prod = new Product((int)reader["ID"],
name,
(double)reader["Price"],
(int)reader["Stock"],
(int)reader["VATID"],
description);
Use it for every nullable column, for the numeric columns you could use nullable types like int?.
You have an error in your code:
Remove the line reader.NextResult();
NextResult is used for moving to next result set not next record.
Definitely remove the NextResult(). That does NOT move between individual records in the same query. Read() does this for you already. Rather, NextResult() allows you to include multiple queries in the same CommandText and run them all in one trip to the database.
Try this:
public IEnumerable<Product> Search(string name)
{
using (var conn = new SqlConnection(connectionString))
using (var command = new SqlCommand("SELECT * FROM Product ", conn))
{
if (!string.IsNullOrEmpty(name) )
{
command.CommandText += " WHERE Name LIKE #Name + '%'";
command.Parameters.Add("#Name", SqlDbType.NVarChar, 50).Value = name;
}
conn.Open();
using var reader = command.ExecuteReader();
{
while (reader.Read())
{
var prod = new Product((int)reader["ID"], reader["Name"].ToString(),
(double)reader["Price"], (int)reader["Stock"], (int)reader["VATID"],
reader["Description"].ToString());
yield return prod;
}
}
}
}

If the SELECT SQL Server value is null, the query takes 5 minutes C #

I have a very silly problem. I am doing a select, and I want that when the value comes null, return an empty string. When there is value in sql query, the query occurs all ok, but if there is nothing in the query, I have to give a sqlCommand.CommandTimeout greater than 300, and yet sometimes gives timeout. Have a solution for this?
public string TesteMetodo(string codPess)
{
var vp = new Classe.validaPessoa();
string _connection = vp.conString();
string query = String.Format("SELECT COUNT(*) FROM teste cliente WHERE cod_pess = {0}", codPess);
try
{
using (var conn = new SqlConnection(_connection))
{
conn.Open();
using (var cmd = new SqlCommand(query, conn))
{
SqlDataReader dr = cmd.ExecuteReader();
if(dr.HasRows)
return "";
return codPess;
}
}
}
You should probably validate in the UI and pass an integer.
You can combine the usings to a single block. A bit easier to read with fewer indents.
Always use parameters to make the query easier to write and avoid Sql Injection. I had to guess at the SqlDbType so, check your database for the actual type.
Don't open the connection until directly before the .Execute. Since you are only retrieving a single value you can use .ExecuteScalar. .ExecuteScalar returns an Object so must be converted to int.
public string TesteMetodo(string codPess)
{
int codPessNum = 0;
if (!Int32.TryParse(codPess, out codPessNum))
return "codPess is not a number";
var vp = new Classe.validaPessoa();
try
{
using (var conn = new SqlConnection(vp.conString))
using (var cmd = new SqlCommand("SELECT COUNT(*) FROM teste cliente WHERE cod_pess = #cod_pess", conn))
{
cmd.Parameters.Add("#cod_pess", SqlDbType.Int).Value = codPessNum;
conn.Open();
int count = (int)cmd.ExecuteScalar();
if (count > 0)
return "";
return codPess;
}
}
catch (Exception ex)
{
return ex.Message;
}
}

SQLite code optimization

I am a hobbyist programmer and writing a reporting tool to export values from an SQLite database to Excel.
The Excel part is written and working, the data I am retrieving from SQLite is creating a block in the program and taking several minutes to process.
I have rewritten the code out using generic values to help illustrate the processes. The initial populateList module is taking a negligible amount of time, but I have included it below as that is the providing the data for the doStuff module. The populateList currently retrieves approximately 500 distinct records.
I need the program to iterate through all the values retrieved by the populateList and do several counts. It is then populating another list valuesCount with the counted values.
I tried to improve the speed by looping through the list without closing the SQLite connection, but the improvement wasn't enough. Is there a more efficient way to retrieve this information from the databse?
public list<string>populateList()
{
List<string>values = new list<string>();
using (SQLiteConnection con = new SQLiteConnection(Passer.connstr))
{
con.Open();
string distinctValues = "SELECT DISTINCT \"value list\" FROM valueTable order by \"value list\" ";
using (SQLiteCommand cmd = new SQLiteCommand(distinctValues, con))
{
SQLiteDataReader sqReader;
sqReader = cmd.ExecuteReader();
while (sqReader.Read())
{
values.Add(sqReader["value list"].ToString());
}
}
}
return values;
}
public void doStuff()
{
bool blanks = false;
string singleValue = string.Empty
string query = string.Empty;
List<string> getInitialValues = populateList();
list<string> valuesCount = new list<string>();
using (SQLiteConnection con = new SQLiteConnection(Passer.connstr))
{
con.Open();
for(int i = 0; i < getInitialValues.Count; i++)
{
blanks = false;
singleValue = getInitialValues[i];
if(singlevalue == "")
{
singleValue = \"\";
blanks = true;
}
for (int x = 0; x < 6; x++)
{
string statement = string.Empty;
switch(x)
{
case 0:
statement = "SELECT COUNT(*) from valueTable where \"column1\" = ";
break;
case 1:
statement = "SELECT COUNT(*) from valueTable where \"column2\" = \"condition 1\" and \"column1\" = ";
break;
case 2:
statement = "SELECT COUNT(*) from valueTable where \"column3\" = \"condition 3\" and \"column1\" = ";
break;
case 3:
statement = "SELECT COUNT(*) from valueTable where \"column4\" = \"condition 4\" and \"column1\" = ";
break;
case 4:
statement = "SELECT COUNT(*) from valueTable where \"column5\" = \"condition 5\" and \"column1\" = ";
break;
case 5:
statement = "SELECT COUNT(*) from valueTable where \"column6\" = \"condition 6\" and \"column1\" = ";
break;
}
if (blanks == true)
{
query = System.String.Format("{0}{1}", statement, singleValue);
}
else
{
query = System.string.format("{0}\"{1}\"", statement, singleValue);
}
using (SQLiteCommand cmd = new SQLiteCommand(query, con))
{
string countValues = cmd.ExecuteScalar().ToString();
valuesCount.Add(countValues);
}
}
}
}
}
Consider writing it as a single SQL query.
You are performing many queries when it very much looks like you simply need to perform a 'conditional count' on the columns. The SQL would be along the lines of
select
val,
col1 = sum(case when col1 = 'cond1' then 1 end)
from valtbl
group by val
you wouldn't even need the first method to get the list of distinct values.
Alternatively as the table seems reasonably small select what you need into a list of 'rows' and use Linq to Objects to do the counts.
You are querying the database multiple times to get the same information.
I would suggest not to do any db calls on dostuff method, rather use a single query for fetch the records form valuetable.
then you can do the count operations on the list itself.
For example get
"SELECT 'valueCol' , 'col1', 'col2' from valueTable"
would be your only query and you would store it in a list(say valueList).
Then on C# side you can use
//not actual code just a sample idea
var distinctValues = valueList.select(v => w.valueCol).Distinct()
var count = 0;
switch(case):
case 0:
count += valueList.where(v => v.col1 == condition).Count();
break; //and so on...

Create a list of distinct values from a gridview

Right now I have code that gets the distinct value from running SQL code on a table. I now use a stored proc to fill my Gridview instead of pulling from a table and can't do select distinct on a table since it's not there. I wanted to know if someone could point me in the right direction to create my list by using the values of a gridview.
Here is the current code I want to switch.
connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ToString());
string strSQL = string.Empty;
switch (strColumnName)
{
case "SiteID":
strSQL = #"SELECT distinct SiteID, SiteID FROM Sites ";
break;
case "OrderDate":
strSQL = #"SELECT distinct OrderDate, CONVERT(VARCHAR(11), OrderDate, 106) AS [OrderDate] FROM Sites ";
break;
}
SqlCommand command = new SqlCommand();
command.CommandText = strSQL;
command.Connection = connection;
command.Connection.Open();
SqlDataReader dataReader = command.ExecuteReader(CommandBehavior.CloseConnection);
IList<FilterValueSet> filterValueList = new List<FilterValueSet>();
while (dataReader.Read())
{
filterValueList.Add(new FilterValueSet
{
Id = dataReader[0].ToString(),
Value = dataReader[1].ToString()
});
}
connection.Close();
return filterValueList.ToArray<FilterValueSet>();
You can use Linq Distinct() method to filter the results like
return filterValueList.Distinct(equalityComparer).ToArray();
You need to provide an equality comparer for your FilterValueSet class, something in this way:
class MyEqualityComparer : EqualityComparer<FilterValueSet>
{
public override int GetHashCode(FilterValueSet obj)
{
return obj.Id.GetHashCode();
}
public override bool Equals(T x, T y)
{
return x.Id.Equals(y.Id);
}
}

Check if Database Exists Before Creating

This seems pretty trivial, but it is now frustrating me.
I am using C# with SQL Server 2005 Express.
I am using the following code. I want to check if a database exists before creating it. However, the integer returned is -1 and this is how MSDN defines what ExecuteNonQuery() will return as well. Right now, the database does exist but it still returns -1. Having said that, how can I make this work to get the desired result?
private static void checkInventoryDatabaseExists(ref SqlConnection tmpConn, ref bool databaseExists)
{
string sqlCreateDBQuery;
try
{
tmpConn = new SqlConnection("server=(local)\\SQLEXPRESS;Trusted_Connection=yes");
sqlCreateDBQuery = "SELECT * FROM master.dbo.sysdatabases where name =
\'INVENTORY\'";
using (tmpConn)
{
tmpConn.Open();
tmpConn.ChangeDatabase("master");
using (SqlCommand sqlCmd = new SqlCommand(sqlCreateDBQuery, tmpConn))
{
int exists = sqlCmd.ExecuteNonQuery();
if (exists <= 0)
databaseExists = false;
else
databaseExists = true;
}
}
}
catch (Exception ex) { }
}
As of SQL Server 2005, the old-style sysobjects and sysdatabases and those catalog views have been deprecated. Do this instead - use the sys. schema - views like sys.databases
private static bool CheckDatabaseExists(SqlConnection tmpConn, string databaseName)
{
string sqlCreateDBQuery;
bool result = false;
try
{
tmpConn = new SqlConnection("server=(local)\\SQLEXPRESS;Trusted_Connection=yes");
sqlCreateDBQuery = string.Format("SELECT database_id FROM sys.databases WHERE Name
= '{0}'", databaseName);
using (tmpConn)
{
using (SqlCommand sqlCmd = new SqlCommand(sqlCreateDBQuery, tmpConn))
{
tmpConn.Open();
object resultObj = sqlCmd.ExecuteScalar();
int databaseID = 0;
if (resultObj != null)
{
int.TryParse(resultObj.ToString(), out databaseID);
}
tmpConn.Close();
result = (databaseID > 0);
}
}
}
catch (Exception ex)
{
result = false;
}
return result;
}
This will work with any database name you pass in as a parameter, and it will return a bool true = database exists, false = database does not exist (or error happened).
Reading this a few years on and there's a cleaner way of expressing this:
public static bool CheckDatabaseExists(string connectionString, string databaseName)
{
using (var connection = new SqlConnection(connectionString))
{
using (var command = new SqlCommand($"SELECT db_id('{databaseName}')", connection))
{
connection.Open();
return (command.ExecuteScalar() != DBNull.Value);
}
}
}
shouldn't this
"SELECT * FROM master.dbo.sysdatabases where name = \'INVENTORY\'"
be this?
"SELECT * FROM master.dbo.sysdatabases where name = 'INVENTORY'"
Also According to MSDN
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. When a trigger exists on a table being inserted or updated, the return value includes the number of rows affected by both the insert or update operation and the number of rows affected by the trigger or triggers. For all other types of statements, the return value is -1. If a rollback occurs, the return value is also -1.
You are doing a SELECT not an DML statement. Why don't you use a ExecuteReader method instead?
An alternative to querying the system views is to use the function db_id which returns the Id of the database if it exists, otherwise null. Example T-SQL below:
if (db_id('INVENTORY') is null)
begin
return 0
end
else
begin
return 1
end
Took Stephen Lloyd's code and added some async and sql injection mitigation.
public static async Task<bool> TestDatabase(string connectionString, string databaseName)
{
using (var connection = new SqlConnection(connectionString))
using (var command = new SqlCommand("SELECT db_id(#databaseName)", connection))
{
command.Parameters.Add(new SqlParameter("databaseName", databaseName));
connection.Open();
return (await command.ExecuteScalarAsync() != DBNull.Value);
}
}
You can't use ExecuteNonQuery because it will always return -1 for SELECT, as the MSDN link shows.
You'll have to use process a resultset eg SELECT DB_ID('INVENTORY') AS DatabaseID or use a variable/parameter: SELECT #DatabaseID = DB_ID('INVENTORY')
For the benefit of searchers, if you are using Entity Framework, this will work:
using (var ctx = new MyDataModel())
{
dbExists = System.Data.Entity.Database.Exists(ctx.Database.Connection);
}
Use this Assembly: Microsoft.SqlServer.SqlManagementObjects => NuGet
using Microsoft.SqlServer.Management.Smo;
var dbExists = new Server(serverOrInstanceName).Databases.Contains(dataBaseName);

Categories