C# - Retrieving data from mysql then storing into variables - c#

I have been trying a more efficient way to get and set data from my database in mysql to a variable. I've used a for loop to shorten the code and make it easier to read, though i can't think of a way to properly set other variables. Here's my code:
Note: I use 18 different local variables. (i.g ad, mnd, psk, pck, etc..)
for (int i = 1; i <= 18; i++) {
MySqlCommand cmd = dbConn.CreateCommand();
cmd.CommandText = "SELECT price from products where productID = '" + i + "'";
MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read()) {
ad = Convert.ToInt32(reader.ToString());
}
}
I am trying to retrieve the prices of 18 products from the database, but on this piece of code, I can only set one price. Any kind of help would be appreciated.

You assign all prices to 1 variable. Your code run like this
ad = 150; //sample price
ad = 240;
ad = 100;
...(18 times)
You have to use array instead of single variable.
Change your code to :
MySqlCommand cmd = dbConn.CreateCommand();
cmd.CommandText = "SELECT price from products where productID > 1 AND productID < 19" ;
MySqlDataReader reader = cmd.ExecuteReader();
int counter = 0;
while (reader.Read()) {
ad[counter++] = Convert.ToInt32(reader.ToString());
}

Okay, change your schema a bit, so you have
name | price | id
------------------------
'ad' 1.00 1
'mnd' 42.24 2
'psk' 6.66 3
'pck' 2.00 4
'etc' 9999.99 5
...
Then use Dapper like this,
using Dapper;
...
IDictionary<string, decimal> products;
using(var connection = new SqlConnection(GetConnectionString()))
{
connection.Open();
products = connection.Query("SELECT name, price FROM products;")
.ToDictionary(
row => (string)row.Name,
row => (decimal)row.Price);
}
then you can get whatever product you want like this,
var adPrice = products["ad"];
Once you have many products (a lot more than 18) you won't want to hold them all in memory at once but for now this would work well.

Related

Trying to use SQL data to multiply with other SQL data

So I am trying to use two different inputs from a user to get two different values then multiply them together to get an answer.
//code to get value
SqlCommand cmd = new SqlCommand("select Charges, Students from Subs where Subject_name='" + Subject + "'and Level='" + Level + "'", con);
//code to read and times the values
var reader = cmd.ExecuteReader();
int Price = Convert.ToInt32(reader["Charges"]);
int NumS = Convert.ToInt32(reader["Subject_name"]);
int final = (Price*NumS) / 100;
status = final + "$";
You should try something like this:
// Define **parametrized** query
string query = "SELECT Charges, Students FROM dbo.Subs WHERE Subject_name = #SubjectName AND Level = #Level;";
using (SqlCommand cmd = new SqlCommand(query, con))
{
// define the parameters and set value
// I'm just *guessing* what datatype and what length these parameters are - please adapt as needed !
cmd.Parameters.Add("#SubjectName", SqlDbType.VarChar, 50).Value = Subject;
cmd.Parameters.Add("#Level", SqlDbType.Int).Value = Level;
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
int Price = reader.GetInt32(0); // index = 0 is "Charges" of type INT
// you are **NOT** selecting "Subject_Name" in your query - you therefore **CANNOT** read it from the SqlDataReader
// int NumS = Convert.ToInt32(reader["Subject_name"]);
int NumS = 1.0;
int final = (Price * NumS) / 100;
status = final + "$";
}
}
Points to ponder:
You should also put your SqlConnection con into a proper using (..) { ... } block to ensure disposal
You need to check the parameters - since you hadn't specified anything in your question, and also not posted any information about them, I can only guess
Be aware - the SqlDataReader might (and in a great many cases will) return multiple rows - which you need to iterate over
If you want to read out a column from the database table - it must be in the SELECT list of columns! You're trying to read out a column you're not selecting - that won't work, of course. ...

Getting "Index was outside of bounds of the Array"

I am getting the error, and not sure how to fix it. When I change the SQL command to another query, it seems to work (with the same amount of data, 10 rows). Ideas? Note: I am aware I should be using parameters in my SQL command, i am just testing.
SqlCommand getLabsCommand = new SqlCommand("SELECT labGrade FROM labStudent WHERE studentID = '"+Label1.Text+"' ");
getLabsCommand.Connection = conn;
ArrayList alMakers = new ArrayList();
conn.Open();
SqlDataReader dr = getLabsCommand.ExecuteReader();
if (dr.HasRows)
{
while (dr.Read())
{
//alMakers.Add(dr.GetString(1));
alMakers.Add(dr.GetInt32(1));
}
}
string[] labsList = (string[])alMakers.ToArray(typeof(string));
for(int i = 0; i < alMakers.Count; i++)
{
TextBox labs = new TextBox();
labs.ID = "lab" + i;
form1.Controls.Add(labs);
labs.Text = labsList.GetValue(i).ToString();
}
dr.Close();
conn.Close();
}
The function above should be putting these values in each textbox.
25
25
25
25
20
22
25
10
15
16
You are only selecting one column (SELECT labGrade FROM...); indexing is 0-based, so only GetInt32(0) is defined. GetInt32(1) refers to the second column (the first column is index 0, second column is index 1, etc). You probably want:
alMakers.Add(dr.GetInt32(0));
This type of thing is where tools like dapper shine, btw:
var alMakers = conn.Query<int>(
"SELECT labGrade FROM labStudent WHERE studentID = #id",
new { id = Label1.Text }).AsList();

How can I add and get all my database table values (numbers) and displaying the total amount? C#

I am since recently struggling with a new problem. I've got a database table that contains multiple fields (columns) with a few rows containing (money - decimal) values that are related to the fieldnames.
For example:
table = money
Field names: Rent A, Rent B, Rent C
Values: $10, $20, $30.
What I want to do is getting these values from the database, add them together and displaying the total amount in a label.
Up till now I used the OleDbDataReader for all my outputting/storing value needs. Though I have absolutely no clue how I can add the read values since the reader usually expects an pre defined field name to read.
In my project however, a user can add a custom new field name (so a pre defined field name in the reader isn't possible because you don't know which custom field names will be added by the user in the DB. These custom added fields names and their values need to be added in the total amount as well though..
Does anyone have a clue how I can fix this?
I've tried multiple things like storing it in an array, defining decimal variables and using something like x = x + (decimal)reader[0] but this all didn't work so I think I am way off.
The code (and query) I am using for the reading part is as follows:
try
{
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
string query = "select * from money where [Month]='January'";
command.CommandText = query;
OleDbDataReader reader = command.ExecuteReader();
while (reader.Read())
{
//Something I tried
//x[0] = (decimal)reader[0];
//x[1] = (decimal)reader[1];
//And so on...
//Another thing I tried
//list.Add(reader.GetInt32(0));
}
//list.ToArray();
//int sum = list.Sum();
// y = x[0] + x[1] + ...;
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error" + ex);
}
You should just be able to declare a variable, then add up all the columns. If you don't know the number of columns in the reader, you can get that using reader.FieldCount.
You do not need to know the column name to get data from the reader. You can access it by column index as you started to do, e.g. reader[0], or using the helper methods such as GetDecimal(0).
try
{
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
string query = "select * from money where [Month]='January'";
command.CommandText = query;
OleDbDataReader reader = command.ExecuteReader();
// start the total at 0
int total = 0.0m;
while (reader.Read())
{
// loop through all the fields in the reader
for(int f = 0; f < reader.FieldCount; f++) {
// read as a decimal and add to the total
total += reader.GetDecimal(f);
}
}
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error" + ex);
}
Hope this helps -
decimal total = 0M;
while (dr.Read())
{
for (int i = 0; i < dr.FieldCount; i++)
{
total+= (decimal) (dr[i] != DBNull.Value ? dr[i] : 0.0);
}
}
this will add all the column's value for each row.
Datareader has property called field count which can give number of columns.. so you can use it something like below
double num=0.0m;
for (int i = 0; i < rdr.FieldCount; i++)
num += rdr[i];

Fastest way to update more than 50.000 rows in a mdb database c#

I searched on the net something but nothing really helped me. I want to update, with a list of article, a database, but the way that I've found is really slow.
This is my code:
List<Article> costs = GetIdCosts(); //here there are 70.000 articles
conn = new OleDbConnection(string.Format(MDB_CONNECTION_STRING, PATH, PSW));
conn.Open();
transaction = conn.BeginTransaction();
using (var cmd = conn.CreateCommand())
{
cmd.Transaction = transaction;
cmd.CommandText = "UPDATE TABLE_RO SET TABLE_RO.COST = ? WHERE TABLE_RO.ID = ?;";
for (int i = 0; i < costs.Count; i++)
{
double cost = costs[i].Cost;
int id = costs[i].Id;
cmd.Parameters.AddWithValue("data", cost);
cmd.Parameters.AddWithValue("id", id);
if (cmd.ExecuteNonQuery() != 1) throw new Exception();
}
}
transaction.Commit();
But this way take a lot of minutes something like 10 minutes or more. There are another way to speed up this updating ? Thanks.
Try modifying your code to this:
List<Article> costs = GetIdCosts(); //here there are 70.000 articles
// Setup and open the database connection
conn = new OleDbConnection(string.Format(MDB_CONNECTION_STRING, PATH, PSW));
conn.Open();
// Setup a command
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
cmd.CommandText = "UPDATE TABLE_RO SET TABLE_RO.COST = ? WHERE TABLE_RO.ID = ?;";
// Setup the paramaters and prepare the command to be executed
cmd.Parameters.Add("?", OleDbType.Currency, 255);
cmd.Parameters.Add("?", OleDbType.Integer, 8); // Assuming you ID is never longer than 8 digits
cmd.Prepare();
OleDbTransaction transaction = conn.BeginTransaction();
cmd.Transaction = transaction;
// Start the loop
for (int i = 0; i < costs.Count; i++)
{
cmd.Parameters[0].Value = costs[i].Cost;
cmd.Parameters[1].Value = costs[i].Id;
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
// handle any exception here
}
}
transaction.Commit();
conn.Close();
The cmd.Prepare method will speed things up since it creates a compiled version of the command on the data source.
Small change option:
Using StringBuilder and string.Format construct one big command text.
var sb = new StringBuilder();
for(....){
sb.AppendLine(string.Format("UPDATE TABLE_RO SET TABLE_RO.COST = '{0}' WHERE TABLE_RO.ID = '{1}';",cost, id));
}
Even faster option:
As in first example construct a sql but this time make it look (in result) like:
-- declaring table variable
declare table #data (id int primary key, cost decimal(10,8))
-- insert union selected variables into the table
insert into #data
select 1121 as id, 10.23 as cost
union select 1122 as id, 58.43 as cost
union select ...
-- update TABLE_RO using update join syntax where inner join data
-- and copy value from column in #data to column in TABLE_RO
update dest
set dest.cost = source.cost
from TABLE_RO dest
inner join #data source on dest.id = source.id
This is the fastest you can get without using bulk inserts.
Performing mass-updates with Ado.net and OleDb is painfully slow. If possible, you could consider performing the update via DAO. Just add the reference to the DAO-Library (COM-Object) and use something like the following code (caution -> untested):
// Import Reference to "Microsoft DAO 3.6 Object Library" (COM)
string TargetDBPath = "insert Path to .mdb file here";
DAO.DBEngine dbEngine = new DAO.DBEngine();
DAO.Database daodb = dbEngine.OpenDatabase(TargetDBPath, false, false, "MS Access;pwd="+"insert your db password here (if you have any)");
DAO.Recordset rs = daodb.OpenRecordset("insert target Table name here", DAO.RecordsetTypeEnum.dbOpenDynaset);
if (rs.RecordCount > 0)
{
rs.MoveFirst();
while (!rs.EOF)
{
// Load id of row
int rowid = rs.Fields["Id"].Value;
// Iterate List to find entry with matching ID
for (int i = 0; i < costs.Count; i++)
{
double cost = costs[i].Cost;
int id = costs[i].Id;
if (rowid == id)
{
// Save changed values
rs.Edit();
rs.Fields["Id"].Value = cost;
rs.Update();
}
}
rs.MoveNext();
}
}
rs.Close();
Note the fact that we are doing a full table scan here. But, unless the total number of records in the table is many orders of magnitude bigger than the number of updated records, it should still outperform the Ado.net approach significantly...

How to retrieve data from mdx query in c#?

I am trying to get data from an MDX query using the Adomdclient library. I relied on this example http://www.yaldex.com/sql_server/progsqlsvr-CHP-20-SECT-6.html.
MDX query:
SELECT {[Measures].[Cantidad Vta],[Measures].[Monto Vta],[Measures].[ExistenciaHistorica],[Measures].[Valor Inventario historico]} DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON COLUMNS , NON EMPTY Hierarchize({DrilldownLevel({[DIM SUBMARCA].[Código].[All]})}) DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON ROWS FROM (SELECT ({[DIM TIENDA].[JERARQUIA TIENDA].[Región].&[Bodega],[DIM TIENDA].[JERARQUIA TIENDA].[Región].&[Cadena],[DIM TIENDA].[JERARQUIA TIENDA].[Región].&[Outlet]}) ON COLUMNS FROM [JUGUETRONHQ]) WHERE ([DIM FECHA VENTA].[JERARQUIA FECHA VENTA].[Time].&[2012-01-01T00:00:00],[DIM FECHA EXISTENCIA].[JERARQUIA FECHA EXISTENCIA].[All]) CELL PROPERTIES VALUE
Like other namespaces such as SqlClient, use a connection, a command and a datareader:
using Microsoft.AnalysisServices.AdomdClient;
...
using (AdomdConnection con = new AdomdConnection(connection_string))
{
con.Open();
using (AdomdCommand command = new AdomdCommand(query, con))
{
using (AdomdDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
Console.Write(reader[i] + (i == reader.FieldCount - 1 ? "" : ", "));
Console.WriteLine("");
}
}
}
}
However, this snippet only shows 4 of 5 columns correctly:
[DIM SUBMARCA].[Código].[All], , , 3, 825
It must be:
115200081, , , 3, 825
Perhaps need a cast but I don't know how to do it.
This looks like a problem with the MDX query, not the retrieval of the data. It's not correctly constraining on the [DIM SUBMARCA].[Código] dimension.
Your query has 1 [ALL] Level Dimension and 4 measures:
[DIM SUBMARCA].[Código].[All],
[Measures].[Cantidad Vta],
[Measures].[Monto Vta],
[Measures].[ExistenciaHistorica],
[Measures].[Valor Inventario historico]
This retrieves 1 [ALL] column and 4 Values:
[DIM SUBMARCA].[Código].[All], , , 3, 825
115200081 is a key value? You could get this value using "DIMENSION PROPERTIES MEMBER_HEY".
Retrieve data from MDX query
added the reference for Microsoft.AnalysisServices.AdomdClient.dll
AdomdConnection steps
AdomdConnection con = new AdomdConnection("connectionstring"); // connect DB con.Open(); AdomdCommand cmd = new AdomdCommand("MDX query", con); //query
AdomdDataReader reader = cmd.ExecuteReader(); //Execute query
while (reader.Read()) // read
{
Data dt = new Data(); // custom class
dt.Gender = reader[0].ToString();
dt.Eid = reader[1].ToString();
dt.salary = reader[2].ToString();
data.Add(dt);
}

Categories