I am trying to increase the value from a database after each row is added to a label, I get it to increase until the 3rd Invoice. Here is my code:
public void loadInv()
{
>declare variables
int i;
int y;
y = 0;
i = 1;
>declare data source
string datasource = #"Data Source=DESKTOP-VVM3FB0\WARRENDB;Initial Catalog=mAdjustments; User ID=WarrenDB; password=//purposely taken out; ";
>declare selectquery variable
string selectQuery;
>create sql connection
SqlConnection con = new SqlConnection(datasource);
>open sql connection
con.Open();
>initialize the select query with sql query
selectQuery = #"SELECT MAX(InvoiceNum) FROM Invoices";
>initialize command with parameter of select query with connection
SqlCommand com = new SqlCommand(selectQuery, con);
> declare data reader and execute the command
SqlDataReader dr = com.ExecuteReader();
>conditional statement while reader is reading from database
while (dr.Read())
{
>if database has no row
if (dr.IsDBNull(y))
{
lblInvNum.Text = 1.ToString();
}
>if database has row
else if (dr.HasRows)
{
>>count the amount on the field and add 1
i = dr.FieldCount + 1;
i = i + 1;
>>assign to label
lblInvNum.Text = i.ToString();
}
}
}
Can someone please help me figure this out?
It seems u are looking for last inserted row so you can use output parameter in sql query and scope_variable to return last inserted row ID to your out parameter
Related
I have a stored procedure created in my SQL Server 2012 database that selects data from multiple tables. In C#, I use this procedure to show data in a datagridview.
Issue: when I execute the query in SQL Server, I get the correct result which returns 3 rows, but in C#, it returns only 2 rows.
Query:
SELECT DISTINCT
Employee.Employee_No AS 'Badge'
,Employee.Employee_Name_Ar AS 'Emp Name'
,Employee.Basic_Salary AS 'Basic'
,Employee.Current_Salary AS 'Current'
,Attendance.Present
,Attendance.Leave
,Attendance.Othe_Leave AS 'OL'
,Pay_Slip.Salary_Amount AS 'Sal. Amt.'
,(ISNULL(Pay_Slip.OverTime1_Amount, 0.00) + ISNULL(Pay_Slip.OverTime2_Amount, 0.00)) AS 'O/T Amt.'
,(ISNULL(Pay_Slip.Salary_Amount, 0.00) + ISNULL(ISNULL(Pay_Slip.OverTime1_Amount, 0.00) + ISNULL(Pay_Slip.OverTime2_Amount, 0.00), 0.00)) AS 'Sal. & O/T'
,Pay_Slip.Trasnport AS 'Allow'
,Pay_Slip.CostofLiving AS 'O.Allow'
,Pay_Slip.Gross_Salary AS 'T Salary'
,Pay_Slip.Insurance1_Amount AS 'ss 7%'
,Pay_Slip.Insurance2_Amount AS 'ss 11%'
,(ISNULL(Pay_Slip.Insurance1_Amount, 0.00) + ISNULL(Pay_Slip.Insurance2_Amount, 0.00)) AS 'Total s.s'
,Pay_Slip.Tax
,Pay_Slip.Personal_Loans AS 'Advance'
,Pay_Slip.Other_Deductions AS 'Ded.'
,Pay_Slip.Net_Salary AS 'Net'
FROM Pay_Slip
LEFT JOIN Employee ON Pay_Slip.Employee_No = Employee.Employee_No
LEFT JOIN Attendance ON Pay_Slip.Employee_No = Attendance.Employee_No
WHERE Pay_Slip.Month = '5'
AND Pay_Slip.Year = '2020'
AND Attendance.Month = '5'
AND Attendance.Year = '2020'
Executing this query in SQL Server returns 3 rows which are the employee slips on May-2020 (They all have values in May-2020).
C# code:
private void dateTimePicker_ReportDate_ValueChanged(object sender, EventArgs e)
{
try
{
DateTime date = dateTimePicker_ReportDate.Value;
String Month = dateTimePicker_ReportDate.Value.ToString("MM");
String Year = dateTimePicker_ReportDate.Value.ToString("yyyy");
String str = "server=localhost;database=EasyManagementSystem;User Id=Jaz;Password=Jaz#2020;Integrated Security=True;";
String query = "Execute EMP_PAY_ATT_Selection #Month, #Year";
SqlConnection con = null;
con = new SqlConnection(str);
SqlCommand cmd= new SqlCommand(query, con);
cmd.Parameters.Add("#Month", SqlDbType.Int).Value = Convert.ToInt32(Month);
cmd.Parameters.Add("#Year", SqlDbType.Int).Value = Convert.ToInt32(Year);
SqlDataReader sdr;
con.Open();
sdr = cmd.ExecuteReader();
if (sdr.Read())
{
DataTable dt = new DataTable();
dt.Load(sdr);
dataGridView_Report.DataSource = dt;
dataGridView_Report.EnableHeadersVisualStyles = false;
dataGridView_Report.ColumnHeadersDefaultCellStyle.BackColor = Color.LightBlue;
}
else
{
dataGridView_Report.DataSource = null;
dataGridView_Report.Rows.Clear();
}
con.Close();
}
catch (Exception es)
{
MessageBox.Show(es.Message);
}
}
Again, when running this, it only returns 2 rows on the datagridview. While it should be 3 rows.
These are the tables:
The DbDataReader.Read method advances the reader to the next record.
There is no way to rewind a data reader. Any methods that you pass it to will have to use it from whatever record it is currently on.
If you want to pass the reader to DataTable.Load(), do not Read from it yourself. If you merely want to know if it contains records, use HasRows.
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());
}
}
New to stackoverflow and very much a c# beginner
Currently creating a form which produces a bar chart from data stored in a database. The chosen record is identified by pID (patient's ID) and tdate (Test date). These values are determined by 2 combo boxes that the user can select from, The problem I am having is that only the first and last records stored in the database are populating the barchart.
if (radioButtonTestResult.Checked)
{
foreach (var series in TestResultBarChart.Series)
{
series.Points.Clear();
}
string tdate = comboBox2.Text;
using (SqlConnection connection = new SqlConnection(#"Data Source= (LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\MMSEDB.mdf;Integrated Security=True"))
{
connection.Open();
string sql = "SELECT T_CLOCK_SCORE,T_LANGUAGE_SCORE,T_RECALL_SCORE,T_REGISTRATION_SCORE,T_ORIENTATION _SCORE,T_TIME FROM TEST_RESULTS WHERE P_ID='" + pID + "' AND T_DATE='"+ tdate +"'";
using(SqlCommand command = new SqlCommand(sql, connection))
{
command.CommandTimeout = 3600;
using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
{
while (reader.Read())
{
MessageBox.Show("hello4");
String clockScoreString = reader["T_CLOCK_SCORE"].ToString();
MessageBox.Show(clockScoreString);
clockScore = Int32.Parse(clockScoreString);
String langScoreString = reader["T_LANGUAGE_SCORE"].ToString();
langScore = Int32.Parse(langScoreString);
String recallScoreString = reader["T_RECALL_SCORE"].ToString();
recallScore = Int32.Parse(recallScoreString);
String regScoreString = reader["T_REGISTRATION_SCORE"].ToString();
regScore = Int32.Parse(regScoreString);
String orientScoreString = reader["T_ORIENTATION_SCORE"].ToString();
orientScore = Int32.Parse(orientScoreString);
String timeScoreString = reader["T_TIME"].ToString();
timeScore = Int32.Parse(timeScoreString);
}
reader.Close();
}
}
this.TestResultBarChart.Series["Series1"].Points.AddXY("Clock Score", clockScore);
this.TestResultBarChart.Series["Series1"].Points.AddXY("Language Score", langScore);
this.TestResultBarChart.Series["Series1"].Points.AddXY("Recall Score", recallScore);
this.TestResultBarChart.Series["Series1"].Points.AddXY("Registration Score", regScore);
this.TestResultBarChart.Series["Series1"].Points.AddXY("Orientation Score", orientScore);
}
}
Here is a pic of the data:
Test_results_table
here is a pic of the interface with the first record working:
interface
I know this has something to do with the reader but can't work out how to get to function correctly
Any help is very much appreciated
You are reading in a loop all the returned values, then exit from the loop and use just the last value to set your Points. You should move the Point settings inside the loop
....
while (reader.Read())
{
clockScore = Convert.ToInt32(reader["T_CLOCK_SCORE"]);
langScore = Convert.ToInt32(reader["T_LANGUAGE_SCORE"]);
recallScore = Convert.ToInt32(reader["T_RECALL_SCORE"]);
regScore = Convert.ToInt32(reader["T_REGISTRATION_SCORE"]);
orientScore = Convert.ToInt32(reader["T_ORIENTATION_SCORE"]);
timeScore = Convert.ToInt32(reader["T_TIME"]);
this.TestResultBarChart.Series["Series1"].Points.AddXY("Clock Score", clockScore);
this.TestResultBarChart.Series["Series1"].Points.AddXY("Language Score", langScore);
this.TestResultBarChart.Series["Series1"].Points.AddXY("Recall Score", recallScore);
this.TestResultBarChart.Series["Series1"].Points.AddXY("Registration Score", regScore);
this.TestResultBarChart.Series["Series1"].Points.AddXY("Orientation Score", orientScore);
}
reader.Close();
Note that your query is built using string concatenation. This is a well known problem with database code. Never do it and use a parameterized query
EDIT
Looking at your comment below, I repeat the advice to use a parameterized query instead of string concatenation. Not only this avoid Sql Injection hacks but also you don't leave the job to understand the meaning of your values to the database engine
DateTime tDate = Convert.ToDateTime(comboBox2.Text);
......
string sql = #"SELECT
T_CLOCK_SCORE,T_LANGUAGE_SCORE,T_RECALL_SCORE,
T_REGISTRATION_SCORE,T_ORIENTATION_SCORE,T_TIME
FROM TEST_RESULTS
WHERE P_ID=#id AND T_DATE=#date";
using(SqlCommand command = new SqlCommand(sql, connection))
{
command.Parameters.Add("#id", SqlDbType.Int).Value = pID;
command.Parameters.Add("#date", SqlDbType.Date).Value = tdate;
command.CommandTimeout = 3600;
using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
{
while (reader.Read())
....
In this example I assume that the variable pID is of type integer and the variable tDate is of type DateTime matching the type of the database fields. This doesn't leave any doubt to the database engine on your values.
Of course if the fields are of different type then you should change the SqlDbType accordingly.
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
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.