How to retrieve real column name of aliased column - c#

I need to get the real column name from DataTable which I filled it by FillSchema() method,
this is the query I used (SELECT ID AS [SNO],CATEG_NAME AS [Category] FROM Categories)
var dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter("SELECT ID AS [SNO],CATEG_NAME AS [Category] FROM Categories",conn);
da.FillSchema(dt, SchemaType.Source);
dt.FillBySql(sql);
When I check dt.columns I find that there are 2 columns with the same alias name which mentioned in query. What can I do to get the real column names(id, categ_name)?

I tried to add one column with the name same as alias column name but just let it blank. see column
then I execute this query:
SELECT
status_action,
isread,
CONCAT(
FLOOR(HOUR(TIMEDIFF(work_given, sysdate())) / 24),
' days, ',
MOD(HOUR(TIMEDIFF(work_given, sysdate())), 24),
' hours, ',
MINUTE(TIMEDIFF(work_given, sysdate())),
' minutes') **as** **workgivendays**
from progressreport
And then I call it use MySqlDataReader
like this :
MySqlDataReader mdr = cmd.ExecuteReader();
workgivendays = mdr.GetString("workgivendays");
and it works

I believe that your best bet is to alter them in C#, not alias them in SQL. This is not a best practice, but this workaround has worked for me.
On a databound datagridview, you have to change the underlying datatable. This sample will change the name of the column from 'ID' to 'SNO'. Make sure you alter a copy the table, so the original remains unchanged.
var dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter("SELECT ID,CATEG_NAME AS [Category] FROM Categories",conn);
da.FillSchema(dt, SchemaType.Source);
dt.FillBySql(sql);
DataTable clonedWithColumnsChanged= dt.Copy();
clonedWithColumnsChanged.Columns["ID"].ColumnName = "SNO";
dgvReports.DataSource = clonedWithColumnsChanged;

Related

Get database schema when getting the table metadata

Please note that when I using the word "schema" I mean Schema as the security feature provided by Sql Server ("dbo"...) that you must provide with the table name if you want your query to succeed, NOT its metadata (columns...).
I'm using this bit of code to get the table metadata (columns, types, etc) :
// Parameter table includes the schema name.
public DataTable GetTableSchema(string table)
{
var tbl = new DataTable();
using (var conn = new SqlConnection(ConnectionString))
using (var adapter = new SqlDataAdapter(String.Format("SELECT * FROM {0} WHERE 1=0", table), conn))
{
tbl = adapter.FillSchema(tbl, SchemaType.Source);
}
return tbl;
}
My issue is that the property DataTable.TableName doesn't contain the table schema ("dbo", or any custom schema) and I can't find any property in the object that allows me to get that information, so it is lost during the process (or I have to pass several variables to methods, while I'd like to keep everything in the DataTable object, which should be logical).
Where / how can I get it along with the database structure ?
Only solution I found : adding tbl.TableName = table; before returning the table but it feels... wrong.
You could query the INFORMATION_SCHEMA.TABLES view and get your info from the TABLE_SCHEMA field
"SELECT TABLE_SCHEMA FROM INFORMATION_SCHEMA.TABLES where table_name = '" + table "'";
It is not clear why you need this info, so I can only suggest to run this code
SqlCommand cmd = new SqlCommand(#"SELECT TABLE_SCHEMA
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #table", con);
cmd.Parameters.Add("#table", SqlDbType.NVarChar).Value = table;
string schema = (string)cmd.ExecuteScalar();
There is also an alternative, that could return some of the info on your table and the table_schema in a single call
DataTable dt = new DataTable();
dt = cnn.GetSchema("COLUMNS", new string[] { null, null, table, null });
Console.WriteLine(dt.Rows[0]["TABLE_SCHEMA"].ToString());
This code returns a lot of info about your table and also the TABLE_SCHEMA colum.
Not sure if this approach is suitable for your purpose because here the datatable returned contains a row for each column and each column of this DataTable contains details about the columns (Like OrdinalPosition, IsNullable, DataType, Character_Maximum_Length)

Remove a column from select statement

I would like to know is there a way to remove a specific column when displaying in a datagridview. Below is the sql statemnt to retrieve
OleDbDataAdapter oda = new OleDbDataAdapter("select * from BHR_2016_FEB_CIT4114_FYP_GD", con);
DataTable dt = new DataTable();
oda.Fill(dt);
dt.Columns.Remove("Fingerprint_Template");
dataGridViewAttendanceDatabase.DataSource = dt;
The reasons is because, i have a type of format CLOB, therefore it will not display in datagridview. So i plan remove a column which stores the CLOB format. I can specify, but the problem i will be selecting table based on combo box and each table have different number of columns such as a table might have 31 column, another table might have 28 column. So how i could remove only a single column. Thanks in advanced.
There is still an error as when i state select *, it includes the column which consist of CLOB format. Therefore error exist at oda.Fill(dt);. Is there a way to select * except a columns which consist of CLOB format. This help is really appreciated.
you can just do this
dt.Columns.Remove("xyz");
Update
It seems Fill does not support CLOB data. Above solution will not work.You need to do change in SQL itself. My suggestion is to move everything in stored procedure and use meta data to extract column which you want (or exclude column which you do not want.) Here is sample code. Please note I have not tested it so you may find some minor issue but the code gives you gist of what you can do to solve your problem
C# Code
OleDbConnection oc= new OleDbConnection("[pass your connection string]");
OleDbCommand ocom = new OleDbCommand();
ocom.CommandText = "Abc"; // Abc is stored procedure
ocom.Connection = oc;
ocom.CommandType = CommandType.StoreProcedure;
ocom.Parameters.AddWithValue("#tableName","PQR") // pass your table name
ocom.Parameters.AddWithValue("#databaseName","IJK"); // pass your database name
OleDbDataAdapter oda = new OleDbDataAdapter(ocom);
DataTable dt = new DataTable();
oda.Fill(dt);
dataGridViewAttendanceDatabase.DataSource = dt;
SQL Script
Create Porocedure Abc (#tableName varchar(255),#databaseName varchar(255))
Begin
SET #sql = CONCAT('SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME), 'Fingerprint_Template,', '') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #tableName AND TABLE_SCHEMA = #databaseName), CONCAT(' FROM ',#tableName));
PREPARE stmt FROM #sql;
EXECUTE stmt;
End

Varchar(N) being ignored in DataTable.Load()

Possible that I'm overlooking something here, but when I load a DataTable from SqlCommand.ExecuteReader() I am finding that the MaxLength property of my String field is ignored and reset to '50' in the resulting DataColumn. Here's an example table:
CREATE TABLE MySqlServerTable (
[instance_id] INT NOT NULL,
[field_id] INT NOT NULL,
[value] VARCHAR (MAX) NOT NULL);
and the method I'm using to initialize the local DataTable is
public DataTable GetDT()
{
string query = "SELECT top 0 * FROM MySqlServerTable;";
SqlCommand cmd = new SqlCommand(query, _msSqlConn);
DataTable dt = new DataTable();
dt.Load(cmd.ExecuteReader());
return dt;
}
where _msSqlConn is the already opened SqlConnection. If I then scroll through the DataColumns, I find that the value column (the string column) has been assigned a MaxLength of 50.
Console.WriteLine(GetDT().Columns["value"].MaxLength);
So what gives?
Kinda related to this attempted answer but still unresolved.
What's the right way to do this such that my string column MaxLengths are properly retrieved from the SqlServer2012 DB?
I think you need to use DataAdapter.FillSchema() to retrieve meta data. Try this something like this:
_msSqlConn.Open();
using (SqlDataAdapter da = new SqlDataAdapter(query, _msSqlConn))
{
DataTable dt = new DataTable();
da.FillSchema(dt, SchemaType.Mapped); //Or may be SchemaType.Source
return dt;
}

Datagrid view to fill based on columns

Below is my Datagridview code to get the data from employee table.
the problem am facing is ,my employee table have 10 columns (ID,emplNo,Dob,JoingData...etc)
i just want to fill my grid with only ID,EmplyNo and DOB.
but the below code get everything,please advise me what i suppose to do to get only particular column
string sql = "select * from Employee";
SqlConnection connection = new SqlConnection(CONNECTION_STRING);
//SqlDataAdapter dataadapter = new SqlDataAdapter(sql, connection);
dataadapter = new SqlDataAdapter(sql, connection);
// DataSet ds = new DataSet();
ds = new DataSet();
connection.Open();
dataadapter.Fill(ds, scrollVal, 5, "Employee");
connection.Close();
dgMessages.DataSource = ds;
dgMessages.DataMember = "tEmployee";
instead of
string sql = "select * from Employee";
do
string sql = "select ID, EmplyNo, DOB from Employee";
either change your select to only get the supset of what you want or use the designer:
it's a bit of a pain because you first have to add an unbound column and then edit the just added column to setthe DataPropertyName to a column-name in your resulting table - but it works.
You find this dialogs by clicking the "..." in the "columns" property of the PropertyEditor for the DataGridView or by clicking the little "Play"-Button on the top-right of the Grid in the designer (when it is selected)
Almost forgot: IMPORTANT: you need to add EVERY column and set Visible=False on those you don't want to see - I think this is different in WebForms where there is something like AutogenerateColumns.

Using temporary table in c#

I read an excel sheet into a datagrid.From there , I have managed to read the grid's rows into a DataTable object.The DataTable object has data because when I make equal a grid's datasource to that table object , the grid is populated.
My Problem : I want to use the table object and manipulate its values using SQL server,(i.e. I want to store it as a temporary table and manipulate it using SQL queries from within C# code and , I want it to return a different result inte a grid.(I don't know how to work with temporary tables in C#)
Here's code to execute when clicking button....
SqlConnection conn = new SqlConnection("server = localhost;integrated security = SSPI");
//is connection string incorrect?
SqlCommand cmd = new SqlCommand();
//!!The method ConvertFPSheetDataTable Returns a DataTable object//
cmd.Parameters.AddWithValue("#table",ConvertFPSheetDataTable(12,false,fpSpread2_Sheet1));
//I am trying to create temporary table
//Here , I do a query
cmd.CommandText = "Select col1,col2,SUM(col7) From #table group by col1,col2 Drop #table";
SqlDataAdapter da = new SqlDataAdapter(cmd.CommandText,conn);
DataTable dt = new DataTable();
da.Fill(dt); ***// I get an error here 'Invalid object name '#table'.'***
fpDataSet_Sheet1.DataSource = dt;
//**NOTE:** fpDataSet_Sheet1 is the grid control
Change your temp table from #table to ##table in both places.
Using ## means a global temp table that stays around. You'll need to Drop it after you have completed your task.
Command = " Drop Table ##table"
Putting the data into a database will take time - since you already have it in memory, perhaps LINQ-to-Objects (with DataSetExtensions) is your friend? Replace <int> etc with the correct types...
var query = from row in table.Rows.Cast<DataRow>()
group row by new
{
Col1 = row.Field<int>(1),
Col2 = row.Field<int>(2)
} into grp
select new
{
Col1 = grp.Key.Col1,
Col2 = grp.Key.Col2,
SumCol7 = grp.Sum(x => x.Field<int>(7))
};
foreach (var item in query)
{
Console.WriteLine("{0},{1}: {2}",
item.Col1, item.Col2, item.SumCol7);
}
I don't think you can make a temp table in SQL the way you are thinking, since it only exists within the scope of the query/stored procedure that creates it.
If the spreadsheet is a standard format - meaning you know the columns and they are always the same, you would want to create a Table in SQL to put this file into. There is a very fast way to do this called SqlBulkCopy
// Load the reports in bulk
SqlBulkCopy bulkCopy = new SqlBulkCopy(connectionString);
// Map the columns
foreach(DataColumn col in dataTable.Columns)
bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
bulkCopy.DestinationTableName = "SQLTempTable";
bulkCopy.WriteToServer(dataTable);
But, if I'm understanding your problem correctly, you don't need to use SQL server to modify the data in the DataTable. You c an use the JET engine to grab the data for you.
// For CSV
connStr = string.Format("Provider=Microsoft.JET.OLEDB.4.0;Data Source={0};Extended Properties='Text;HDR=Yes;FMT=Delimited;IMEX=1'", Folder);
cmdStr = string.Format("SELECT * FROM [{0}]", FileName);
// For XLS
connStr = string.Format("Provider=Microsoft.JET.OLEDB.4.0;Data Source={0}{1};Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'", Folder, FileName);
cmdStr = "select * from [Sheet1$]";
OleDbConnection oConn = new OleDbConnection(connStr);
OleDbCommand cmd = new OleDbCommand(cmdStr, oConn);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
oConn.Open();
da.Fill(dataTable);
oConn.Close();
Also, in your code you ask if your connection string is correct. I don't think it is (but I could be wrong). If yours isn't working try this.
connectionString="Data Source=localhost\<instance>;database=<yourDataBase>;Integrated Security=SSPI" providerName="System.Data.SqlClient"
Pardon me, if I have not understood what you exactly want.
If you want to perform SQL query on excel sheet, you could do it directly.
Alternatively, you can use SQL Server to query excel (OPENROWSET or a function which I dont remember right away). Using this, you can join a sql server table with excel sheet
Marc's suggestion is one more way to look at it.
Perhaps you could use a DataView. You create that from a DataTable, which you already have.
dv = new DataView(dataTableName);
Then, you can filter (apply a SQL WHERE clause) or sort the data using the DataView's methods. You can also use Find to find a matching row, or FindRows to find all matching rows.
Some filters:
dv.RowFilter = "Country = 'USA'";
dv.RowFilter = "EmployeeID >5 AND Birthdate < #1/31/82#"
dv.RowFilter = "Description LIKE '*product*'"
dv.RowFilter = "employeeID IN (2,4,5)"
Sorting:
dv.Sort = "City"
Finding a row: Find the customer named "John Smith".
vals(0)= "John"
vals(1) = "Smith"
i = dv.Find(vals)
where i is the index of the row containing the customer.
Once you've applied these to the DataView, you can bind your grid to the DataView.
Change the command text from
Select col1,col2,SUM(col7) From #table group by col1,col2
to
Select col1,col2,SUM(col7) From ##table group by col1,col2

Categories

Resources