Limiting the number of retrieved rows using Fill in ADOMD - c#

The following C# code runs a DAX statement and retrieves a DataTable. This works fine, but now I need to retrieve from the database up to N rows. Is there a way to limit the number of rows returned by the Fill function? If not, how can I retrieve the top N rows? Note that I need to keep this generic for any DAX statement, so you shouldn't change the DAX itself. Also, I don't want to retrieve all the data and then take the first N rows as the data may be too large.
public static DataTable runDaxStatement(int maxRows) {
var con = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
AdomdConnection conn = new AdomdConnection(con);
DataSet ds = new DataSet();
ds.EnforceConstraints = false;
AdomdCommand cmd = new AdomdCommand("evaluate customers", conn);
AdomdDataAdapter da = new AdomdDataAdapter(cmd);
da.Fill(ds);
return ds.Tables[0];
}

Came across the following TOPN function in the documentation.
This can be used to return the top N rows of the specified table.
For example
public static DataTable runDaxStatement(int maxRows) {
var connectionString = ConfigurationManager.ConnectionStrings["Default"].ConnectionString;
using(AdomdConnection connection = new AdomdConnection(connectionString)) {
string commandText = $"EVALUATE TOPN({maxRows}, customers, <orderBy_expression_here>)";
AdomdCommand command = connection.CreateCommand();
command.CommandText = commandText;
DataSet dataSet = new DataSet(){
EnforceConstraints = false
}
AdomdDataAdapter adapter = new AdomdDataAdapter(command);
adapter.Fill(dataSet);
return dataSet.Tables[0];
}
}

Related

C# reading values from datatable filled with sql select

I am coding win form app, which checks on startup right of the currently logged user. I had these right saved in MS SQL server in the table. When importing data to Datatable, there is no problem. But when I want to read value, there is message "cannot find column xy".
SqlDataAdapter sdaRights = new SqlDataAdapter("SELECT * FROM rights WHERE [user]='" + System.Security.Principal.WindowsIdentity.GetCurrent().Name + "'", conn);
DataTable dtRights = new DataTable(); //this is creating a virtual table
sdaRights.Fill(dtRights);
Object cellValue = dt.Rows[0][1];
int value = Convert.ToInt32(cellValue);
MessageBox.Show(value.ToString());
I would like, that program would save the value from SQL to int.
You are assuming that you have rows being returned, would be my first guess. You should loop through your DataTable instead of simply trying to access element 0 in it.
DataTable dtRights = new DataTable();
sdaRights.Fill(dtRights);
foreach(DataRow row in dtRights.Rows) {
Object cellValue = row[1];
int value = Convert.ToInt32(cellValue);
MessageBox.Show(value.ToString());
}
using (SqlConnection con = new SqlConnection("your connection string"))
{
using (SqlCommand cmd = new SqlCommand("SELECT [column_you_want] FROM [rights] WHERE [user] = #user"))
{
cmd.Parameters.AddWithValue("#user", System.Security.Principal.WindowsIdentity.GetCurrent().Name);
con.Open();
int right = Convert.ToInt32(cmd.ExecuteScalar());
}
}

dataset relation in c# for two columns

I would really appreciate a help in this code. I have a DataSet with two tables; I need to create a relation based on two columns as primary key:
public DataSet GetAll()
{
string sql = $#"SELECT * FROM Journal ORDER BY JvNO, cYear;
SELECT * FROM JournalDetail ORDER BY JvNO, cYear";
using (SqlConnection connection = new SqlConnection(GlobalConfig.ConnString()))
{
connection.Open();
SqlCommand cmd = new SqlCommand(sql, connection);
SqlDataAdapter da = new SqlDataAdapter(sql, connection);
DataSet ds = new DataSet();
da.Fill(ds);
ds.Relations.Add("Journal_Batch", new DataColumn[] { ds.Tables[0].Columns["JvNO"], ds.Tables[0].Columns["cYear"] },
new DataColumn[] { ds.Tables[1].Columns["JvNO"], ds.Tables[1].Columns["cYear"] });
return ds;
}
}
Currently, I'm doing it like this and it's working but I need it with DataSet relation:
public DataSet GetJournalByID(int JVNO, int cYear)
{
string sql = $#"SELECT * FROM Journal WHERE JvNO = { JVNO } and cYear = { cYear };
SELECT * FROM JournalDetail WHERE JvNO = { JVNO } and cYear = { cYear };";
using (SqlConnection connection = new SqlConnection(GlobalConfig.ConnString()))
{
connection.Open();
SqlCommand cmd = new SqlCommand(sql, connection);
SqlDataAdapter da = new SqlDataAdapter(sql, connection);
DataSet ds = new DataSet();
da.Fill(ds);
return ds;
}
}
I don't know what's wrong with first code, as it returns all matching JvNO or Year.
i want to use the first one to fill two grids as follow:
private void GetData()
{
DataSet currentDs = new DataSet();
grdJournalDetails.DataSource = null;
grdJournal.DataSource = null;
JournalConnector journalConnection = new JournalConnector();
currentDs = journalConnection.GetAll();
grdJournal.DataSource = currentDs.Tables[0];
grdJournalDetails.DataSource = currentDs.Tables[1];
}
then with each row selected from grdJournal to display grdJournalDetails with related data without calling each time the second snippet of code.
i used Dapper and i'm familiar with it, but with devexpress grid, it have to be a datatable to use the event gvJournal_FocusedRowChanged, otherwise datarow returns always null;
Thanks for any suggestion.

Retrieve Data From DataTable

I am running a SQL Query which will return a count the query is
Select Count(numstudents) from classA
I am using C# to connect to SQL Server and execute this query, but my issue is, how do I get the actual number returned? My current method returns the number of rows in the DataTable which by default will always be 1. I need to get the Count() returned.
Here is full C# syntax:
private void GetData()
{
DataSet ds = new DataSet()
using (var con = new SqlConnection(connectionString))
{
using (var cmd = new SqlCommand("RunAStoredProc", con))
{
using (var da = new SqlDataAdapter(cmd))
{
cmd.CommandType = CommandType.StoredProcedure;
da.Fill(ds);
}
}
}
DataTable table1 = new DataTable();
table1 = ds.Tables[0];
DataTable table2 = new DataTable();
table2 = ds.Tables[1];
string numberreturned = table1.Rows.Count.ToString();
Console.WriteLine(numberreturned);
Console.ReadKey();
}
Stored procedure reads like such:
Alter Procedure [dbo].[GetData]
As
Select Count(*) FROM classA
Select studentfirstname, studentlastname FROM classA
Where enrolled = 'Yes'
You don't need an SqlDataAdapter and all the infrastructure required to work with if you just have a single value returned by your Stored Procedure. Just use ExecuteScalar
int count = 0;
using (var con = new SqlConnection(connectionString))
using (var cmd = new SqlCommand("RunAStoredProc", con))
{
cmd.CommandType = CommandType.StoredProcedure;
count = (int)cmd.ExecuteScalar();
}
Console.WriteLine(count);
Console.ReadKey();
However if your really want to use an adapter and a dataset then you can find the result of your query reading the value from the first row and first column from the returned table
int count = Convert.ToInt32(table1.Rows[0][0]);
or even (without declaring the table1 variable)
int count = Convert.ToInt32(ds.Tables[0].Rows[0][0]);
To discover the difference between the result of the first select statement and the count of rows returned in the second select statement you could write
int allStudents = Convert.ToInt32(ds.Tables[0].Rows[0][0]);
int enrolledStudents = ds.Tables[1].Rows.Count;
int notEnrolledStudents = allStudents - enrolledStudents;

Retrieve records from Mysql database and display it in a combo box

I have a DbConnect class which queries a MySQL database and store the results into a datatable - something like this:
public DataTable selectCombo()
{
string query = "SELECT DISTINCT month FROM printer_count";
if (this.OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
DataTable dt = new DataTable();
MySqlDataAdapter da = new MySqlDataAdapter(cmd);
da.Fill(dt);
}
this.CloseConnection();
return dt;
}
Now how to retrieve the datatable from the class into the combo box main form? Can I do something like this?
ComboBox1.DataSource = dbConnect();
ComboBox1.DisplayMember = "Name"; // column name to display
You have two variables with the same name. (dt) One is defined as a string, the other one inside the if block is defined as a datatable. You return the empty string and this, of course, cannot work when you try to assign the DataSource of the combo
public DataTable selectCombo()
{
DataTable dt = new DataTable();
string query = "SELECT DISTINCT month FROM printer_count";
if (this.OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataAdapter da = new MySqlDataAdapter(cmd);
da.Fill(dt);
}
this.CloseConnection();
return dt;
}
Now you could write
....
ComboBox1.DisplayMember = "Name";
ComboBox1.DataSource = selectCombo();
.....
Also this code is not very safe. If, for any reason, you get an exception, the CloseConnection will not be called leaving an open connection around and this is very problematic for the stability of your system. However, fixing that problem, requires a different approach to you OpenConnection code. Instead of true this method should return the MySqlConnection object so your calling code could apply the using statement around the connection instance

DataSet, SqlDataAdapter, Multiple select returns one table

I would like to make one call (containing several SELECT statement) to the database and then databind the results to multiple components.
I'm using a DataSet and SqlDataAdapter to fill tables that are then bound to components.
Problem is the results of the first SELECT statement are put into both tables so I get a "'System.Data.DataRowView' does not contain a property..." error when I try to use the second lot of data on the second component.
Have I misunderstood how this is meant to work?
DataSet ds = new DataSet();
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["myString"].ConnectionString);
StringBuilder topicDropDownListSQL = new StringBuilder();
topicDropDownListSQL.Append("SELECT topic.topic_ID, topic.topic_title FROM FPL2012_TOPIC as topic WHERE topic.topic_isEnabled = 1;");
topicDropDownListSQL.Append("SELECT explain.itemExplanationType_ID, explain.itemExplanationType_type FROM FPL2012_ITEM_EXPLANATION_TYPE as explain;");
SqlDataAdapter da = new SqlDataAdapter(topicDropDownListSQL.ToString(), connection);
ds.Tables.Add("Topics");
ds.Tables.Add("ExplainType");
ds.EnforceConstraints = false;
ds.Tables["Topics"].BeginLoadData();
da.Fill(ds.Tables[0]);
ds.Tables["Topics"].EndLoadData();
ds.Tables["ExplainType"].BeginLoadData();
da.Fill(ds.Tables[1]);
ds.Tables["ExplainType"].EndLoadData();
topicDropDownList.DataValueField = "topic_ID";
topicDropDownList.DataTextField = "topic_title";
topicDropDownList.DataSource = ds.Tables["Topics"];
topicDropDownList.DataBind();
explanationTypeDropDownList.DataValueField = "itemExplanationType_ID";
explanationTypeDropDownList.DataTextField = "itemExplanationType_type";
explanationTypeDropDownList.DataSource = ds.Tables["ExplainType"];
explanationTypeDropDownList.DataBind();
connection.Close();
You can use this acces the tables by there indexes not by there names
DataSet ds = new DataSet();
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["myString"].ConnectionString);
String qry="SELECT topic_ID,topic_title FROM FPL2012_TOPIC WHERE topic_isEnabled = 1; SELECT itemExplanationType_ID, itemExplanationType_type FROM FPL2012_ITEM_EXPLANATION_TYPE ";
SqlDataAdapter da = new SqlDataAdapter(qry, connection);
da.Fill(ds)
topicDropDownList.DataValueField = "topic_ID";
topicDropDownList.DataTextField = "topic_title";
topicDropDownList.DataSource = ds.Tables[0];
topicDropDownList.DataBind();
explanationTypeDropDownList.DataValueField = "itemExplanationType_ID";
explanationTypeDropDownList.DataTextField = "itemExplanationType_type";
explanationTypeDropDownList.DataSource = ds.Tables[1];
explanationTypeDropDownList.DataBind();
connection.Close();
OK, I tried using a datareader next, didn't expect it to work but it does! I can make multiple select statements and then fill multiple componenets. I'm not marking this as an answer as I still think it would be useful to know how to do it using the dataset.
The new code that worked for me (in case it is useful):
string connectionString = WebConfigurationManager.ConnectionStrings["myString"].ConnectionString;
SqlConnection connection = new SqlConnection(connectionString);
StringBuilder sql = new StringBuilder();
sql.Append("SELECT topic.topic_ID, topic.topic_title FROM FPL2012_TOPIC as topic WHERE topic.topic_isEnabled = 1;");
sql.Append("SELECT explain.itemExplanationType_ID, explain.itemExplanationType_type FROM FPL2012_ITEM_EXPLANATION_TYPE as explain;");
SqlCommand command = new SqlCommand(sql.ToString(), connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
topicDropDownList.DataSource = reader;
topicDropDownList.DataValueField = "topic_ID";
topicDropDownList.DataTextField = "topic_title";
topicDropDownList.DataBind();
reader.NextResult();
explanationTypeDropDownList.DataSource = reader;
explanationTypeDropDownList.DataValueField = "itemExplanationType_ID";
explanationTypeDropDownList.DataTextField = "itemExplanationType_type";
explanationTypeDropDownList.DataBind();
reader.Close();
connection.Close();

Categories