How to count columns of SQL Server 2008's table using C#? - c#

I am developing an application in C# in Visual Studio 2008. I connected a SQL Server 2008 database with it.
I want to count the number of columns so that I can loop around them to get the particular data.
I can figure it out columns by going to the database but I am joing 4-5 tables in my programs so I want to know if I can count the columns.
Can anyone help me in this?
Thank you
Shyam

select count(*) from INFORMATION_SCHEMA.columns where TABLE_NAME = 'YourTableName'

Something like this ?
SELECT COUNT(*)
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
WHERE t.name = 'yourTable'
See this page provided wy TaronPro to know how to retrieve the result.

If you are using SQLConnection object to connect to DB, use its GetSchema method to get list of all columns without querying.
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Connect to the database then retrieve the schema information.
connection.Open();
DataTable table = connection.GetSchema("Tables");
..
..
..
If you want to know columns for specific owner, table or table type, use restriction within GetSchema method.
string[] restrictions = new string[4];
restrictions[1] = "dbo";
DataTable table = connection.GetSchema("Tables", restrictions);
for more information refer this link.

What I did in a similar situation is that when I executed the query I retrieved all the data into a DataSet.
When I got the DataSet I opened the first table (ds.Tables[0]). Obviously you check first for existance.
When you have the table then its as simple as performing a
dt.Columns.Count;
In summary DS.Tables[0].Columns.Count
To find a specific column by name you loop through and find the one that
for (z=0; z < dt.Columns.Count; z++)
{
// check to see if the column name is the required name passed in.
if (dt.Columns[z].ColumnName == fieldName)
{
// If the column was found then retrieve it
//dc = dt.Columns[z];
// and stop looking the rest of the columns
requiredColumn = z;
break;
}
}
Then to find the data you need I would then loop through the rows of the table and get the field for that column...
ie...
string return = dr.Field<string>(requiredColumn);
Probalby not the best way of doing it but it works. Obviously if the data contained in the field is not string then you need to pass the appropriate type...
dr.Field<decimal>(requiredColumn)
dr.Field<int>(requiredColumn)
etc
Rgds
George

The reader itself gives you the number of columns. This is useful when you don't want to know the number rows of a specific table or view but from an ad-hoc query.
You can dump the columns like this
string sql = "SELECT * FROM my query";
SqlCommand cmd = new SqlCommand(sql, connection);
using (SqlDataReader reader = cmd.ExecuteReader()) {
while (reader.Read()) {
for (int i = 0; i < reader.FieldCount; i++) {
Console.WriteLine("{0} = {1}",
reader.GetName(i),
reader.IsDBNull(i) ? "NULL" : reader.GetValue(i));
}
Console.WriteLine("---------------");
}
}

you can use Microsoft.SqlServer.Management.Smo namespace to get the number of columns in a specified table as follows
1 . add Microsoft.SqlServer.Management.Smo dll in your project and use the namespace Microsoft.SqlServer.Management.Smo
2 . write the follwing code
private int colCount()
{
Server server=new Server(".\\SQLEXPRESS");
Database database=Server.Databases["your database name"];
Table table=database.Tables["your table name"];
return (table.Columns.Count);
}

Related

Why can I not get the names of my tables using System.Data.SqlClient?

I did not create and do not own this database. My job is usually just to put data in it, so I don't have to think too much about the DBA side. I am messing with a side project and can not figure out why I can't list all the table names. I have found several methods to gather this information, but none work for me in a c# context. I get 0 rows back every time. They do work when executed as queries in azure data studio. I get 99 rows back (the correct number of tables) no matter which method I use to enumerate the tables. My connection string specifies the database to use within the server.
The query named workingQuery returns the expected information (1 row with 15 fields). So I know my connection string is correct and my code is functional.
I have a test function that I am trying many queries on.
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
List<string> fields = new List<string>();
string workingQuery = "SELECT TOP (1) * FROM myRealTable";
string failingTablesQuery1 = "SELECT name FROM sysobjects WHERE xtype = 'U'";
string failingTablesQuery2 = "SELECT name AS table_name FROM sys.tables GO";
string failingTablesQuery3 = "SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_TYPE = 'BASE TABLE'";
using (var command = conn.CreateCommand())
{
command.CommandText = workingQuery;
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
for (int i = 0; i < reader.FieldCount; i++)
{
fields.Add(reader[i].ToString());
}
conn.Close();
return fields;
}
}
In addition to the raw sql queries I have also tried SqlConnection.GetSchema("Tables"). It also returns no rows.
I tried prepending USE myDatabaseName; to the front of the queries to no effect.
I can only assume this is an issue with the way the database is set up. Can anyone help me track down what is causing this issue?
SOLUTION:
My connection string had credentials that did not have the necessary permissions for this operation.
In SQL Server access to metadata is controlled by the VIEW DEFINITION permission. You might have permission to SELECT from a table, but not to view its definition or discover it in the catalog. By default any permission on an object implies VIEW DEFINITION, but it can be DENY'd to a user. See Metadata Visibility Configuration.
So check that you're using the same identity in both places and that that identity has VIEW DEFINITION permissions on the tables.

Batch insert to SQL Server table from DataTable using ODBC Connection

I have been asked to look at finding the most efficient way to take a DataTable input and write it to a SQL Server table using C#. The snag is that the solution must use ODBC Connections throughout, this rules out sqlBulkCopy. The solution must also work on all SQL Server versions back to SQL Server 2008 R2.
I am thinking that the best approach would be to use batch inserts of 1000 rows at a time using the following SQL syntax:
INSERT INTO dbo.Table1(Field1, Field2)
SELECT Value1, Value2
UNION
SELECT Value1, Value2
I have already written the code the check if a table corresponding to the DataTable input already exists on the SQL Server and to create one if it doesn't.
I have also written the code to create the INSERT statement itself. What I am struggling with is how to dynamically build the SELECT statements from the rows in the data table. How can I access the values in the rows to build my SELECT statement? I think I will also need to check the data type of each column in order to determine whether the values need to be enclosed in single quotes (') or not.
Here is my current code:
public bool CopyDataTable(DataTable sourceTable, OdbcConnection targetConn, string targetTable)
{
OdbcTransaction tran = null;
string[] selectStatement = new string[sourceTable.Rows.Count];
// Check if targetTable exists, create it if it doesn't
if (!TableExists(targetConn, targetTable))
{
bool created = CreateTableFromDataTable(targetConn, sourceTable);
if (!created)
return false;
}
try
{
// Prepare insert statement based on sourceTable
string insertStatement = string.Format("INSERT INTO [dbo].[{0}] (", targetTable);
foreach (DataColumn dataColumn in sourceTable.Columns)
{
insertStatement += dataColumn + ",";
}
insertStatement += insertStatement.TrimEnd(',') + ") ";
// Open connection to target db
using (targetConn)
{
if (targetConn.State != ConnectionState.Open)
targetConn.Open();
tran = targetConn.BeginTransaction();
for (int i = 0; i < sourceTable.Rows.Count; i++)
{
DataRow row = sourceTable.Rows[i];
// Need to iterate through columns in row, getting values and data types and building a SELECT statement
selectStatement[i] = "SELECT ";
}
insertStatement += string.Join(" UNION ", selectStatement);
using (OdbcCommand cmd = new OdbcCommand(insertStatement, targetConn, tran))
{
cmd.ExecuteNonQuery();
}
tran.Commit();
return true;
}
}
catch
{
tran.Rollback();
return false;
}
}
Any advice would be much appreciated. Also if there is a simpler approach than the one I am suggesting then any details of that would be great.
Ok since we cannot use stored procedures or Bulk Copy ; when I modelled the various approaches a couple of years ago, the key determinant to performance was the number of calls to the server. So batching a set of MERGE or INSERT statements into a single call separated by semi-colons was found to be the fastest method. I ended up batching my SQL statements. I think the max size of a SQL statement was 32k so I chopped up my batch into units of that size.
(Note - use StringBuilder instead of concatenating strings manually - it has a beneficial effect on performance)
Psuedo-code
string sqlStatement = "INSERT INTO Tab1 VALUES {0},{1},{2}";
StringBuilder sqlBatch = new StringBuilder();
foreach(DataRow row in myDataTable)
{
sqlBatch.AppendLine(string.Format(sqlStatement, row["Field1"], row["Field2"], row["Field3"]));
sqlBatch.Append(";");
}
myOdbcConnection.ExecuteSql(sqlBatch.ToString());
You need to deal with batch size complications, and formatting of the correct field data types in the string-replace step, but otherwise this will be the best performance.
Marked solution of PhillipH is open for several mistakes and SQL injection.
Normally you should build a DbCommand with parameters and execute this instead of executing a self build SQL statement.
The CommandText must be "INSERT INTO Tab1 VALUES ?,?,?" for ODBC and OLEDB, SqlClient needs named parameters ("#<Name>").
Parameters should be added with the dimensions of underlaying column.

Checking and Saving/Loading from MySQL C#

I am making something that requires MySQL. I have the saving done from in-game, which is simply done by INSERT.
I have a column that will have a password in and I need to check if the inputted password matched any of the rows and then if it is, get all of the contents of the row then save it to variables.
Does anyone have an idea how to do this in C#?
//////////////////////////
I have found how to save and get the string, however it will only get 1 string at a time :(
MySql.Data.MySqlClient.MySqlCommand command = conn.CreateCommand();
command.CommandText = "SELECT * FROM (player) WHERE (pass)";
command.ExecuteNonQuery();
command.CommandType = System.Data.CommandType.Text;
MySql.Data.MySqlClient.MySqlDataReader reader = command.ExecuteReader();
reader.Read();
ayy = reader.GetString(1);
print (ayy);
if(ayy == password){
//something
}
My best practice is to use MySQLDataAdapter to fill a DataTable. You can then iterate through the rows and try to match the password.
Something like this;
DataTable dt = new DataTable();
using(MySQLDataAdapter adapter = new MySQLDataAdaper(query, connection))
{
adapter.Fill(dt);
}
foreach(DataRow row in dt.Rows)
{
//Supposing you stored your password in a stringfield in your database
if((row.Field<String>("columnName").Equals("password"))
{
//Do something with it
}
}
I hope this compiles since I typed this from my phone. You can find a nice explanation and example here.
However, if you are needing data from a specific user, why not specificly ask it from the database? Your query would be like;
SELECT * FROM usercolumn WHERE user_id = input_id AND pass = input_pass
Since I suppose every user is unique, you will now get the data from the specific user, meaning you should not have to check for passwords anymore.
For the SQL statement, you should be able to search your database as follows and get only the entry you need back from it.
"SELECT * FROM table_name WHERE column_name LIKE input_string"
If input_string contains any of the special characters for SQL string comparison (% and _, I believe) you'll just have to escape them which can be done quite simply with regex. As I said in the comments, it's been a while since I've done SQL, but there's plenty of resources online for perfecting that query.
This should then return the entire row, and if I'm thinking correctly you should be able to then put the entire row into an array of objects all at once, or simply read them string by string and convert to values as needed using one of the Convert methods, as found here: http://msdn.microsoft.com/en-us/library/system.convert(v=vs.110).aspx
Edit as per Prix's comment: Data entered into the MySQL table should not need conversion.
Example to get an integer:
string x = [...];
[...]
var y = Convert.ToInt32(x);
If you're able to get them into object arrays, that works as well.
object[] obj = [...];
[...]
var x0 = Convert.To[...](obj[0]);
var x1 = Convert.To[...](obj[1]);
Etcetera.

Create SQL Server table programmatically

I need to programmatically create a SQL Server 2008 table in C# such that the columns of the table should be generated from a list of columns (each column name is the name of a row in the table)
My question is what is the command string to loop through the list of columns and creates the table's recorded:
List<string> columnsName = ["col1","col2","col3"]
I want to create a table with the columns in the columnsName. But since the list size in not constant, I need to loop through the list to generate the table columns.
The simple answer is
CREATE TABLE table_name
(
column_name1 data_type,
column_name2 data_type,
column_name3 data_type,
....
)
from w3Schools.com
In C# use a string builder to concatenate the query and then execute the query.
StringBuilder query = new StringBuilder();
query.Append("CREATE TABLE ");
query.Append(tableName);
query.Append(" ( ");
for (int i = 0; i < columnNames.Length; i++)
{
query.Append(columnNames[i]);
query.Append(" ");
query.Append(columnTypes[i]);
query.Append(", ");
}
if (columnNames.Length > 1) { query.Length -= 2; } //Remove trailing ", "
query.Append(")");
SqlCommand sqlQuery = new SqlCommand(query.ToString(), sqlConn);
SqlDataReader reader = sqlQuery.ExecuteReader();
Note: tableName, columnNames, and columnTypes would be replaced with what ever you are getting the data from. From your description it sounds like you are getting the column values from a query, so rather than using a for loop and arrays you will probably be using a while loop to iterate through the results to build the query. Let me know if you need an example using this method and I will make one tonight.
If you are having trouble with the syntax for creating the table you can try creating the table (or a sample table) in MS SQL Server Management Studio, then right click the table and select Script Table as\Create To\New Query Editor Window. This will show you the script it would use to build the query.
Are you looking to implement something like an Entity–attribute–value model?
http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model

How can I get a list of the columns in a SQL SELECT statement?

I'm wanting to get a list of the column names returned from a SQL SELECT statement. Can someone suggest an easy way to do this?
I have a tool that lets users define a query using any SQL SELECT statement. The results of the query are then presented in a custom manner. To set up the presentation, I need to know the column names so that the user can store formatting settings about each column.
Btw, the formatting settings are all being created via ASP.NET web pages, so the query results will end up in .NET if that helps with any ideas people have.
Any ideas?
You should be able to do this using the GetName method. Something like this probably:
SqlDataReader mySDR = cmd.ExecuteReader();
for(int i = 0;i < mySDR.FieldCount; i++)
{
Console.WriteLine(mySDR.GetName(i));
}
This is something you could do entirely from a asp.net page. No special/extra SQL required.
Assuming SQL Server: You could use SET FMTONLY to just return metadata (and not the actual data), e.g.:
USE AdventureWorks2008R2;
GO
SET FMTONLY ON;
GO
SELECT *
FROM HumanResources.Employee;
GO
SET FMTONLY OFF;
GO
You can get by something as following
Note : You need to fill the DataTable of the Dataset.........
DataSet1 DataSet1 = new DataSet1();
DataTable dt = DataSet1.Tables(0);
DataColumn dc = null;
foreach (DataColumn dc_loopVariable in dt.Columns) {
dc = dc_loopVariable;
Response.write(dc.ColumnName.ToString() + " " + dc.DataType.ToString() + "<br>");
}
Another method to just return meta data is
select top 0 * from table
If you know the table name you could try using:
desc <table_name>
I'm assuming you are using SQL Server.
Or as an alternative:
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TableNameGoesHere'
ORDER BY ORDINAL_POSITION
You might want to use the second option if you are going to be using ASP.NET
This will get you more than the column name if you need more information about each column like size, ordinal,etc. A few of the most important properties are listed, but there are more.
Note, DataObjects.Column is a POCO for storing column information. You can roll your own in your code. Also, note I derive the .Net type as well, useful for converting SQL data types to .Net (C#) ones. ConnectionString and TableName would be supplied from a caller.
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
conn.Open();
SqlCommand comm = new SqlCommand("Select top(1) * from " + TableName + " Where 1=0");
comm.CommandType = CommandType.Text;
comm.Connection = conn;
using (SqlDataReader reader = comm.ExecuteReader(CommandBehavior.KeyInfo))
{
DataTable dt = reader.GetSchemaTable();
foreach (DataRow row in dt.Rows)
{
//Create a column
DataObjects.Column column = new DataObjects.Column();
column.ColumnName = (string)row["ColumnName"];
column.ColumnOrdinal = (int)row["ColumnOrdinal"];
column.ColumnSize = (int)row["ColumnSize"];
column.IsIdentity = (bool)row["IsIdentity"];
column.IsUnique = (bool)row["IsUnique"];
//Get the C# type of data
object obj = row["DataType"];
Type runtimeType = obj.GetType();
System.Reflection.PropertyInfo propInfo = runtimeType.GetProperty("UnderlyingSystemType");
column.type = (Type)propInfo.GetValue(obj, null);
//Set a string so we can serialize properly later on
column.DataTypeFullName = column.type.FullName;
//I believe this is SQL Server Data Type
column.SQLServerDataTypeName = (string)row["DataTypeName"];
//Do something with the column
}
}
}

Categories

Resources