Is there a better way to get table structure? - c#

Is there a better way to fetch using a different SQL query?
Have also added the code snippet (though not really related to my question).
select * from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA =
'$schema_name$', TABLE_NAME='$table_name$';
public TableStructure GetTableStructure(string TableName, MySqlConnection Connection)
{
if (Connection == null)
throw new ArgumentNullException("Sql Connection should be initialized.");
string sqlQuery = #"select * from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '$schema_name$', TABLE_NAME='$table_name$'";
sqlQuery = sqlQuery.Replace("$table_name$", TableName);
sqlQuery = sqlQuery.Replace("$schema_name$", SchemaName);
TableStructure tableStructure = null;
try
{
using (MySqlCommand sqlCmd = new MySqlCommand(sqlQuery, Connection))
{
if (Connection.State == ConnectionState.Closed)
Connection.Open();
using (MySqlDataReader dr = sqlCmd.ExecuteReader())
{
while (dr.Read())
{
...
...
//tableStructure = TableStructure.GetTableStructureFromDataReader(TableName, dr);
}
}
}
}
catch (Exception)
{
//TODO
throw new Exception("Error occured while obtaining tables list");
}
return tableStructure;
}

A WHERE statement with multiple conditions requires an AND / OR to join the two conditions
string sqlQuery = #"select * from INFORMATION_SCHEMA.COLUMNS
where TABLE_SCHEMA = '$schema_name$' AND TABLE_NAME='$table_name$'";
And instead of using a REPLACE to set your string values (a dangerous practice if the input are typed directly by your end user) you could use a parameterized query
string sqlQuery = #"select * from INFORMATION_SCHEMA.COLUMNS
where TABLE_SCHEMA = #schema AND TABLE_NAME=#table";
using (MySqlCommand sqlCmd = new MySqlCommand(sqlQuery, Connection))
{
sqlCmd.Parameters.AddWithValue("#schema", SchemaName);
sqlCmd.Parameters.AddWithValue("#table", TableName);
.....

Related

Getting always FALSE as a result of Table Exists method using C# SQLClient MSSQL

I have the code like this for checking if database exists:
private bool CheckDatabase(string databaseName)
{
var connString = "Server=localhost\\SQLEXPRESS;Integrated Security = SSPI; database = master";
string cmdText = "select count(*) from master.dbo.sysdatabases where name=\'" + databaseName + "\'";
using (var sqlConnection = new SqlConnection(connString))
{
using (var sqlCmd = new SqlCommand(cmdText, sqlConnection))
{
sqlCmd.Parameters.Add(#"database", System.Data.SqlDbType.NVarChar).Value = databaseName;
sqlConnection.Open();
return Convert.ToInt32(sqlCmd.ExecuteScalar()) == 1;
}
}
}
EDIT:
I used the query from the comments but I am always getting false as a result:
public static bool CheckTableExists()
{
var connString = "Server=localhost\\SQLEXPRESS;Integrated Security = SSPI; database = master";
string cmdText = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = \'" + "databaseName" + "\' AND TABLE_NAME = \'" + "testingTable" + "\'";
using (var sqlConnection = new SqlConnection(connString))
{
using (var sqlCmd = new SqlCommand(cmdText, sqlConnection))
{
sqlCmd.Parameters.Add(#"database", System.Data.SqlDbType.NVarChar).Value = "databaseName";
sqlConnection.Open();
return Convert.ToInt32(sqlCmd.ExecuteScalar()) == 1;
}
}
}
You can check for tables existing in SQL pretty easily
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'myDatabase'
AND TABLE_NAME = 'myTable'
To get the list of databases (rather than tables):
select name from sys.databases
Another way is using a try .. catch like below, make a query against the table and catch the SqlException like
string cmdText = "select 1 from mytbl1";
using (var sqlConnection = new SqlConnection(connString))
{
using (var sqlCmd = new SqlCommand(cmdText, sqlConnection))
{
try
{
sqlConnection.Open();
return Convert.ToInt32(sqlCmd.ExecuteScalar()) == 1;
}
catch(SqlException ex)
{
}
}
}

Correct use of Try Catch for the SQL connection in C#

Is this code correct in means of Try/Catch? I need to value whether the action is done or not to inform the user about the result, so I will then get the bool value to know if connection was successful.
public static bool CreateSQLDatabaseTable()
{
var connString = "Server=localhost\\SQLEXPRESS;Integrated Security = SSPI; database = MyDB";
string cmdText = "SELECT count(*) as Exist from INFORMATION_SCHEMA.TABLES where table_name =#Product";
try
{
using (var sqlConnection = new SqlConnection(connString))
{
using (var sqlCmd = new SqlCommand(cmdText, sqlConnection))
{
sqlCmd.Parameters.Add("#Product", System.Data.SqlDbType.NVarChar).Value = "Product";
sqlConnection.Open();
sqlCmd.ExecuteScalar();
if ((int)sqlCmd.ExecuteScalar() != 1)
{
using (SqlCommand command = new SqlCommand("CREATE TABLE Product (Id INT, UserId TEXT, CreationDate TEXT, Name TEXT)", sqlConnection))
{
command.ExecuteNonQuery();
return true;
}
}
}
}
return false;
}
catch
{
return false;
}
}
Your method can actually have 3 outcomes:
The table was created successfully (method returns true)
The table already exists (method returns false)
There was an error trying to create the table (exception is thrown)
So you should handle the exception outside of this method and you should not blindly catch all Exceptions. You should only handle the SqlException so that other exceptions will not be handled. Also you should be logging the exception somewhere as a good practice.
For more information on the SqlException
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlexception(v=vs.110).aspx
public static bool CreateSQLDatabaseTable()
{
var connString = "Server=localhost\\SQLEXPRESS;Integrated Security = SSPI; database = MyDB";
string cmdText = "SELECT count(*) as Exist from INFORMATION_SCHEMA.TABLES where table_name =#Product";
using (var sqlConnection = new SqlConnection(connString))
{
using (var sqlCmd = new SqlCommand(cmdText, sqlConnection))
{
sqlCmd.Parameters.Add("#Product", System.Data.SqlDbType.NVarChar).Value = "Product";
sqlConnection.Open();
sqlCmd.ExecuteScalar();
if ((int)sqlCmd.ExecuteScalar() != 1)
{
using (SqlCommand command = new SqlCommand("CREATE TABLE Product (Id INT, UserId TEXT, CreationDate TEXT, Name TEXT)", sqlConnection))
{
command.ExecuteNonQuery();
return true;
}
}
}
}
return false;
}
public static void Main()
{
try
{
bool wasCreated = CreateSQLDatabaseTable();
}
catch (SqlException ex)
{
// Handle the SQL Exception as you wish
Console.WriteLine(ex.ToString());
}
}
I would solve such a problem through a single query that does the exists check itself and returns whether it was created or not.
public static bool CreateSQLDatabaseTable() {
var connString = "...";
const string tableName = "Product";
string cmdText = $"IF EXISTS (SELECT TOP(1) 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG = DB_NAME() AND TABLE_SCHEMA = 'dbo' AND TABLE_NAME = '{tableName}' AND TABLE_TYPE = 'BASE TABLE') BEGIN\r\n" +
$" SELECT CAST(0 AS BIT) AS CreatedNow\r\n" +
$"END ELSE BEGIN\r\n" +
$" CREATE TABLE dbo.{tableName}(Id INT, CreatorId INT, CreationDate DATETIME, CreationDateUtc DATETIME, Name NVARCHAR)\r\n" +
$" SELECT CAST(1 AS BIT) AS CreatedNow\r\n" +
$"END";
using (var sqlConnection = new SqlConnection(connString)) {
using (var sqlCmd = new SqlCommand(cmdText, sqlConnection)) {
sqlConnection.Open();
return (bool)sqlCmd.ExecuteScalar();
}
}
}

Check if two tables exist in database

I have database pavadinimas.mdf, which contains two tables: Vehicle and Repairs. I want to check if both tables exist in database. So, far I managed to check if one table exist, but how to check if both exist, if not create them.
Here is my code:
string tblnm = "Vehicle";
SqlConnection conn;
using (conn = new SqlConnection(connection))
{
conn.Open();
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
cmd.CommandText = #"IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME='" + tblnm + "') SELECT 1 ELSE SELECT 0"; ;
cmd.Connection = conn;
cmd.ExecuteNonQuery();
int x = Convert.ToInt32(cmd.ExecuteScalar());
conn.Close();
if (x == 2)
{
MessageBox.Show("Lentelės yra");
}
else
{
MessageBox.Show("Lenteliu nėra.Sukuriama");
}
I also have code which should create table. Here is code:
string table1 = "Repairs";
SqlConnection conn;
conn = new SqlConnection(connection);
conn.Open();
string createString = "CREATE TABLE [dbo].['" + table1 + "'](" + "[VIN] [nvarchar](50)," + "[Taisymas] [nvarchar](50)," + "[Kaina] [decimal](18, 2))";
SqlCommand sqlCmd = new SqlCommand(createString, conn);
sqlCmd.ExecuteNonQuery();
conn.Close();
But this code don't create table in my database. Then I call this method, it is saying that table already exist, but when I check tables in database it's nothing, empty...
Are you looking for something similar to:
IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='tbl1') AND EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='tbl2') SELECT 1 ELSE SELECT 0
How about using a parameter and looping through the tables?
conn.Open();
var cmd = new System.Data.SqlClient.SqlCommand(
#"SELECT count (*) FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME = #TABLE_NAME",
conn);
cmd.Parameters.Add("#TABLE_NAME", SqlDbType.VarChar);
List<String> tables = new List<string>() { "Vehicles", "Repairs" };
foreach (string tableName in tables)
{
cmd.Parameters[0].Value = tableName;
int x = Convert.ToInt32(cmd.ExecuteScalar());
if (x == 0)
CreateTable(tableName, conn);
}
conn.Close();
-- EDIT --
CreateTable method was added above, and the code would look something like this. Caveat -- this is EXTREMELY brute force, but in the absence of other information, is is one way to accomplish the task, as I best understand your issue.
private void CreateTable(String TableName, System.Data.SqlClient.SqlConnection conn)
{
StringBuilder sql = new StringBuilder(#"create table [");
sql.Append(TableName);
sql.AppendLine(#"] (");
switch (TableName)
{
case "Vehicle":
sql.AppendLine("[VIN] varchar(100),");
sql.AppendLine("[Manufacturer] varchar(100),");
sql.AppendLine("[Model] varchar(100),");
sql.AppendLine("[Year] integer");
break;
case "Repair":
sql.AppendLine("[VIN] varchar(100),");
sql.AppendLine("[Correction] varchar(100),");
sql.AppendLine("[Price] decimal");
break;
}
sql.Append(")");
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(
sql.ToString, conn);
try
{
cmd.ExecuteNonQuery();
MessageBox.Show("Created Table " + TableName);
}
catch (Exception ex)
{
MessageBox.Show("Oops, I did it again");
}
}
Wrap it in a for loop
for(int i = 0; i < 2; i++){
if (i = 0)
{
string tblnm = "Vehicle";
}
else
{
string tblnm = "Repairs";
}
SqlConnection conn;
using (conn = new SqlConnection(connection))
{
conn.Open();
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
cmd.CommandText = #"IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME='" + tblnm + "') SELECT 1 ELSE SELECT 0"; ;
cmd.Connection = conn;
cmd.ExecuteNonQuery();
int x = Convert.ToInt32(cmd.ExecuteScalar());
conn.Close();
if (x == 2)
{
MessageBox.Show("Lentelės yra");
}
else
{
MessageBox.Show("Lenteliu nėra.Sukuriama");
}
}

Reader not showing any data on search?

I n this sample of code when the execution get there on the while(reader.read()) part.. it not enters the loop and shows there is not any data for this query. I have tried the commented things in it.. that too doesn't worked out. suggest me what's wrong in this code?
string constr = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection connection = new SqlConnection(constr))
{
connection.Open();
SqlCommand command = new SqlCommand("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =" + " '" + "#TableName" + "'", connection);
// SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'ActivityIndex';
command.Parameters.Add("#TableName", SqlDbType.NVarChar).Value = listSelectTable.Text;
//SqlCommand command = new SqlCommand();
//command.CommandType = CommandType.Text;
//command.Connection = connection;
//command.CommandText = String.Format("SELECT [column_name] FROM information_schema.columns WHERE table_name = '{0}'", listSelectTable.Text);
/*using (command)
{*/
listSelectColumn.Items.Clear();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
listSelectColumn.Items.Add((string)reader["COLUMN_NAME"]);
}
listSelectColumn.Items.Add("ALL");
}
/*}*/
connection.Close();
}
When you pass parameter separately no need to decorate.
string constr = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection connection = new SqlConnection(constr))
{
connection.Open();
SqlCommand command = new SqlCommand("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =#TableName", connection);
command.Parameters.Add("#TableName", SqlDbType.NVarChar).Value = listSelectTable.Text;
listSelectColumn.Items.Clear();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
listSelectColumn.Items.Add((string)reader["COLUMN_NAME"]);
}
listSelectColumn.Items.Add("ALL");
}
connection.Close();
}
Try modifying your code as follows
SqlCommand command = new SqlCommand("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #TableName" , connection);
command.Parameters.Add("#TableName", SqlDbType.NVarChar);
command.Parameters["#TableName"].Value = listSelectTable.Text;
Try this:-
SqlCommand command = new SqlCommand("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME =#TableName", connection);
There is no need to add quotes in your query, since you are specifying that in command parameters. Also, no need to use your commented code since you are aleady specifying Connection' & 'CommandType is Text by default.

Retrieving total count from database to c#

This query is been executed in database.
select COUNT(*) from Patient_Data where DummyValue = 'Y';
104
I have to retrieve this number (104) from database to asp.net with c# so that when the count becomes zero I have to disable a button, How to retrieve this number from database into the code. It should be stored as integer.
I have tried these line of code in c#
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("select COUNT(*) as PatientCount from Patient_Data where DummyValue = 'Y' ", cn))
{
try
{
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
int Patcount;
if (rdr.Read())
{
//Code Required
}
}
}
catch (Exception ex)
{
// handle errors here
}
}
}
use alias to get the count as below:
select COUNT(*) as PatientCount from Patient_Data where DummyValue = 'Y';
Read the PatientCount value in code.
you can use GetInt32() function to get the count as int.
Note: you are passing the parameter values in your query which leads to Sql Injection Attacks, so you could use Parameterized Sql Queries to avoid them.
sample code is asbelow:
private int readPatientData()
{
int PatientCount = 0;
String strCommand = "select COUNT(*) as PatientCount from Patient_Data where DummyValue = #MyDummyValue";
using (SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString))
{
sqlConnection.Open();
using (SqlCommand sqlcommand=new SqlCommand(strCommand,sqlConnection))
{
sqlcommand.Parameters.Add(new SqlParameter("MyDummyValue", 'Y'));
SqlDataReader sqlReader = sqlcommand.ExecuteReader();
if (sqlReader.Read())
PatientCount = sqlReader.GetInt32(0);
}
}
return PatientCount;
}
I solved my issue with these lines of code.
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("select COUNT(*) as PatientCount from Patient_Data where DummyValue = 'Y' ", cn))
{
try
{
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
//int Patcount;
if (rdr.Read())
{
int Patcount = int.Parse(rdr["PatientCount"].ToString());
if (Patcount != 0)
{
Label3.Visible = true;
Label3.Text = "You have already have "+Patcount+" dummy records,Please update those records by clicking Update Dummy Records Link.";
btnSkipSubmit.Visible = false;
}
//Code Required
}
}
}
catch (Exception ex)
{
// handle errors here
}
}
}
Update based on code change in question
You can write rdr.GetInt32(3); instead of code required in your code.
previous answer
You need to use ExecuteScalar method while executing your command. Here is the example from msdn:
static public int AddProductCategory(string newName, string connString)
{
Int32 newProdID = 0;
string sql =
"INSERT INTO Production.ProductCategory (Name) VALUES (#Name); "
+ "SELECT CAST(scope_identity() AS int)";
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.Add("#Name", SqlDbType.VarChar);
cmd.Parameters["#name"].Value = newName;
try
{
conn.Open();
newProdID = (Int32)cmd.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
return (int)newProdID;
}
In this example they are returning newly added product Id.
ExecuteScalar returns object that you can check for null and cast to number as you know with int.parse method or the best one you know.
As Per my knowledge there are three ways to do this:
Using COUNT you can do this as below:
select COUNT(*) as RowCount from Patient_Data where DummyValue = 'Y';
Using ROW_NUMBER you can do this as below:
Select ROW_NUMBER() OVER (ORDER BY Patient_Data.ID DESC) AS RowNumber from Patient_Data where DummyValue = 'Y';
And there is another way but that way is only to get the row count and is the fastest way to get the row count in sql server according to me.
SELECT
Total_Rows= SUM(st.row_count)
FROM
sys.dm_db_partition_stats st
WHERE
object_name(object_id) = 'Patient_Data' AND (index_id < 2)
That's all

Categories