I'm trying to get the column names of a table I have stored in SQL Server 2008 R2.
I've literally tried everything but I can't seem to find how to do this.
Right now this is my code in C#
public string[] getColumnsName()
{
List<string> listacolumnas=new List<string>();
using (SqlConnection connection = new SqlConnection(Connection))
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT TOP 0 * FROM Usuarios";
connection.Open();
using (var reader = command.ExecuteReader(CommandBehavior.KeyInfo))
{
reader.Read();
var table = reader.GetSchemaTable();
foreach (DataColumn column in table.Columns)
{
listacolumnas.Add(column.ColumnName);
}
}
}
return listacolumnas.ToArray();
}
But this is returning me the following
<string>ColumnName</string>
<string>ColumnOrdinal</string>
<string>ColumnSize</string>
<string>NumericPrecision</string>
<string>NumericScale</string>
<string>IsUnique</string>
<string>IsKey</string>
<string>BaseServerName</string>
<string>BaseCatalogName</string>
<string>BaseColumnName</string>
<string>BaseSchemaName</string>
<string>BaseTableName</string>
<string>DataType</string>
<string>AllowDBNull</string>
<string>ProviderType</string>
<string>IsAliased</string>
<string>IsExpression</string>
<string>IsIdentity</string>
<string>IsAutoIncrement</string>
<string>IsRowVersion</string>
<string>IsHidden</string>
<string>IsLong</string>
<string>IsReadOnly</string>
<string>ProviderSpecificDataType</string>
<string>DataTypeName</string>
<string>XmlSchemaCollectionDatabase</string>
<string>XmlSchemaCollectionOwningSchema</string>
<string>XmlSchemaCollectionName</string>
<string>UdtAssemblyQualifiedName</string>
<string>NonVersionedProviderType</string>
<string>IsColumnSet</string>
Any ideas?
It shows the <string> tags as this is how my web service sends the data.
You can use the query below to get the column names for your table. The query below gets all the columns for a user table of a given name:
select c.name from sys.columns c
inner join sys.tables t
on t.object_id = c.object_id
and t.name = 'Usuarios' and t.type = 'U'
In your code, it will look like that:
public string[] getColumnsName()
{
List<string> listacolumnas=new List<string>();
using (SqlConnection connection = new SqlConnection(Connection))
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "select c.name from sys.columns c inner join sys.tables t on t.object_id = c.object_id and t.name = 'Usuarios' and t.type = 'U'";
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
listacolumnas.Add(reader.GetString(0));
}
}
}
return listacolumnas.ToArray();
}
I typically use the GetSchema method to retrieve Column specific information, this snippet will return the column names in a string List:
using (SqlConnection conn = new SqlConnection("<ConnectionString>"))
{
string[] restrictions = new string[4] { null, null, "<TableName>", null };
conn.Open();
var columnList = conn.GetSchema("Columns", restrictions).AsEnumerable().Select(s => s.Field<String>("Column_Name")).ToList();
}
SELECT COLUMN_NAME
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'YourTable'
public string[] getColumnsName()
{
List<string> listacolumnas=new List<string>();
using (SqlConnection connection = new SqlConnection(Connection))
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "select column_name from information_schema.columns where table_name = 'Usuarios'";
connection.Open(;
using (var reader = command.ExecuteReader(CommandBehavior.KeyInfo))
{
reader.Read();
var table = reader.GetSchemaTable();
foreach (DataColumn column in table.Columns)
{
listacolumnas.Add(column.ColumnName);
}
}
}
return listacolumnas.ToArray();
}
The original post was close to the goal, Just some small changes and you got it.
Here is my solution.
public List<string> GetColumns(string tableName)
{
List<string> colList = new List<string>();
DataTable dataTable = new DataTable();
string cmdString = String.Format("SELECT TOP 0 * FROM {0}", tableName);
if (ConnectionManager != null)
{
try
{
using (SqlDataAdapter dataContent = new SqlDataAdapter(cmdString, ConnectionManager.ConnectionToSQL))
{
dataContent.Fill(dataTable);
foreach (DataColumn col in dataTable.Columns)
{
colList.Add(col.ColumnName);
}
}
}
catch (Exception ex)
{
InternalError = ex.Message;
}
}
return colList;
}
Currently, there are two ways I could think of doing this:
In pure SQL Server SQL you can use the views defined in INFORMATION_SCHEMA.COLUMNS. There, you would need to select the row for your table, matching on the column TABLE_NAME.
Since you are using C#, it's probably easier to obtain the names from the SqlDataReader instance that is returned by ExecuteReader. The class provides a property FieldCount, for the number of columns, and a method GetName(int), taking the column number as its argument and returning the name of the column.
sp_columns - http://technet.microsoft.com/en-us/library/ms176077.aspx
There are many built in stored procedures for this type of thing.
Related
I'm working on a database migration where I need to drop all the tables in a specific schema and then run another script to recreate them from another database.
I'm running into issues with trying to delete specific tables in the proper order.
Is there a SQL query that will order the tables in the correct order so they can be dropped properly?
Here is the code I am trying so far, but the tables are not in the proper order:
private void CreateDropStatementsAndRun(string schema)
{
string sql = string.Format(#"SELECT table_name
FROM information_schema.tables
WHERE table_schema = '{0}';", schema);
var connectionString = ConfigurationManager.ConnectionStrings["TARGET_DefaultConnection"];
StringBuilder sb = new StringBuilder();
var listOfTables = new List<string>();
using (SqlConnection conn = new SqlConnection(connectionString.ConnectionString))
{
conn.Open();
using (var command = new SqlCommand(sql, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
listOfTables.Add(reader.GetString(0));
}
}
}
foreach (var item in listOfTables)
{
sb.AppendFormat("alter table {0}.{1} nocheck constraint all;", schema, item).AppendLine();
sb.AppendFormat("DROP TABLE IF EXISTS {0}.{1};", schema, item).AppendLine();
}
using (var cmd = new SqlCommand(sb.ToString(), conn))
{
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
}
Remember that there might be circular references between tables. There might be foreign key constraints from A -> B -> C -> A, for example.
Have a look at the approach in How to drop all tables in a SQL Server database? - but you will have to alter it to work with just your schema.
Here is my answer:
Focus on the ORDER BY dependency_level desc and then the where schema_Name = '{0}'
Here is where I found my answer: How to list tables in their dependency order (based on foreign keys)?
private void CreateDropStatementsAndRun(string schema)
{
string sql = string.Format(#"WITH cte (lvl, object_id, name, schema_Name) AS
(SELECT 1, object_id, sys.tables.name, sys.schemas.name as schema_Name
FROM sys.tables Inner Join sys.schemas on sys.tables.schema_id = sys.schemas.schema_id
WHERE type_desc = 'USER_TABLE'
AND is_ms_shipped = 0
UNION ALL SELECT cte.lvl + 1, t.object_id, t.name, S.name as schema_Name
FROM cte
JOIN sys.tables AS t ON EXISTS
(SELECT NULL FROM sys.foreign_keys AS fk
WHERE fk.parent_object_id = t.object_id
AND fk.referenced_object_id = cte.object_id )
JOIN sys.schemas as S on t.schema_id = S.schema_id
AND t.object_id <> cte.object_id
AND cte.lvl < 30
WHERE t.type_desc = 'USER_TABLE'
AND t.is_ms_shipped = 0 )
SELECT schema_Name, name, MAX (lvl) AS dependency_level
FROM cte
where schema_Name = '{0}'
GROUP BY schema_Name, name
ORDER BY dependency_level desc,schema_Name, name;", schema);
var connectionString = ConfigurationManager.ConnectionStrings["TARGET_DefaultConnection"];
StringBuilder sb = new StringBuilder();
var listOfTables = new List<string>();
using (SqlConnection conn = new SqlConnection(connectionString.ConnectionString))
{
conn.Open();
using (var command = new SqlCommand(sql, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
listOfTables.Add(reader.GetString(1));
}
}
}
if (listOfTables.Count > 0)
{
foreach (var item in listOfTables)
{
sb.AppendFormat("DROP TABLE IF EXISTS {0}.{1};", schema, item).AppendLine();
}
using (var cmd = new SqlCommand(sb.ToString(), conn))
{
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
}
}
I have parameterized stored procedure (tested and works) in mysql.
I wanted to replace my long select statement with stored procedure in my code.
With select statement it worked but now I am not able to run it with sp (commented string req).
My stored procedure:
CREATE DEFINER=`root`#`%` PROCEDURE `GetProjectVM`(
IN projectName NVARCHAR(255)
)
BEGIN
select VirtualMachines.Name,
VirtualMachines.IpAddress,
VirtualMachines.DiskSize,
VirtualMachines.CPU,
VirtualMachines.Ram,
VirtualMachines.ImageUrl,
VirtualMachines.Role,
Hypervisors.Name as Hypervisor,
Managements.Netmask,
Managements.Gateway from VirtualMachines inner join Projects
on Projects.id = VirtualMachines.ProjectId inner join Hypervisors
on Hypervisors.HypervisorId = VirtualMachines.HypervisorId inner join Managements
on VirtualMachines.ManagementId = Managements.Id
where Projects.Name = projectName;
END
My code looks like:
private string _dbUrl;
private MySqlConnection _cnn;
public Dbmanagement(string dbUrl)
{
this._dbUrl = dbUrl;
this._cnn = new MySqlConnection(this._dbUrl);
}
private MySqlDataReader ExecuteMysqlCommand(string cmd)
{
_cnn.Open();
var result = new MySqlCommand(cmd, _cnn);
return result.ExecuteReader();
}
public IEnumerable<VM> GetProjectVM(string projectName)
{
var vmList = new List<VM>();
//string req =
// $"select VirtualMachines.Name,VirtualMachines.IpAddress,VirtualMachines.DiskSize,VirtualMachines.CPU,VirtualMachines.Ram,VirtualMachines.ImageUrl,VirtualMachines.Role,Hypervisors.Name as Hypervisor,Managements.Netmask,Managements.Gateway from VirtualMachines inner join Projects on Projects.id = VirtualMachines.ProjectId inner join Hypervisors on Hypervisors.HypervisorId = VirtualMachines.HypervisorId inner join Managements on VirtualMachines.ManagementId = Managements.Id where Projects.Name = \"{projectName}\" ;";
MySqlCommand cmd = new MySqlCommand("GetProjectVM", _cnn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#projectName", projectName);
var req = cmd;
var rd = ExecuteMysqlCommand(req.ToString());
while (rd.Read())
{
vmList.Add(new VM(rd));
}
_cnn.Close();
return vmList;
}
The problem - or at least the first problem - is how you're executing the command.
Calling ToString on a MySqlCommand is very unlikely to be able to convey all the relevant information. You're losing parameterization, command type etc.
Change this:
var req = cmd;
var rd = ExecuteMysqlCommand(req.ToString());
to
_cnn.Open();
var rd = req.ExecuteReader();
I'd also suggest not having a single MySqlConnection, but just constructing one when you need to, and letting the connection pool manage making that efficient. So something like:
using (var connection = new MySqlConnection(_dbUrl))
{
connection.Open();
using (var cmd = new MySqlCommand("GetProjectVM", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
// Avoid AddWithValue where possible, to avoid conversion issues.
cmd.Parameters.Add("#projectName", MySqlDbType. VarChar).Value = projectName;
using (var reader = cmd.ExecuteReader())
{
var list = new List<VM>();
while (reader.Read())
{
list.Add(new VM(reader));
}
return list;
}
}
}
This is my first foray into LINQ.
I still have to wrap my head around the results part, but I can't seem to get any results from this.
var institutions = from lots in lotsdb.NEWinstitution
join webs in webbitdb.tblinstitution
on lots.institutionid equals webs.dispenseinstid into newinsts
from webs2 in newinsts.DefaultIfEmpty()
where webs2 == null
select new
{
instid = lots.institutionid,
instname = lots.institutionname
};
foreach(var instfound in institutions)
{
MessageBox.Show(instfound.instid.ToString() + " " + instfound.instname.ToString());
}
I'm using Datasets created by Visual Studio in the DATASources list.
Below is my original SQL string that i have "tried" to adapt to LINQ
string strgetloc = #"
SELECT NEWinstitution.institutionid, NEWinstitution.institutionname
FROM NEWinstitution
LEFT JOIN tblinstitution
ON NEWinstitution.institutionid = tblinstitution.dispenseinstid
WHERE (((tblinstitution.institutionid) Is Null));"
You probably need something like this:
var institutions =
from lots in lotsdb.NEWinstitution
join webs in webbitdb.tblinstitution on lots.institutionid equals webs.dispenseinstid
where webs.IsInstitutionIdNull()
select new
{
instid = lots.institutionid,
instname = lots.institutionname
};
The IsInstitutionIdNull() method is generated by the MSDataSetGenerator when the columns allows DBNull. Because you cannot compare it directly to DBNull or to null.
(fixed a typo)
So I ended up using the following code:
var idsNotInB = dtLotsInst.AsEnumerable().Select(r => r.Field<int>("institutionid"))
.Except(dtWebbitInst.AsEnumerable().Select(r => r.Field<int>("institutionid")));
count = idsNotInB.Count();
if (count != 0)
{
DataTable dtOnlyLots = (from row in dtLotsInst.AsEnumerable()
join id in idsNotInB
on row.Field<int>("institutionid") equals id
select row).CopyToDataTable();
using (OleDbConnection con = new OleDbConnection(PackChecker.Properties.Settings.Default["WebbitConnectionString"].ToString()))
{
string strgetloc = #"INSERT INTO tblinstitution ( dispenseinstid, institutionname ) VALUES (?,?)";
using (OleDbCommand cmd = new OleDbCommand(strgetloc, con))
{
con.Open();
foreach (DataRow dr in dtOnlyLots.Rows)
{
cmd.Parameters.Add("?", OleDbType.Integer).Value = Convert.ToInt32(dr["institutionid"]);
cmd.Parameters.Add("?", OleDbType.VarWChar).Value = dr["institutionname"].ToString();
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
con.Close();
}
}
}
This uses LINQ and works well by using "EXCEPT" in the first LINQ section to find values not in one table. Then it uses this list to generate the rows from the table I want.
I am using PostgreSQL database with C# and the Npgsql library.
Right now I can select the last row in my table, but I can not figure out how to assign a C# variable to it. I know that my selection works, because I have successfully edited my last entry before.
You can find my code below. Note that I have not pasted the rest of the methods as I think they are irrelevant.
public void myMethod()
{
this.OpenConn(); //opens the connection
string sql = "SELECT id FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'customers' ORDER BY id DESC, LIMIT 1";
using (NpgsqlCommand command = new NpgsqlCommand(sql, conn))
{
int id = 0; //instead of '0' I want it to be equal to the ID value from the row
//something like "int id = sqlSelection.id;" -- this obviously doesn't work
this.CloseConn(); //close the current connection
}
}
You could achieve this goal by using the specific DataReader:
public void myMethod()
{
this.OpenConn(); //opens the connection
string sql = "SELECT id FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'customers' ORDER BY id DESC, LIMIT 1";
using (NpgsqlCommand command = new NpgsqlCommand(sql, conn))
{
int val;
NpgsqlDataReader reader = command.ExecuteReader();
while(reader.Read()){
val = Int32.Parse(reader[0].ToString());
//do whatever you like
}
this.CloseConn(); //close the current connection
}
}
Useful notes
In some contexts ExecuteScalar is a good alternative
Npgsql documentation
Use can use following code variation too;
using (var command = new NpgsqlCommand(sql, conn))
{
int id = 0;
var reader = command.ExecuteReader();
while(reader.Read())
{
var id = Int32.Parse(reader["id"].ToString());
}
this.CloseConn();
}
You can use ExecuteScalarSync method.
public void myMethod()
{
this.OpenConn(); //opens the connection
string sql = "SELECT id FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'customers' ORDER BY id DESC, LIMIT 1";
using (NpgsqlCommand command = new NpgsqlCommand(sql, conn))
{
int id= (int)DBHelperRepository.ExecuteScalarSync(sqlString, CommandType.Text);
this.CloseConn(); //close the current connection
}
}
Lets say I have a table in SQLServer named MyTable
ID FirstName LastName
1 Harry Dan
2 Maria Vicente
3 Joe Martin
Now if I have to insert any data in table, I will simply fire Insert Query like this
INSERT INTO MyTable (ID, FirstName, LastName) VALUES (4, Smith, Dan);
But what if I don't know the column names beforehand, I only know table name. Then is there a way to get the column name of table at runtime?
You can use sql-
SELECT name FROM sys.columns WHERE object_id = OBJECT_ID('TABLE_NAME')
Or you can query for SELECT TOP 0 * FROM TableName. Then, you can get the columns:
using(var reader = command.ExecuteReader())
{
reader.Read();
var table = reader.GetSchemaTable();
foreach (DataColumn column in table.Columns)
{
Console.WriteLine(column.ColumnName);
}
}
Another option using pure C# / .NET code:
First a helper method, that here returns a simple list of column names. Using a DataTable to hold table schema information, means that other information can also be retreived for each column, fx. if it is an AutoIncreament column etc.
private IEnumerable<string> GetColumnNames(string conStr, string tableName)
{
var result = new List<string>();
using (var sqlCon = new SqlConnection(conStr))
{
sqlCon.Open();
var sqlCmd = sqlCon.CreateCommand();
sqlCmd.CommandText = "select * from " + tableName + " where 1=0"; // No data wanted, only schema
sqlCmd.CommandType = CommandType.Text;
var sqlDR = sqlCmd.ExecuteReader();
var dataTable = sqlDR.GetSchemaTable();
foreach (DataRow row in dataTable.Rows) result.Add(row.Field<string>("ColumnName"));
}
return result;
}
The method can be called as:
var sortedNames = GetColumnNames("Data Source=localhost;Initial Catalog=OF2E;Integrated Security=SSPI", "Articles").OrderBy(x => x);
foreach (var columnName in sortedNames) Console.WriteLine(columnName);
Simply by this Query :
SELECT * FROM sys.columns
WHERE object_id = OBJECT_ID('dbo.[table_name]')
OR This Query :
SELECT COLUMN_NAME
FROM information_schema.columns
WHERE TABLE_NAME = [table_name]
ORDER BY COLUMN_NAME
var ColName = "";
var model = new AttributeMappingSource().GetModel(typeof(DataClassesDataContext));
foreach (var mt in model.GetTables())
{
if (mt.TableName == "dbo.Table_Name")
{
foreach (var dm in mt.RowType.DataMembers)
{
ColName = dm.MappedName + ", ";
Response.Write(ColName);
}
}
}
This question was answered before in various threads
check:
How can I get column names from a table in SQL Server?
How can I get column names from a table in Oracle?
How do I list all the columns in a table?