I use the following code to execute a query in C#:
AdomdConnection con = new AdomdConnection("Datasource=local;...");
con.Open();
AdomdCommand command = con.CreateCommand();
command.CommandText = input;
AdomdDataReader reader = command.ExecuteReader();
while (reader.Read())
{
for(i =0; i<reader.fieldCount; i++){
a[i]=reader.GetString(i);
}
return a;
Howeever, this code returns the full path in the hierarchy for each cell. I.e., each row of data is like [AllGeography, Canada, Vancouver, Allproduct, bikes, accessories, 297483].
I want to retrieve only the leaves and the measure value that is :[vancouver, accessories, 297483]. What should I do? How I can specify the leaves?
Because the result of MDX query is actually multidimentional, i feel myself more comfortable with ExecuteCellSet. You can get the whole CellSet, then you get Measures via coordinates.
For example (if you have one measure in query):
AdomdCommand cmd = conn.CreateCommand();
cmd.CommandText = #"SELECT
[Geography].[Geography].[Country].&[Canada].Children ON 0,
[Product].[Id] ON 1
FROM [Cube]
WHERE [Measures].[Your Measure]";
CellSet cs = cmd.ExecuteCellSet();
TupleCollection CanadaChildren = cs.Axes[0].Set.Tuples;
TupleCollection ProductIds = cs.Axes[1].Set.Tuples;
for (int row = 0; row < CanadaChildren.Count; row++)
{
for (int col = 0; col < ProductIds.Count; col++)
{
a[i++] = cs.Cells[col, row].Value;
}
}
conn.Close();
If you have several measures, than it will be a third dimention in query and a third cooridinate in a cellset.
Related
I have a table with some columns like
now I want to use a for loop to set
out_0 = 0,
out_1 = 1,
out_2 = 2,
out_3 = 3,
out_4 = 4
so I update it with such code as
string sql = "update exchange_out set #column = #id where member_id = 6;";
SqlCommand cmd = new SqlCommand(sql, connet);
cmd.Parameters.Add("#column", SqlDbType.NVarChar);
cmd.Parameters.Add("#id", SqlDbType.Int);
int n = 0;
for (int i = 0; i < 5; i++)
{
cmd.Parameters["#column"].Value = "out_" + i;
cmd.Parameters["#gid"].Value = i;
n = cmd.ExecuteNonQuery();
MessageBox.Show("" + n);
}
but it didn't write any data into the table while it literally did five times of updating, because the messagebox returns "1" five times.
finally I solve this by
for (int i = 0; i < 5; i++){
sql = string.Format("update exchange_out set {0} = {1} where member_id = 6", "out_" + i, i);
}
but I'm still wondering why it didn't work by adding parameters?
any respond will be appreciated. :)
I'm still wondering why it didn't work by adding parameters?
Identifiers such as table and column names cannot be parameterized in this way, only data. Your attempt effectively runs a query like this:
update exchange_out set 'out_1' = 1 where member_id = 6;
It's the same in any programming language:
var data1 = "hello";
var whichData = "1";
Console.WriteLine(data+whichData); //it doesn't compile; you cannot programmatically build a variable name `data1` in this way
The way you found is reasonably the only way but you should still parameterize the data:
using var cmd = new SqlCommand(sql, connet);
cmd.Parameters.Add("#data", SqlDbType.NVarChar);
cmd.Parameters.Add("#id", SqlDbType.Int);
for (int i = 0; i < 5; i++){
sql = string.Format("update exchange_out set out_{0} = #data where member_id = #id", i);
cmd.CommandText = sql;
cmd.Parameters["#data"].Value = ...
cmd.Parameters["#id].Value = 6;
...
You could also start with an SQL stub like "UPDATE t SET " and repeatedly concatenate on identifiers and parameters:
using var cmd = new SqlCommand(sql, connet);
cmd.Parameters.Add("#data", SqlDbType.NVarChar);
cmd.Parameters.Add("#id", SqlDbType.Int);
var sql = "UPDATE exchange_out SET ";
for (int i = 0; i < 5; i++){
sql += string.Format("out_{0} = #data{0},", i);
cmd.Parameters["#data"+i].Value = ...
}
sql = sql.TrimEnd(',');
sql += " where member_id = #id";
cmd.Parameters["#id"].Value = 6;
cmd.CommandText = sql;
...
This does the update in one operation, running a query like UPDATE t SET out_1 = #data1, out_2 = #data2 ...
These are safe from SQL injection because your code controls the entire SQL; there isn't any capacity for a user to provide '; DROP TABLE Students;-- as the {0} going into the identifier in this case but take care that you don't arrange for it to be possible (don't let the user provide identifier text)..
Your non-parameter attempt is also safe from SQL injection in this case by virtue of inserting intergers that you control, rather than strings you don't, but be careful you don't universally apply the technique and one day include user-suppied strings. If you do find yourself in that suitable you should use something like a whitelist of user input - any string identifier provided by the user that isn't whitelisted should not be put in the SQL
Using OleDbDataAdapter SQL query to search for secific entry in access database.
OleDbDataAdapter adapter1 = new OleDbDataAdapter(#"SELECT Gallery_Number FROM Paintings WHERE Painting Number = '" + searchString + "'", myDB);
searchString = Convert.ToString( adapter);
searchString returns System.Data.OleDb.OleDbDataAdapter and not a Gallery number.
I would like to know how to get the value of this adapter and put it into a textbox.
First of all, I'd use a Scalar for this, since you only return a single value.
OleDbCommand command = new OleDbCommand(queryString, connection);
command.Connection.Open();
int galeryNumber = (int)command.ExecuteScalar();
But let's take a look at your code:
DataSet galNum = new DataSet();
oledbAdapter.Fill(galNum);
int galeryNumber = int.Parse(ds.Tables[0].Rows[0].ItemArray[0].ToString());
The best way to gain access to a OleDbDataAdapter is by converting the result set into a `DataSet. Then you can iterate through this set.
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
DataRow dr = ds.Tables[0].Rows[i]; //One result line in your set
//DataRow contains n columns
for (int i = 0; i < ds.Tables[0].Columns.Count; i++)
{
string someEntry = dr[i].ToString();
}
}
I am new to Servicestack Ormlite.
I want to execute the SQL query on database using Servicestack Ormlite and get the results in datatable.
SQL query will be generated randomly, containing different tables, columns each time. So I can't use poco class for the same.
We are using SQL Server as the database.
OrmLite doesn't support or have any dependencies on DataTables or DataSets which as a code-first POCO ORM is strictly opposed against the use of.
See the Dynamic Result Set docs for examples of querying untyped structures, either in a object List:
db.Select<List<object>>(db.From<Poco>()
.Select("COUNT(*), MIN(Id), MAX(Id)"));
Or Dictionary:
db.Select<Dictionary<string,object>>(db.From<Poco>()
.Select("COUNT(*) Total, MIN(Id) MinId, MAX(Id) MaxId"));
you can use CreateCommand method to get a datareader, like this:
var dt = new DataTable();
using (var db = dbFactory.Open())
using (var cmd = db.CreateCommand())
{
cmd.CommandText = "select * from [table]";
cmd.CommandType = CommandType.Text;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var row = dt.NewRow();
for (int i = 0; i < reader.FieldCount; i++)
{
if (dt.Columns == null || dt.Columns.Count == 0)
{
for (int j = 0; j < reader.FieldCount; j++)
{
dt.Columns.Add(reader.GetName(j), reader.GetFieldType(j));
}
}
var cell = reader.GetValue(i);
row[i] = cell;
}
dt.Rows.Add(row);
}
}
}
I intend to populate an access DB table that has three columns; Entity(text type), Date and Value(double type).
I wrote the following code by going through some online links. Although the code runs fine, the table has no data. I am probably missing some part. Any advice?
for (int i = 0; i < model.CDFResults.Count; i++)
{ // connection details to the DB here...
for (int j = 0; j < model.CDFResults[i].DataPoints.Count; j++)
{
OleDbCommand myAccessCommand = new OleDbCommand();
myAccessCommand.CommandType = CommandType.Text;
myAccessCommand.CommandText = "INSERT INTO TypeCurves([Entity],[Date],[Value])VALUES(?,?,?)";
myAccessCommand.Parameters.AddWithValue("#Entity", model.CDFResults[i].catname_db);
myAccessCommand.Parameters.AddWithValue("#Date", model.CDFResults[i].DataPoints[j].dt);
myAccessCommand.Parameters.AddWithValue("#Value", model.CDFResults[i].DataPoints[j].CDFVal);
} // end of FOR(j) loop
} // end of FOR(i) loop
EDIT: Still not working
for (int i = 0; i < model.CDFResults.Count; i++)
{ // connection details to the DB here...
for (int j = 0; j < model.CDFResults[i].DataPoints.Count; j++)
{
OleDbConnection thisConnection = new OleDbConnection(connectionname);
thisConnection.Open();
OleDbCommand myAccessCommand = new OleDbCommand();
myAccessCommand.CommandType = CommandType.Text;
myAccessCommand.CommandText = "INSERT INTO TypeCurves([Entity],[Date],[Value])VALUES(?,?,?)";
myAccessCommand.Parameters.AddWithValue("#Entity", model.CDFResults[i].catname_db);
myAccessCommand.Parameters.AddWithValue("#Date", model.CDFResults[i].DataPoints[j].dt);
myAccessCommand.Parameters.AddWithValue("#Value", model.CDFResults[i].DataPoints[j].CDFVal);
myAccessCommand.ExecuteNonQuery();
} // end of FOR(j) loop
} // end of FOR(i) loop
You need create the connection to the database and execute the query.
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
string query = "INSERT INTO TypeCurves([Entity],[Date],[Value])VALUES(#Entity,#Date,#Value)";
OleDbCommand myAccessCommand = new OleDbCommand(query, connection);
myAccessCommand.Parameters.AddWithValue("#Entity", model.CDFResults[i].catname_db);
myAccessCommand.Parameters.AddWithValue("#Date", model.CDFResults[i].DataPoints[j].dt);
myAccessCommand.Parameters.AddWithValue("#Value", model.CDFResults[i].DataPoints[j].CDFVal);
connection.Open();
myAccessCommand.ExecuteNonQuery();
}
connectionString is whatever your connection string is to your database.
In this example you don't need to explicitly close the connection after the query is executed as the connection is wrapped in a using block, and so will be disposed of once it has exited the block.
https://msdn.microsoft.com/en-us/library/system.data.oledb.oledbcommand.executenonquery(v=vs.110).aspx
For example, the following code prints "System.Int32", not "int":
string connArgs = "..."; // use your settings here
string query = "SELECT 1";
using (SqlConnection conn = new SqlConnection(connArgs)) {
conn.Open();
SqlCommand cmd = new SqlCommand(query, conn);
using (SqlDataReader reader = cmd.ExecuteReader())
for (int col = 0; col < reader.VisibleFieldCount; ++col)
Console.WriteLine(reader.GetFieldType(col));
}
How can I obtain the underlying SQL type, not just its equivalent .NET system type?
You can use a GetDataTypeName method for that:
Gets a string representing the data type of the specified column.
for (int col = 0; col < reader.VisibleFieldCount; ++col) {
Console.WriteLine(reader.GetDataTypeName(col));
}