System.Data.SqlClient.SqlException: 'Ambiguous column name
'SchoolID'.'
I need to select a SchoolName == SchoolID and an AcademicYear from two combo-boxes that are found in two database tables School-Info and School_AcademicYear
Also SchoolID in School_AcademicYear is Foreign Key and its Primary Key in School_Info, I am using inner join to join these two tables but an error is occuring
Ambiguous column name 'SchoolID'
con.Open();
adp = new SqlDataAdapter("SELECT AcademicYearID,AcademicYear,SchoolID FROM School_AcademicYear INNER JOIN School_Info ON School_AcademicYear.AcademicYearID = School_Info.SchoolID where School_AcademicYear.AcademicYearID = '" + AcademicYearID + "'", con);
dt = new DataTable();
adp.Fill(dt);
dataGridViewSchoolNMergeAcYear.DataSource = dt;
con.Close();
If you join two tables that contain columns with the same name and you refer to one of these columns in the SELECT list, then you need to specify from which table are you getting the values. So to solve this problem let's start using some alias for the table names. Using the alias in front of the column's name correctly identify the columns source table.
While at it, I have also changed your string concatenation to a parameterized query. It is a lot better because it avoids parsing errors and a well known security problem called Sql Injection
using(SqlConnection con = new SqlConnection(.......))
{
string cmdText = #"SELECT a.AcademicYearID,a.AcademicYear,i.SchoolID
FROM School_AcademicYear a INNER JOIN School_Info i
ON a.AcademicYearID = i.SchoolID
WHERE a.AcademicYearID = #id";
con.Open();
adp = new SqlDataAdapter(cmdText, con);
adp.SelectCommand.Parameters.Add("#id", SqlDbType.Int).Value = AcademicYearID;
dt = new DataTable();
adp.Fill(dt);
dataGridViewSchoolNMergeAcYear.DataSource = dt;
}
To be complete this answer introduces also the using statement around the disposable connection object. In this way the connection is closed and disposed when the code exits the using block. Note that I suppose that AcademicYearID is a number and not a string so, the parameter is of type SqlDbType.Int instead of NVarChar.
You have multiple columns in those tables with name SchoolID.
You have to specify the column name, because sql cannot know which one you want. Example: School_Info.SchoolID
adp = new SqlDataAdapter(`
SELECT AcademicYearID,AcademicYear,School_Info.SchoolID
FROM School_AcademicYear
INNER JOIN School_Info ON School_AcademicYear.AcademicYearID = School_Info.SchoolID
where School_AcademicYear.AcademicYearID = '` + AcademicYearID + "'", con);
Related
Error Description
myCon = new SqlConnection(#"myconnectionstring");
myCon.Open();
string id_trender = "UPDATE b SET b.id_trender = #a.id_trender FROM trenders a JOIN adjustments b ON a.dim_name_trender = b.name";
//var cmd1 = new SqlCommand(id_trender, myCon);
cmd1 = new SqlCommand("INSERT INTO adjustments(id_trender) VALUES" + "(#id_trender)", myCon);
// cmd1.Parameters.AddWithValue("#id_trender", SqlDbType.Int).Value = id_trender;
cmd1.Parameters.Add(new SqlParameter("#id_trender", id_trender));
cmd1.ExecuteNonQuery();
myCon.Close();
I get this error when making a connection to my database in SQL Server Management Studio.
I have a two tables with id_trender in one table and I'm using an inner join to insert the id_trender into another table. Basically, I want to match the id on trender table to the name in adjustments table.
Here is my table structure in SQL:
Adjustments table:
id, name, id_trender
Trenders table:
dim_name_trender, id_trender
Solution was just to have the update statement because I am already connected to the server:
string id_trender = "update b set b.id_trender = a.id_trender FROM trenders a JOIN adjustments b ON a.dim_name_trender = b.name";
Try this:
cmd1 = new SqlCommand("INSERT INTO adjustments(id_trender) VALUES #id_trender)", myCon);
I have used the INFORMATION_SCHEMA to get all tables and columns of my database.
DataTable dt_search_BaseTables = new DataTable();
MySqlDataAdapter mAdapter;
MySqlCommand myCommand = new MySqlCommand(#"SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME,
COLUMN_DEFAULT, COLUMN_TYPE, COLUMN_KEY FROM
INFORMATION_SCHEMA.COLUMNS", connection);
mAdapter = new MySqlDataAdapter(myCommand);
mAdapter.Fill(dt_search_BaseTables);
But if I want to select a specific table_name to get only the columns of one table that doesn't work:
DataRow[] dr = dt_search_BaseTables.Select("TABLE_NAME=" + stablename);
I get the
ERROR: The column [stablename] could not be found.
How can I solve that problem?
The issue is quite simple: you need to add single quotes around the passed table name inside stablename, then it treated the passed value as string literal assignment due to Select method has same expression rule as RowFilter syntax.
Therefore it should be like this:
DataRow[] dr = dt_search_BaseTables.Select("TABLE_NAME = '" + stablename + "'");
or create a string variable then pass it into Select method:
string expression = "TABLE_NAME = '" + stablename + "'";
DataRow[] dr = dt_search_BaseTables.Select(expression);
Reference:
DataTable.Select Method (MSDN)
I'd suggest you to add WHERE condition to the SELECT query. It will help to filter a huge set of unnecessary tables on server side -
For example -
SELECT
TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, COLUMN_DEFAULT, COLUMN_TYPE, COLUMN_KEY
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME = '{1}';
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)
I'm trying to update my SQL backend with data that has changed in my webform.
That data is initially fetched from SQL like so
string cs = ConfigurationManager.ConnectionStrings["ConnectionString"].ToString();
SqlConnection connection = new SqlConnection(cs);
SqlCommand command = new SqlCommand("my.storedprocedure", cs);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#customerID", custid));
command.CommandTimeout = 300;
connection.Open();
SqlDataAdapter sda = new SqlDataAdapter(command);
connection.Close();
sda.FillSchema(myDataTable, SchemaType.Source);
sda.Fill(myDataTable);
The stored procedure makes a selection
SELECT c.*
,cs.*
,p.*
,sl.*
,drl.*
FROM tableC as c
INNER JOIN tableCS as cs ON c.[custID] = cs.[custID]
INNER JOIN tableSL as sl ON cs.[custStatusID] = sl.[custStatusID]
LEFT OUTER JOIN tableP as p ON c.custID = p.custID
LEFT OUTER JOIN tableDRL as drl ON cs.custID = drl.custID
WHERE c.[custID] = #custID AND c.[EndDate] IS NULL AND cs.[EndDate] IS NULL
I then manipulate the data table that is filled with this stored procedure, call a dt.NewRow(), add values to that new row, add the row into the data table. Set fields in the previous row, etc.
My question is, when I get ready to call a SqlDataAdapter.Update(myDataTable) will the data adapter go ahead and make the update to all the tables I joined too? Based on what's in my data table?
The short answer is no - a single adapter is for a single table. You need to use a DataSet if you are using ADO.NET.
Using a DataSet:
Populating a DataSet from a DataAdapter
ADO.NET - Updating Multiple DataTables
Fill DataSet with multiple Tables and update them with DataAdapter
Using TableAdapterManager:
TableAdapterManager Overview
I'm sure all table names are ok. I want to get the list of players of each team.
public List<Speler> getSpelersPerPloeg(int ploegID)
{
List<Speler> spelersLijst = new List<Speler>();
connection.Open();
OleDbCommand command = new OleDbCommand("select * from proj1Speler inner join proj1Ploeg on proj1Speler.ploegID = proj1Ploeg.ploegID where proj1Ploeg.ploegID = #ploegID", connection);
command.Parameters.Add(new OleDbParameter("#ploegID", ploegID));
OleDbDataReader dataReader = command.ExecuteReader();
while (dataReader.Read())
{
spelersLijst.Add(new Speler((int)dataReader["spelerID"], dataReader["spelerNaam"].ToString(), (int)dataReader["ploegID"], dataReader["ploegNaam"].ToString(), (int)dataReader["spelerTypeID"]));
}
dataReader.Close();
connection.Close();
return spelersLijst;
}
It trows the error with ploegID on this line " spelersLijst.Add(new Speler((...", any ideas?
And the funny thing is with sql server it works without any problem, maybe my relations in Acces are wrong?
You are joining the two tables using the *, in this way fields from both tables are returned from your query.
But what happens when you have two fields with the same name from the two different tables in the same query? Some automatic renaming occurs, the tablename is added to the two identical field names to disambiguate the column name.
So when you try to use the simple name (without the table name) you get the error. I bet that the culprit is the "ploegID" field that appears in both tables.
I suggest to return just the field names really required by your code
OleDbCommand command = new OleDbCommand(#"select ps.spelerID, ps.spelerNaam,
pp.ploegID, pp.ploegNaam, ps.spelerTypeID
from proj1Speler ps
inner join proj1Ploeg pp
on ps.ploegID = pp.ploegID
where pp.ploegID = #ploegID", connection);
command.Parameters.Add(new OleDbParameter("#ploegID", ploegID));
OleDbDataReader dataReader = command.ExecuteReader();
(Note, I am not really sure about what field is contained in which table, this is just to get the idea)