Retrieve Cellset Value in SSAS\MDX - asp.net

Im writing SSAS MDX queries involving more than 2 axis' to retrieve a value. Using ADOMD.NET, I can get the returned cellset and determine the value by using
lblTotalGrossSales.Text = CellSet.Cells(0).Value
Is there a way I can get the CellSet's Cell(0) Value in my MDX query, instead of relying on the data returning to ADOMD.NET?
thanks!
Edit 1: - Based on Daryl's comment, here's some elaboration on what Im doing. My current query is using several axis', which is:
SELECT {[Term Date].[Date Calcs].[MTD]} ON 0,
{[Sale Date].[YQMD].[DAY].&[20121115]} ON 1,
{[Customer].[ID].[All].[A612Q4-35]} ON 2,
{[Measures].[Loss]} ON 3
FROM OUR_CUBE
If I run that query in Management Studio, I am told Results cannot be displayed for cellsets with more than two axes - which makes sense since.. you know.. there's more than 2 axes. However, if I use ADOMD.NET to run this query in-line, and read the returning value into an ADOMD.NET cellset, I can check the value at cell "0", giving me my value... which as I understand it (im a total noob at cubes) is the value sitting where all these values intersect.
So to answer your question Daryl, what I'd love to have is the ability to have the value here returned to me, not have to read in a cell set into the calling application. Why you may ask? Well.. ultimately I'd love to have one query that performs several multi-axis queries to return the values. Again.. Im VERY new to cubes and MDX, so it's possible Im going at this all wrong (Im a .NET developer by trade).

Simplify your query to return two axis;
SELECT {[Measures].[Loss]} ON 0, {[Term Date].[Date Calcs].[MTD] * [Sale Date].[YQMD].[DAY].&[20121115] * [Customer].[ID].[All].[A612Q4-35]} ON 1 FROM OUR_CUBE
and then try the following to access the cellset;
string connectionString = "Data Source=localhost;Catalog=AdventureWorksDW2012";
//Create a new string builder to store the results
System.Text.StringBuilder result = new System.Text.StringBuilder();
AdomdConnection conn = new AdomdConnection(connectionString);
//Connect to the local serverusing (AdomdConnection conn = new AdomdConnection("Data Source=localhost;"))
{
conn.Open();
//Create a command, using this connection
AdomdCommand cmd = conn.CreateCommand();
cmd.CommandText = #"SELECT { [Measures].[Unit Price] } ON COLUMNS , {[Product].[Color].[Color].MEMBERS-[Product].[Color].[]} * [Product].[Model Name].[Model Name]ON ROWS FROM [Adventure Works] ;";
//Execute the query, returning a cellset
CellSet cs = cmd.ExecuteCellSet();
//Output the column captions from the first axis//Note that this procedure assumes a single member exists per column.
result.Append("\t\t\t");
TupleCollection tuplesOnColumns = cs.Axes[0].Set.Tuples;
foreach (Microsoft.AnalysisServices.AdomdClient.Tuple column in tuplesOnColumns)
{
result.Append(column.Members[0].Caption + "\t");
}
result.AppendLine();
//Output the row captions from the second axis and cell data//Note that this procedure assumes a two-dimensional cellset
TupleCollection tuplesOnRows = cs.Axes[1].Set.Tuples;
for (int row = 0; row < tuplesOnRows.Count; row++)
{
for (int members = 0; members < tuplesOnRows[row].Members.Count; members++ )
{
result.Append(tuplesOnRows[row].Members[members].Caption + "\t");
}
for (int col = 0; col < tuplesOnColumns.Count; col++)
{
result.Append(cs.Cells[col, row].FormattedValue + "\t");
}
result.AppendLine();
}
conn.Close();
TextBox1.Text = result.ToString();
} // using connection
Source : Retrieving Data Using the CellSet

This is fine upto select on columns and on Rows. It will be helpful analyze how to traverse sub select queries from main query.

Related

.Net Core Npgsql Return Single Row

I was just wondering if it's possible to return a single row using Npgsql in a .Net Core Script.
I've been doing with the Read Method like bellow
NpgsqlCommand command = new NpgsqlCommand (
" select col01, col02, col03 from table ",
dbconnection
);
var result = command.ExecuteReader();
while(result.Read()) {
var varCol01 = result["col01"];
var varCol02 = result["col02"];
}
Which seems a bit excessive for a single row because I would have to exit the while manually.
Each time you call NpgsqlDataReader.Read, you're reading an additional row - so your code sample doesn't seem to be a good fit for a single row scenario...
If you know you're only getting a single row, why not do something along the lines of:
var reader = command.ExecuteReader();
reader.Read(); // You can do a Debug.Assert to make sure the result of this is true
var (col1, col2) = (result["col01"], result["col02"]);

Asp.net gridview insert calculations

I want to create code where if for example the dropdown list is = to linemen then his monthly salary is = 6000 and I want this to be put into monthly salary column in my database.
Here is the code - with this code I get error in monthlysalary parameters saying
use of unassigned local variable total
Code:
float total;
if (Designation.SelectedValue == "Linemen")
{
total = 4000;
}
if (Designation.SelectedValue == "Manager")
{
total = 6000;
}
if (Designation.SelectedValue == "Boss")
{
total = 8000;
}
string emp = datapayemp.SelectedRow.Cells[1].Text;
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["connect"].ConnectionString);
string command = "INSERT INTO PAYROLL(RegEmpID, MonthlySalary) VALUES (#RegEmpID, #MonthlySalary)";
SqlCommand cmd = new SqlCommand(command, con);
cmd.Parameters.AddWithValue("#RegEmpID", emp);
cmd.Parameters.AddWithValue("#MonthlySalary",total);
try
{
con.Open();
cmd.ExecuteNonQuery();
}
finally
{
con.Close();
}
Well, the problem is: you're not initializing total to any value - and if the Designation.SelectedValue is neither Linemen, Manager nor Boss, then there's never any value assigned to total.
You need to give that total an initial value, just in case none of the if clauses match:
float total = 0.0;
Also: float is notorious for rounding errors etc. - so if you're dealing with money values, I would strongly recommend to use the decimal datatype instead. Same goes for the SQL Server database table: don't use FLOAT or REAL - use DECIMAL(p,s) instead

Faster database access by index

I have this code
using (var contents = connection.CreateCommand())
{
contents.CommandText = "SELECT [subject],[note] FROM tasks";
var r = contents.ExecuteReader();
int zaehler = 0;
int zielzahl = 5;
while (r.Read())
{
if (zaehler == zielzahl)
{
//access r["subject"].ToString()
}
zaehler++;
}
}
I want to make it faster by accessing zielzahl directly like r[zielzahl] instead of iterating through all entries. But
r[zielzahl]["subject"]
does not work aswell as
r["subject"][zielzahl]
How do I access the column subject of result number zielzahl?
To get only the sixth record, use the OFFSET clause:
SELECT subject, note
FROM tasks
LIMIT 1 OFFSET 5
Please note that the order of returned records is not guaranteed unless you use the ORDER BY clause.

bulk insertion in MS SQL from a text file

I have a text file that contains around 21 lac entries and I want to insert all these entries into a table. Initially I have created one function in c# that read line by line and insert into table but it takes too much time. Please suggest an efficient way to insert these bulk data and that file is containing TAB(4 spaces) as delimiter.
And that text file also containing some duplicate entries and I don't want to insert those entries.
Load all of your data into a DataTable object and then use SqlBulkCopy to bulk insert them:
DataTable dtData = new DataTable("Data");
// load your data here
using (SqlConnection dbConn = new SqlConnection("db conn string"))
{
dbConn.Open();
using (SqlTransaction dbTrans = dbConn.BeginTransaction())
{
try
{
using (SqlBulkCopy dbBulkCopy = new SqlBulkCopy(dbConn, SqlBulkCopyOptions.Default, dbTrans))
{
dbBulkCopy.DestinationTableName = "intended SQL table name";
dbBulkCopy.WriteToServer(dtData );
}
dbTrans.Commit();
}
catch
{
dbTrans.Rollback();
throw;
}
}
dbConn.Close();
}
I've included the example to wrap this into a SqlTransaction so there will be a full rollback if there's a failure along the way. To get you started, here's a good CodeProject article on loading the delimited data into a DataSet object.
Sanitizing the data before loading
OK, here's how I think your data looks:
CC_FIPS FULL_NAME_ND
AN Xixerella
AN Vila
AN Sornas
AN Soldeu
AN Sispony
... (cut down for brevity)
In this instance you want to create your DataTable like this:
DataTable dtData = new DataTable("Data");
dtData.Columns.Add("CC_FIPS");
dtData.Columns.Add("FULL_NAME_ND");
Then you want to iterate each row (assuming your tab delimited data is separated row-by-row by carriage returns) and check whether this data already exists in the DataTable using the .Select method and if there is a match (i'm checking for BOTH values, it's up to you whether you want to do something else) then don't add it thereby preventing duplicates.
using (FileStream fs = new FileStream("path to your file", FileMode.Open, FileAccess.Read))
{
int rowIndex = 0;
using (StreamReader sr = new StreamReader(fs))
{
string line = string.Empty;
while (!sr.EndOfStream)
{
line = sr.ReadLine();
// use a row index to skip the header row as you don't want to insert CC_FIPS and FULL_NAME_ND
if (rowIndex > 0)
{
// split your data up into a 2-d array tab delimited
string[] parts = line.Split('\t');
// now check whether this data has already been added to the datatable
DataRow[] rows = dtData.Select("CC_FIPS = '" + parts[0] + "' and FULL_NAME_ND = '" + parts[1] + "'");
if (rows.Length == 0)
{
// if there're no rows, then the data doesn't exist so add it
DataRow nr = dtData.NewRow();
nr["CC_FIPS"] = parts[0];
nr["FULL_NAME_ND"] = parts[1];
dtData.Rows.Add(nr);
}
}
rowIndex++;
}
}
}
At the end of this you should have a sanitized DataTable that you can bulk insert. Please note that this code isn't tested, but it's a best guess as to how you should do it. There are many ways this can be done, and probably a lot better than this method (specifically LINQ) - but it's a starting point.

C# - Insert Multiple Records at once to AS400

I have a problem like this:
1. I retrieve data from MySQL using C# ASP .Net. -- done --
2. All data from no.1 will be inserted into table on AS400. -- I got an error on this step --
Error message says that ERROR [42000] [IBM][System i Access ODBC Driver][DB2 for i5/OS]SQL0104 - Token ; was not valid. Valid tokens: <END-OF-STATEMENT>.. It's true that I used semicolon to separate queries with each others, but it's not allowed. I've Googling but I can't find the solution.
My question is what the <END-OF-STATEMENT> means of that error message..?
Here is my source code.
private static void doInsertDOCADM(MySqlConnection conn)
{
// Get Temporary table
String query = "SELECT * FROM TB_T_DOC_TEMPORARY_ADM";
DataTable dt = CSTDDBUtil.ExecuteQuery(query);
OdbcConnection as400Con = null;
as400Con = CSTDDBUtil.GetAS400Connection();
as400Con.Open();
if (dt != null && dt.Rows.Count > 0)
{
int counter = 1, maxInsertLoop = 50;
using (OdbcCommand cmd = new OdbcCommand())
{
cmd.Connection = as400Con;
foreach (DataRow dr in dt.Rows)
{
cmd.CommandText += "INSERT INTO DCDLIB.WDFDOCQ VALUES " + "(?,?,?,?);";
cmd.Parameters.Add("1", OdbcType.VarChar).Value = dr["PROD_MONTH"].ToString();
cmd.Parameters.Add("2", OdbcType.VarChar).Value = dr["NEW_MAIN_DEALER_CD"].ToString();
cmd.Parameters.Add("3", OdbcType.VarChar).Value = dr["MODEL_SERIES"].ToString();
cmd.Parameters.Add("4", OdbcType.VarChar).Value = dr["MODEL_CD"].ToString();
if (counter < maxInsertLoop)
{
counter++;
}
else
{
counter = 1;
cmd.ExecuteNonQuery();
cmd.CommandText = "";
cmd.Parameters.Clear();
}
}
if (counter > 1) cmd.ExecuteNonQuery();
}
}
Notes: I used this way (Collect some queries first, and then execute those query) to improve the performance of my application.
As Clockwork-Muse pointed out, the problem is that you can only run a single SQL statement in a command. The iSeries server does not handle multiple statements at once.
If your iSeries server is running V6R1 or later, you can use block inserts to insert multiple rows. I'm not sure if you can do so through the ODBC driver, but since you have Client Access, you should be able to install the iSeries ADO.NET driver. There are not many differences between the ADO.NET iSeries driver and the ODBC one, but with ADO.NET you get access to iSeries specific functions.
With the ADO.NET driver, multiple insert become a simple matter of :
using (iDB2Connection connection = new iDB2Connection(".... connection string ..."))
{
// Create a new SQL command
iDB2Command command =
new iDB2Command("INSERT INTO MYLIB.MYTABLE VALUES(#COL_1, #COL_2", connection);
// Initialize the parameters collection
command.DeriveParameters();
// Insert 10 rows of data at once
for (int i = 0; i < 20; i++)
{
// Here, you set your parameters for a single row
command.Parameters["#COL_1"].Value = i;
command.Parameters["#COL_2"].Value = i + 1;
// AddBatch() tells the command you're done preparing a row
command.AddBatch();
}
// The query gets executed
command.ExecuteNonQuery();
}
}
There is also some reference code provided by IBM to do block inserts using VB6 and ODBC, but I'm not sure it can be easily ported to .NET : http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=%2Frzaik%2Frzaikextfetch.htm
Hope that helps.
When it says <END-OF-STATEMENT> it means about what it says - it wants that to be the end of the executed statement. I don't recall if the AS/400 allows multiple statements per execution unit (at all), but clearly it's not working here. And the driver isn't dealing with it either.
Actually, you have a larger, more fundamental problem; specifically, you're INSERTing a row at a time (usually known as row-by-agonizing-row). DB2 allows a comma-separated list of rows in a VALUES clause (so, INSERT INTO <table_name> VALUES(<row_1_columns>), (<row_2_columns>)) - does the driver you're using allow you to provide arrays (either of the entire row, or per-column)? Otherwise, look into using extract/load utilities for stuff like this - I can guarantee you that this will speed up the process.

Resources