Trying to use SQL data to multiply with other SQL data - c#

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. ...

Related

C# - Retrieving data from mysql then storing into variables

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.

DataReader Exception

I have a simple database that I am using. It contains two entries for users which is a user with UserID 1 and IsAdmin 0 and another with UserID 3041234567 and IsAdmin of 1. The only fields in the database is a string UserID and a bit IsAdmin. I am reading from the database with the following code:
SqlConnection conn = new SqlConnection(Properties.Settings.Default.Conn);
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM Users WHERE UserID = " + t.Text.ToString(), conn);
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
user.UserID = reader["UserID"].ToString();
user.IsAdmin = Convert.ToBoolean(reader["IsAdmin"]);
}
}
conn.Close();
If I enter the number 3041234567 as the UserID everything works perfectly, but If I enter the number 1 I get an exception saying that "The conversion of the nvarchar value '3041234567' overflowed an int column."
If I set a breakpoint and watch the while(reader.read()) loop the loop iterates through fine and sets the user.UserID = 1 and the user.IsAdmin = false. The exception is thrown when the loop begins to iterate a second time. I guess I have a couple of questions:
Why is the loop iterating a second time?
How is the ID 3041234567 being returned with the sql command "SELECT * FROM Users WHERE UserID = 1"
What is the int column that is being overflowed?
Well, since
3041234567 > int.MaxValue ( == 2147483647)
you've got an overflow; if you want some kind of integer value, however, try long (which is 64 bit long):
long value = Convert.ToInt64(reader["UserID"]);
Something like this:
// Wrap IDisposable into using
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.Conn)) {
conn.Open();
// Make sql
// 1. Readable
// 2. Parametrized
// 3. Avoid * in select
String sql =
#"select UserID,
IsAdmin
from Users
where UserID = #prm_UserId";
// Wrap IDisposable into using
using (SqlCommand cmd = new SqlCommand(sql, conn)) {
// Explicit data type will be better here (Add Parameter with type)
// but I don't know it
cmd.Parameters.AddWidthValue("prm_UserId", t.Text);
// Wrap IDisposable into using
using (SqlDataReader reader = cmd.ExecuteReader()) {
// You don't want to iterate the whole cursor, but the first record
if (reader.Read()) {
//TODO: Make UserID being "long"
user.UserID = Convert.ToInt64(reader["UserID"]);
user.IsAdmin = Convert.ToBoolean(reader["IsAdmin"]);
}
}
}
}

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];

Checking the number of rows returned from MySQL Data Reader

I am currently working on an C# project and I am trying to get the number of rows returned from MySQL Data Reader.
I know there is no direct function so I am trying to write my own. In the function, I pass it the MySQLDataReader object and then loop through the MySQL Data Reader and increment a counter and return the value of the counter.
This then seems to lock up the program, I guess because I am Reader.read() after I've got the count I'm already at the end. Instead I have tried creating a copy of the reader and then loop through the temp version but I get the same result.
Below is my code where I am executing the query and calling the function.
string query = "SELECT * FROM reports, software, platforms, versions "
+ "WHERE EmailVerified = #verified AND reports.SoftwareID = software.id AND reports.PlatformID = platforms.id "
+ "AND reports.VersionID = versions.id AND BugReportAcceptedNotificationSent = #notificationSent";
using (MySqlCommand cmd = new MySqlCommand(query, db.conn))
{
cmd.Parameters.AddWithValue("#verified", "1");
cmd.Parameters.AddWithValue("#notificationSent", "0");
using (MySqlDataReader reader = cmd.ExecuteReader())
{
totalEmails = HelperClass.totalRowsInMySQLDataReader(reader);
while (reader.Read())
{
currentEmailCount++;
EmailNotifications emailNotification = new EmailNotifications(reader);
emailNotification.sendNewBugReportAfterVerificationEmail(currentEmailCount, totalEmails);
}
}
}
Below is my function that gets the row count
public static int totalRowsInMySQLDataReader(MySqlDataReader reader)
{
MySqlDataReader tempReader = reader;
ILibraryInterface library = GeneralTasks.returnBitsLibrary(Configuration.databaseSettings, Configuration.engineConfig.logFile);
string methodInfo = classDetails + MethodInfo.GetCurrentMethod().Name;
try
{
int count = 0;
while (tempReader.Read())
{
count++;
}
tempReader = null;
return count;
}
catch (Exception ex)
{
string error = string.Format("Failed to get total rows in MySQL Database. Exception: {0}", ex.Message);
library.logging(methodInfo, error);
library.setAlarm(error, CommonTasks.AlarmStatus.Medium, methodInfo);
return -1;
}
}
Make use of a DataTable to load your results, e.g.
DataTable dt = new DataTable();
dt.Load(reader);
int numberOfResults = dt.Rows.Count;
You can then also iterate over the rows to read the values, e.g.
foreach(DataRow dr in dt.Rows)
{
var value = dr["SomeResultingColumn"]
}
The other option is to issue two separate SQL statements, however you would need to ensure both statements were enclosed within a transaction with a Serializable isolation level, this is needed to make sure records aren't inserted between the execution of the two SQL statements.
To avoid multiple queries, how about including the total in the select itself?
SELECT COUNT(*) AS TotalNORows, * FROM reports, software, platforms, versions etc
i think without executing another command it's not possible...as there is no method available for count in reader class
you can try this... if it works..
string query = "SELECT * FROM reports, software, platforms, versions "
+ "WHERE EmailVerified=#verified AND reports.SoftwareID=software.id AND reports.PlatformID=platforms.id "
+ "AND reports.VersionID=versions.id AND BugReportAcceptedNotificationSent=#notificationSent";
using (MySqlCommand cmd = new MySqlCommand(query, db.conn))
{
cmd.Parameters.AddWithValue("#verified", "1");
cmd.Parameters.AddWithValue("#notificationSent", "0");
using (MySqlDataReader reader = cmd.ExecuteReader())
{
// create a new connection db.conn2 then
MySqlCommand cmd2 = new MySqlCommand(query, db.conn2))
cmd2.Parameters.AddWithValue("#verified", "1");
cmd2.Parameters.AddWithValue("#notificationSent", "0");
MySqlDataReader reader2 = cmd2.ExecuteReader();
int numberofrow=0;
while(reader2.Read())
numberofrow++;
//your codes......
}
Was working on the same problem. I hate having to iterate if a method is already available, but this is was the shortest bit I could come up with:
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader reader = cmd.ExecuteReader();
int rowcount = 0;
while(reader.Read()){
rowcount++;
}
First, create this class:
public static class Extensions
{
public static int Count(this MySqlDataReader dr)
{
int count = 0;
while(dr.Read())
count++;
return count;
}
}
This will implement .Count () on MySqlDataReader.
int count = reader.Count();
Exemple:
string sql= "SELECT * FROM TABLE";
MySqlCommand cmd = new MySqlCommand(sql, connection);
MySqlDataReader reader = cmd.ExecuteReader();
int count = reader.Count();
Maybe you could look things the other way around
You could just do a select count(*) and get the row count
or
use a data adapter to fill a container (like a DataTable) and count the rows
Unfortunatelly solution from Jan Van #Herck will return one row only, so in case you are interested in getting all rows and their number in one select, this isn't what you need.
In that case I suggest uou to try this:
select * , (select count(*) from my_table) AS numRow from my_table;
or read this:
Getting total mysql results returned from query with a limit: FOUND_ROWS error
You can use follwoing SQL Query to get the total rows Count.
SELECT COUNT(*) FROM [MYTABLE]
from the Code you can use ExecuteScalar() method to get the total number of rows returned by QUERY.
Try This:
int GetRowsCount(MySqlCommand command)
{
int rowsCount=Convert.ToIn32(command.ExecuteScalar());
return rowsCount;
}
Use above function as below:
MySqlCommand command=new MySlCommand("Select count(*) from MyTable",connectionObj);
int totalRows = GetRowsCount(command)
OleDbDataReader dbreader = new OleDbDataReader();
int intcount = 0;
if (dbreader.HasRows == true)
{
if (dbreader.Read())
{
intcount = dbreader.RecordsAffected;
}
}
"dbreader.RecordsAffected" will give you the number rows changed,inserted or deleted by the last statement of SQL

Undesired result from SQL query in C# console application

In my C# application I am trying to read data within my Accounts table, read the data as a decimal, preform a a calculation on it, and then update the same row.
Right now it reads the correct data in the column but two things go wrong when trying to update.
It sets all of the data in the AccountTotal column to the same value. This value is correct for the first row, but incorrect for the rest.
I believe the second problems occurs in calculating the data that is to be updated. When I try to update the DB, it sets the value twice as high as I am wanting it to be. For example: In my CalculateIncome method I wan't to add 100 to the account total, It adds 200.
What is causing these two problems?
Here is the program:
class Program
{
static void Main(string[] args)
{
//Need to change when deploying on real database.
const string DB_NAME = "Bank.sdf";
const string DB_PATH = #"C:\Users\Lucas\eBankRepository\eBank\App_Data\" + DB_NAME; // Use ".\" for CWD or a specific path
const string CONNECTION_STRING = "Data Source=" + DB_PATH;
decimal AccountTotal;
var conn = new SqlCeConnection(CONNECTION_STRING);
SqlCeDataReader reader = null;
try
{
conn.Open();
//Basic Query of all accounts
SqlCeCommand Query = new SqlCeCommand("SELECT * FROM Accounts", conn);
reader = Query.ExecuteReader();
while (reader.Read())
{
AccountTotal = reader.GetDecimal(2); //Column in DB for Account Total
AccountTotal += CalculateIncome();
//Update Total
SqlCeCommand UpdateTotal = new SqlCeCommand("UPDATE Accounts SET AccountTotal = #UpdatedTotal", conn); // Error when using WHERE Clause "WHERE AccountName= # Savings"
UpdateTotal.Parameters.AddWithValue("#UpdatedTotal", AccountTotal);
UpdateTotal.Connection = conn;
UpdateTotal.ExecuteNonQuery();
}
}
finally
{
if (reader != null)
{
reader.Close();
}
if (conn != null)
{
conn.Close();
}
}
}
public static decimal CalculateIncome()
{
return 100;
}
}
EDIT:
Here is the code I had before that included the WHERE clause in the command. With this code, it now only updates the the rows where it has an account name of "Savings," but it still sets the value in each of the rows to be the same for AccountTotal
while (reader.Read())
{
AccountTotal = reader.GetDecimal(2); //Column in DB for Account Total
AccountTotal += CalculateIncome();
//Update Total
SqlCeCommand UpdateTotal = new SqlCeCommand("UPDATE Accounts SET AccountTotal = #UpdatedTotal WHERE AccountName= #Savings", conn); // Error when using WHERE Clause "WHERE AccountName= # avings"
UpdateTotal.Parameters.AddWithValue("#UpdatedTotal", AccountTotal);
UpdateTotal.Parameters.AddWithValue("#Savings", "Savings");
UpdateTotal.Connection = conn;
UpdateTotal.ExecuteNonQuery();
}
Here is a visual as well for before and after the program is being run.
Before
After
Working Code
while (reader.Read())
{
AccountTotal = reader.GetDecimal(2); //Column in DB for Account Total
//Console.WriteLine(AccountTotal);
AccountTotal += CalculateIncome();
//Console.WriteLine(AccountTotal);
//Update Total
SqlCeCommand UpdateTotal = new SqlCeCommand("UPDATE Accounts SET AccountTotal = #UpdatedTotal WHERE AccountName = #Savings AND AccountID = #ID", conn);
UpdateTotal.Parameters.AddWithValue("#UpdatedTotal", AccountTotal);
UpdateTotal.Parameters.AddWithValue("#Savings", "Savings");
UpdateTotal.Parameters.AddWithValue("#ID", reader.GetInt32(0));
UpdateTotal.Connection = conn;
UpdateTotal.ExecuteNonQuery();
AccountTotal = 0; //Reset
}
Your two issues are:
It's updating all the rows to be the same value
This is because there isn't a where clause in your update statement.
It's making the value double up.
This is because of the line AccountTotal += CalculateIncome();
What this does is in the first run make it be 100 and the second loop around it makes it be 200.

Categories