I am importing a row in a datagridview from another one for editing.
Edit the values.
Save the values.
But I do not want the user to make changes in the column which is the PRIMARY KEY TABLE.
I have the name of primary key column by
string sql = "SELECT ColumnName = col.column_name FROM information_schema.table_constraints tc INNER JOIN information_schema.key_column_usage col ON col.Constraint_Name = tc.Constraint_Name AND col.Constraint_schema = tc.Constraint_schema WHERE tc.Constraint_Type = 'Primary Key' AND col.Table_name = '" + _lstview_item + "'";
SqlConnection conn2 = new SqlConnection(cc.connectionString(cmb_dblist.Text));
SqlCommand cmd_server2 = new SqlCommand(sql);
cmd_server2.CommandType = CommandType.Text;
cmd_server2.Connection = conn2;
conn2.Open();
string ColumnName = (string)cmd_server2.ExecuteScalar();
//string ColumnName = (string)cmd_server2.ExecuteScalar();
conn2.Close();
and I am building up the update statement as below
u.Append("UPDATE ");
u.Append("[Ref].[");
u.Append(_lstview_item);
u.Append("]");
u.Append("SET ");
for (i = 0; i < col_no; i++)
{
u.Append(col_name);
u.Append(" = ");
u.Append("'");
u.Append(col_value);
u.Append("'");
}
How do i detect if the user is changing the value of the primary key column in this situation ?
You should not concatenate your SQL statement like that.
Instead use SQL parameters to set the individual properties.
Se an example of how SQLParameters are used in this sample:
http://www.dotnetperls.com/sqlparameter
Hope this helps!
Related
I want to create excel file by oledb, and my code is
int index = 0;
foreach (DataColumn col in dt.Columns)
{
datatype[index] = $"[{col.ColumnName}]" + " String";
index++;
}
string query = string.Join(",", datatype);
cmd.CommandText = $"CREATE TABLE [{sheetName}] ({query});";
cmd.ExecuteNonQuery();
and I have column name like Product material[EN]
I used break point and check my command string
CREATE TABLE [products]
(
[another Title] String,
[Use of product[EN]] String,
[Product material[EN]] String,
[another Title] String
);
I've tried
Product material[EN]
Product material[[EN]]]
[Product material[EN]]
'[Product material[EN]]'
Product material[[]EN]
['Product material[EN]']
let all columns in query without bracket
CREATE TABLE [products]
(
another Title String,
Use of product[EN] String,
Product material[EN] String,
another Title String
);
let all value in query without bracket
CREATE TABLE [products]
(
another Title String,
Use of product EN String,
Product material EN String,
another Title String
);
but the above syntax all received Syntax error in field definition.
If using parameter and modify the code
cmd.CommandText = $"CREATE TABLE [{sheetName}] (";
for (int i = 0; i < dt.Columns.Count; i++)
{
cmd.CommandText = cmd.CommandText + "[#var" + i.ToString() + "] String,";
cmd.Parameters.AddWithValue("#var" + i.ToString(), datatype[i]);
}
cmd.CommandText = cmd.CommandText.Remove(cmd.CommandText.Length - 1, 1) + ");";
or change
cmd.Parameters.AddWithValue("#var" + i.ToString(), datatype[i]);
to
cmd.Parameters.Add(new OleDbParameter("#var" + i.ToString(), datatype[i]));
and get the command string
CREATE TABLE [products]
(
[#var0] String,
...
[#varN] String
);
will get a successful excel file but with #varxx column names
change to Product material(EN) is work but I need to use bracket []
how do I add bracket into column name use oledb ?
I want to pass a column2 to a function and update column3 with output of function. I have made func function to calculae the output. When i run the program
it only takes last value as input and outputs all columns with same value.What am i doing wrong?
sqlite1 = new SQLiteConnection("DataSource = D:/datab.db;version=3");
sqlite1.Open();
string query1 = "select * from ramrotable";
SQLiteCommand cmd = new SQLiteCommand(query1, sqlite1);
SQLiteDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("Age::" + reader["age"]);
//int data = Convert.ToInt16(reader["age"]);
string tempquery = string.Format("UPDATE ramrotable SET num =
func({0})",reader["age"]);
cmd = new SQLiteCommand(tempquery, sqlite1);
cmd.ExecuteNonQuery();
}
string query4 = "select * from ramrotable";
cmd = new SQLiteCommand(query4, sqlite1);
reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("Name: " + reader["name"] + " Age: " +
reader["age"] + " Num: " + reader["num"]);
}
You need to use a WHERE clause to tell SQLite which record to update exactly. Otherwise all records will be affected. Please make sure that in the WHERE clause you use a column (or a combination of columns) the identify the record uniquely!
Ideally, every record will have an ID column that contains a unique value and is the Primary Key.
I understand from the comments to the question that you actually want to update the value of the num column depending on a value from the age column of the same record, for all the records in the table.
To do this, you neither need to fetch all the records nor do you need to loop. All you need to do is invoke the following statement:
UPDATE ramrotable SET num = func(age)
This takes the value of the age column, passes it to func and sets the result as the new value for the num column for each record in the table.
So all of what you've written above can be shortened to
sqlite1 = new SQLiteConnection("DataSource = D:/datab.db;version=3");
sqlite1.Open();
cmd = new SQLiteCommand("UPDATE ramrotable SET num = func(age)", sqlite1);
cmd.ExecuteNonQuery();
When using
string tempquery = string.Format("UPDATE ramrotable SET num =
func({0})",reader["age"]);
you are updating each row with current func(age) value.
For updating each row with exact value you should use single command outside of the while loop:
string updatequery = "UPDATE ramrotable SET num = func(age)";
cmd = new SQLiteCommand(updatequery, sqlite1);
cmd.ExecuteNonQuery();
Given a SQL query variable, i.e.,
string mySQLQuery = "SELECT TableA.Field1, TableA.Field2,..., TableB.Field1, TableB.Field2,.... FROM TableA LEFT OUTER JOIN TableB ON TableA.Field1 = TableB.Field1"
Is there any straight way I can extract the fields and the table names within the query in two lists? so:
List "Fields":
All fields From table A, table B (and others I could add by joining) with their table prefix (even if there were only one table in a simple 'SELECT * FROM TableA', I'd still need the 'TableA.' prefix).
All fields From table B with their table prefix, by adding them to the list in the usual fieldList.Add() way through looping.
List "Tables":
All tables involved in the query in the usual tablesList.Add() way through looping.
My first approach would be to make a lot of substrings and comparisons, i.e., finding the FROM, then trimming left, the substring until the first blank space, then the JOIN, then trimming, then the first substring until the space..., but that doesn't seem the right way.
REEDIT
I know I can get all the fields from INFORMATION_SCHEMA.COLUMNS with all the properties (that comes later), but the problem is that for that query I need the tables to be known. My steps should be:
The query "SELECT [fields] FROM [tables]" comes from a Multiline Textbox so I can write a SQL Query to fetch the fields I'd like. I take the string by txtMyQuery.Text property.
Find the field in the SELECT query, and find what table belongs to in the FROM clause.
Store the field like [Table].[Field]in a string list List strFields = new List() by the strFields.Add() method;
Then, iterate through the list in a way like:
for (int i = 0; i < fieldList.Count; i++)
{
string mySqlQuery = "SELECT Table_Name, Column_Name, Data_Type FROM INFORMATION_SCHEMA.COLUMNS
WHERE (COLUMN_NAME + "." + TABLE_NAME) ='" + fieldList[i] + "'";
//Commit query, get results in a gridview, etc.
}
Sure,
Tables:
SELECT TABLE_NAME FROM information_schema.TABLES
Fields:
SELECT * FROM information_schema.COLUMNS WHERE TABLE_NAME = N'Your Table'
Ok, after a while, I found SOME way to make this happen... I will work this out as I improve the solution (i.e., now it doesn't work if we use * selections like 'SELECT * FROM TableA', doesn't support aliasing, and all fields in the SELECT should be [table].[field], but will give an idea of what I'm trying to achieve):
This way, I write an SQL statement in a textbox, I pass it onto a new form to check the actual results of the query (if I needed, by clicking on a button "Preview"), and I populate a datagridview with the SCHEMA data I wanted to retrieve.
Thanks to all for your support!
private void btnQuery_Click(object sender, EventArgs e)
{
string strSql = this.txtQuery.Text;
DataTable dt = new DataTable();
String conStr = "Data Source=(LocalDB)\\v11.0;AttachDbFilename=|DataDirectory|\\TestDB.mdf;Integrated Security=True;Connect Timeout=30";
using (SqlConnection conn = new SqlConnection(conStr))
{
//with the call to strSQLSchema, we get the table involved in the query, to retrieve the fields and properties
SqlCommand cmd = new SqlCommand(strSQLSchema(strSql), conn);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
try
{
adapter.Fill(dt);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
this.dgvColumns.DataSource = dt;
}
private void btnPreview_Click(object sender, EventArgs e)
{
//We must pass the sql query to preview
string strSql = this.txtQuery.Text;
SQLQueryDataPreview qp = new SQLQueryDataPreview(strSql);
qp.Show();
}
private string strSQLSchema(string sqlQuery)
{
//we cut the "SELECT " start
sqlQuery = sqlQuery.ToUpper();
sqlQuery = sqlQuery.Substring(7);
//we take all the fields until the FROM
int myIndex = sqlQuery.IndexOf("FROM");
sqlQuery = sqlQuery.Substring(0, myIndex);
sqlQuery = sqlQuery.Trim();
sqlQuery = sqlQuery.Replace(" ", string.Empty);
sqlQuery = sqlQuery.Replace("\r\n", string.Empty);
//Here we add all fields to a list... so far, "*" is not allowed, and all fields should be written [Table].[Name]
string[] myFields = sqlQuery.Split(new char[] {' ', ','});
List <string> myTables = new List<string>();
//We will use this WHERE to find the fields in the SCHEMA. This WHERE first sentence helps to construct a valid where
//and avoid problems with the 'OR' clause in each loop.
string myWhere = "TABLE_NAME + '.' + COLUMN_NAME = ''";
for (int i = 0; i < myFields.Count(); i++)
{
//here we take the table prefix and add it to an array
int tableIndex = myFields[i].IndexOf(".");
if (tableIndex != -1)
{
myTables.Add(myFields[i].Substring(0, tableIndex));
myWhere += "OR (TABLE_NAME + '.' + COLUMN_NAME = '" + myFields[i] + "')";
}
}
//this is a List where we keep the tables derivated from names. We just copy the list generated before with a DISTINCT to eliminate duplicates.
myTables = myTables.Distinct().ToList();
string schema = "SELECT Table_Name, Column_Name, Data_Type FROM INFORMATION_SCHEMA.COLUMNS WHERE " + myWhere;
return schema;
}
}
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?
I am working on a desktop application that populate the list of all tables containing primary key in a combobox on selecting the corresponding database from another combo box like this
///This function binds the names of all the tables without primary keys in a dropdown cmbResults.
public void GetNonPrimaryKeyTables()
{
//An instance of the connection string is created to manage the contents of the connection string.
var sqlConnection = new SqlConnectionStringBuilder();
//Declare the datasource,UserId,Password
sqlConnection.DataSource = "192.168.10.3";
sqlConnection.UserID = "gp";
sqlConnection.Password = "gp";
//Add the initial catalog to the connection string
sqlConnection.InitialCatalog = Convert.ToString(cmbDatabases.SelectedValue);
//Assign the ConnectionString value to a new variable
string connectionString = sqlConnection.ConnectionString;
//Create the connection object
SqlConnection sConnection = new SqlConnection(connectionString);
//To Open the connection.
sConnection.Open();
//Query to select table_names that doesn't have PRIMARY_KEY.
string selectNonPrimaryKeys = #"SELECT
TABLE_NAME
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE
CONSTRAINT_TYPE <> 'PRIMARY KEY'
ORDER BY
TABLE_NAME";
//Create the command object
SqlCommand sCommand = new SqlCommand(selectNonPrimaryKeys, sConnection);
try
{
//Create the dataset
DataSet dsListOfNonPrimaryKeys = new DataSet("INFORMATION_SCHEMA.TABLE_CONSTRAINTS");
//Create the dataadapter object
SqlDataAdapter sDataAdapter = new SqlDataAdapter(selectNonPrimaryKeys, sConnection);
//Provides the master mapping between the sourcr table and system.data.datatable
sDataAdapter.TableMappings.Add("Table", "INFORMATION_SCHEMA.TABLE_CONSTRAINTS");
//Fill the dataset
sDataAdapter.Fill(dsListOfNonPrimaryKeys);
//Bind the result combobox with non primary key table names
DataViewManager dvmListOfNonPrimaryKeys = dsListOfNonPrimaryKeys.DefaultViewManager;
cmbResults.DataSource = dsListOfNonPrimaryKeys.Tables["INFORMATION_SCHEMA.TABLE_CONSTRAINTS"];
cmbResults.DisplayMember = "TABLE_NAME";
cmbResults.ValueMember = ("");
}
catch(Exception ex)
{
//All the exceptions are handled and written in the EventLog.
EventLog log = new EventLog("Application");
log.Source = "MFDBAnalyser";
log.WriteEntry(ex.Message);
}
finally
{
//If connection is not closed then close the connection
if(sConnection.State != ConnectionState.Closed)
{
sConnection.Close();
}
}
}
But what I should do if I need to replace the combobox with a list view populating the same item when according to the selected database from another dropdown.
Can youguys please help me?
Instead of a ListView, try using a DataGridView, replacing these lines
cmbResults.DataSource = dsListOfNonPrimaryKeys.Tables["INFORMATION_SCHEMA.TABLE_CONSTRAINTS"];
cmbResults.DisplayMember = "TABLE_NAME";
cmbResults.ValueMember = ("");
with this
dataGridView1.DataSource = dsListOfNonPrimaryKeys.Tables["INFORMATION_SCHEMA.TABLE_CONSTRAINTS"];
You can set properties on the DataGridView to have it look more like a ListView, for example:
dataGridView1.RowHeadersVisible = false;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.AllowUserToDeleteRows = false;
Edit
Also, looking at your query, if your goal is to get the tables that don't have primary keys, try this:
select t.TABLE_NAME
from INFORMATION_SCHEMA.TABLES t
left join INFORMATION_SCHEMA.TABLE_CONSTRAINTS c
on t.TABLE_SCHEMA = c.TABLE_SCHEMA
and t.TABLE_NAME = c.TABLE_NAME
and c.CONSTRAINT_TYPE = 'PRIMARY KEY'
where t.TABLE_TYPE = 'BASE TABLE'
and c.CONSTRAINT_TYPE is null
The INFORMATION_SCHEMA.TABLE_CONSTRAINTS view also includes rows for FOREIGN KEY, CHECK, and UNIQUE constraints, so your query as it stands now will select the table names associated with any of these constraints.