I have table
itemID
storeID
qty
103
LAB
20
I want to add qantity of specific item for example:'103' stored in warehouse 'LAB'.
public void addQuantity(string store, string item, int qty)
{
con.Open();
string sql = "SELECT qty,warehouse.storeID,item.itemID FROM Item,warehouse,stocker WHERE stocker.storeID=warehouse.storeID AND stocker.itemID=item.itemID AND warehouse.storeID='"+store+"' AND Item.itemID='"+item+"' ";
using (MySqlDataAdapter adapter = new MySqlDataAdapter(sql, con))
{
using (DataTable tempTable = new DataTable())
{
adapter.Fill(tempTable);
if (tempTable.Rows.Count == 0) throw new Exception("No such product");
foreach (DataRow r in tempTable.Rows)
{
int newQty = (int)r["qty"] + qty;
if (newQty > 0)
{
r["qty"] = newQty;
qty = 0;
break;
}
else
{
MessageBox.Show("error");
}
}
using (MySqlCommandBuilder cb = new MySqlCommandBuilder(adapter))
{
adapter.UpdateCommand = cb.GetUpdateCommand();// there is error
adapter.Update(tempTable);
}
}
}
con.Close();
}
it says:"Dynamic SQL generation is not supported for multiple base tables".
what would you advice me?
If qty is integer column, you may try to:
Increment its current value by some value:
using (var updateCommand = new MySqlCommand())
{
updateCommand.CommandText = "UPDATE mytable t SET t.qty = t.qty + #newQty WHERE *...Your WHERE clause...*`"
updateCommand.Parameters.AddWithValue("#newQty", newQtyValue);`
// ...
}
Or append entire new value:
using (var updateCommand = new MySqlCommand())
{
updateCommand.CommandText = "UPDATE mytable t SET t.qty = #newQtyValue WHERE *...Your WHERE clause...*`"
updateCommand.Parameters.AddWithValue("#newQtyValue", newQtyValue);`
// ...
}
As #sticky bit said, it is preferred to use Command.Parameters.AddWithValue instead of string concat/interpolation.
Related
I want to replace if (Convert.ToString(rdr["Data"]) != bItems) with something that would check if data already exist in my database or not to make process faster as going in that loop taking too much time for bigger database. Plz HELP!
for (int p = 0; p < 256; p++) {
bItems += "P" + buffer[p];
}
using (SQLiteConnection con = new SQLiteConnection(databaseObject.myConnection)) {
con.Open();
SQLiteCommand cmd = new SQLiteCommand("select ID, Data from B where Data like 'P%'", con);
var rdr = cmd.ExecuteReader();
while (rdr.Read()) {
if (Convert.ToString(rdr["Data"]) != bItems) {
SQLiteCommand cmd1 = new SQLiteCommand("INSERT INTO B ('Data') SELECT #Data WHERE NOT EXISTS (SELECT ID, Data FROM B WHERE Data = #Data)", con);
cmd1.Parameters.AddWithValue("#Data", bItems);
cmd1.ExecuteNonQuery();
}
else (Convert.ToString(rdr["Data"]) == bItems) {
sItems = "B" + Convert.ToString(rdr["ID"]);
rdr.Close();
break;
}
}
}
bItems = "";
Console.WriteLine(sItems);
}
instead of reading each row and check the data against bItems. You may need to either query the table to see if there is any record matches bItems, if not then insert it. Or, you can simply insert the data if not exists (which what you did in the first condition.
To simplify your work, you can do this :
// insert the new item if not exists in the table
// returns the item Id
private int InsertDataIfNotExists(string bItems)
{
using (SQLiteConnection connection = new SQLiteConnection(databaseObject.myConnection))
using(SQLiteCommand command = new SQLiteCommand("INSERT INTO B ('Data') SELECT #Data WHERE NOT EXISTS (SELECT 1 FROM B WHERE Data = #Data);", con))
{
connection.Open();
command.Parameters.AddWithValue("#Data", bItems);
// insert data if not exists
command.ExecuteNonQuery();
// get the data's Id
cmd.CommandText = "SELECT ID FROM B WHERE Data = #Data LIMIT 1;";
cmd.Parameters.AddWithValue("#Data", bItems);
var result = cmd.ExecuteScalar()?.ToString();
return int.TryParse(result, out int id) && id > 0 ? id : -1;
}
}
with the above, you only insert the data if not exists, and then return the id.
usage :
var insertResultId = InsertDataIfNotExists(bItems);
if(insertResultId == -1)
{
// handle exceptions
}
else
{
Console.WriteLine(insertResultId);
}
I need help in reading data from DataTable and adding key, value to a Dictionary object.
//Here is the object:
public class DBName
{
public int ID { get; set; } // key
public string DatabaseName { get; set; } // value
}
My DataTable is getting data, but can't figure out how to add to Dictionary
reading DataTable and adding to Dictionary -
public static Dictionary<int,DBName> ReadToDictionary()
{
string con = #"MyConnectionString;";
SqlConnection sqlconn = new SqlConnection(con);
string sqlQuery = #"SELECT DISTINCT DisplayName AS DatabaseName, RANK() OVER(ORDER BY MIN(id)) AS ID
FROM dbo.MyTable
GROUP BY DisplayName";
Dictionary<int, DBName> dictionaryDBName = new Dictionary<int, DBName>();
SqlCommand sqlcmd = new SqlCommand(sqlQuery, sqlconn);
{
using (SqlDataAdapter da = new SqlDataAdapter(sqlcmd))
{
try
{
DataTable dt = new DataTable();
da.Fill(dt);
foreach (DataRow dr in dt.Rows)
{
foreach (DataColumn col in dt.Columns)
{
//how to add key and Value?
dictionaryDBName.Add(dr[1], DBName);
}
// anything here?
}
}
catch (Exception ex)
{
//
}
finally
{
sqlconn.Close();
}
}
}
return dictionaryDBName;
}
Please guide.
You are probably much better off just using a DataReader. No need to fill a DataTable and then try looping through it, just loop the reader.
Further points:
Don't swallow exceptions, deal with them properly
You need to have a using on the connection, and then you don't need to call Close
Are you aware of the differences between RANK, DENSE_RANK and ROW_NUMBER?
public static Dictionary<int,DBName> ReadToDictionary()
{
string con = #"MyConnectionString;";
using(SqlConnection sqlconn = new SqlConnection(con))
{
string sqlQuery = #"SELECT DISTINCT
DisplayName AS DatabaseName
,CAST(RANK() OVER(ORDER BY MIN(id)) AS int) AS ID
FROM
dbo.MyTable
GROUP BY
DisplayName";
sqlconn.Open();
Dictionary<int, DBName> dictionaryDBName = new Dictionary<int, DBName>();
using(SqlCommand sqlcmd = new SqlCommand(sqlQuery, sqlconn))
using (var reader = sqlcmd.ExecuteReader())
{
while(reader.Read())
{
DBName n = new DBName { ID = reader.GetInt32(1), DatabaseName = reader[0] as string};
dictionaryDBName.Add(n.ID, n);
}
}
return dictionaryDBName;
}
}
Here's the LINQ solution. The key is to use the powerful ToDictionary extension method.:
var reader = sqlCmd.ExecuteReader();
var dataTable = new DataTable()
dataTable.Load(reader);
var dictionary = dataTable.Rows.Cast<DataRow>().ToDictionary
(
x => (int)x[0], //Convert column 0 into the dictionary's key
x => (string)x[1] //Convert column 1 into the dictionary's value
);
However, since SqlDataReader implements IEnumerable, you can skip the data table entirely like this:
var reader = sqlCmd.ExecuteReader();
var dictionary = reader.Cast<IDataRecord>().ToDictionary
(
x => x.GetInt32(0), //Convert column 0 into the dictionary's key
x => x.GetString(1) //Convert column 1 into the dictionary's value
);
See also this answer.
public int UpdateAmount(List<MyTable> myBizObjList)
{
SqlTransaction sqltxn;
DbClass db = new DbClass();
SqlConnection cs;
cs = db.GetConnection();
string commandText = #"Update MyTable Set amt = #amt where empno = #empno and mydate = #mydate";
int x = myBizObjList.Count;
int y = 0,rowsaffected;
cs.Open();
using (cs)
{
sqltxn = cs.BeginTransaction();
foreach (MyTable myBizObj in myBizObjList)
{
SqlCommand command = new SqlCommand(commandText, cs, sqltxn);
command.Parameters.Add("#empno", SqlDbType.Int);
command.Parameters["#empno"].Value = myBizObj.Empno;
command.Parameters.Add("#mydate", SqlDbType.Date);
command.Parameters["#mydate"].Value = myBizObj.Mydate;
command.Parameters.Add("#amt", SqlDbType.Decimal);
command.Parameters["#amt"].Value = myBizObj.Amt;
try
{
rowsAffected = command.ExecuteNonQuery();
if (rowsAffected == 1)
y++;
}
catch (Exception ex)
{
throw (ex);
}
}
if (y == x)
{
sqltxn.Commit();
}
else
{
sqltxn.Rollback();
y = 0;
}
cs.Close();
return y;
}
}
Question: I am querying a table and getting say 50K records which I am converting to a List of objects. I am processing the List in my BLL and sending to my DAL. The above is a method in my DAL. Is there a better way? I am also checking if all rows are updated & then Commit or Rollback.
You can convert this to a table-valued parameter.
First we need a table type:
CREATE TYPE dbo.MyTVP (
empno int not null,
mydate date not null,
amt decimal not null
primary key (empno, mydate)
);
Then we pass it through. You don't necessarily need a stored procedure, you can do this as an ad-hoc batch:
public int UpdateAmount(List<MyTable> myBizObjList)
{
var table = new DataTable();
table.Columns.Add("empno", typeof(int));
table.Columns.Add("mydate", typeof(datetime));
table.Columns.Add("amt", typeof(decimal));
foreach (MyTable myBizObj in myBizObjList)
table.Rows.Add(myBizObj.Empno, myBizObj.Mydate, myBizObj.Amt);
const string commandText = #"
Update tbl
Set amt = t.amt
FROM MyTable AS tbl
JOIN #tmp AS t ON t.empno = tbl.empno AND t.mydate = tbl.mydate;
";
using (var cs = db.GetConnection())
{
SqlCommand command = new SqlCommand(commandText, cs, sqltxn);
command.Parameters.Add(
new SqlParameter("#tmp", SqlDbType.Structured)
{
Direction = ParameterDirection.Input,
TypeName = "dbo.MyTVP",
Value = table
});
cs.Open();
return command.ExecuteNonQuery();
}
}
I've got a DataGridView that has 2 columns - product name and the quantity of it. So I grab each row in a foreach loop and calculate the price of it. I managed to do that but I can't seems to figure out how to store ALL the calculated rows into a single variable and insert them into a database.
This is what I have so far:
string cMedication = string.Empty;
string cQuantity = string.Empty;
string cAppointment = string.Empty;
foreach (DataGridViewRow row in this.dataPrescription.Rows)
{
cMedication = row.Cells[0].Value.ToString();
cQuantity = row.Cells[1].Value.ToString();
cAppointment = txtAppointmentID.Text;
if (cAppointment == "NO APPOINTMENT HAS BEEN MADE")
{
MessageBox.Show("Please make an appointment first at the Nurse counter", "WARNING");
}
else
{
//this.savePrescription(cMedication, cQuantity, cAppointment);
string strConnectionString = ConfigurationManager.ConnectionStrings["HConnection"].ConnectionString;
string strCalc = "SELECT medicationPrice FROM MEDICATION WHERE medicationName= ('" + cMedication + "')";
using (SqlConnection connection = new SqlConnection(strConnectionString))
{
using (SqlCommand cmdCalc = new SqlCommand(strCalc, connection))
{
connection.Open();
SqlDataReader readPrice = cmdCalc.ExecuteReader();
if (readPrice.Read())
{
string getPrice = readPrice["medicationPrice"].ToString();
double doublePrice = Convert.ToDouble(getPrice);
double doubleQuantity = Convert.ToDouble(cQuantity);
double result = doublePrice * doubleQuantity;
string answer = result.ToString();
//insert TOTAL amount to database below
}
readPrice.Close();
connection.Close();
}
}
}
}
If you're doing this kind of thing a lot then I would use some kind of ORM like Entity Framework (or write your own). Then you would just load / create entites and save them.
If that's overkill for what you're doing then you could build up an insert statement and execute it, much like you've done to query the medication price. Only as I've mentioned in the comment, use SqlParameters instead of string concatenation to avoid possible sql injection attacks.
Something like this (untested).
var builder = new StringBuilder("INSERT INTO MedicationLine (MedicationName, Quantity, Price) VALUES ");
int i = 0;
var parameters = new List<SqlParameter>();
foreach (DataGridViewRow row in this.dataPrescription.Rows)
{
string cAppointment = txtAppointmentID.Text;
if (cAppointment == "NO APPOINTMENT HAS BEEN MADE")
{
MessageBox.Show("Please make an appointment first at the Nurse counter", "WARNING");
return;
}
string cMedication = row.Cells[0].Value.ToString();
string cQuantity = row.Cells[1].Value.ToString();
i++;
string strConnectionString = ConfigurationManager.ConnectionStrings["HConnection"].ConnectionString;
string strCalc = "SELECT medicationPrice FROM MEDICATION WHERE medicationName = #medicationName";
using (SqlConnection connection = new SqlConnection(strConnectionString))
{
using (SqlCommand cmdCalc = new SqlCommand(strCalc, connection))
{
command.Parameters.Add(new SqlParameter("medicationName", cMedication);
connection.Open();
SqlDataReader readPrice = cmdCalc.ExecuteReader();
if (readPrice.Read())
{
string getPrice = readPrice["medicationPrice"].ToString();
double doublePrice = Convert.ToDouble(getPrice);
double doubleQuantity = Convert.ToDouble(cQuantity);
builder.AppendLine();
builder.Append("(";
builder.Append("#Name");
builder.Append(i);
builder.Append("#Qty");
builder.Append(i);
builder.Append("#Price");
builder.Append(i);
builder.Append("),";
parameters.Add(new SqlParameter("Name" + i.ToString(), medicationName);
parameters.Add(new SqlParameter("Qty" + i.ToString(), doubleQuantity);
parameters.Add(new SqlParameter("Price" + i.ToString(), doublePrice);
}
readPrice.Close();
connection.Close();
}
}
}
The idea is to end up with something like:
INSERT INTO MedicationLine (MedicationName, Quantity, Price) VALUES
(#Name1, #Qty1, #Price1),
(#Name2, #Qty2, #Price2),
(#Name3, #Qty3, #Price3),
...
Then execute it. Don't forget to trim the trailing comma.
using (var connection = new SqlConnection(strConnectionString))
{
using (var command = new SqlCommand(builder.ToString().TrimEnd(','), connection))
{
command.Parameters.AddRange(parameters.ToArray());
connection.Open();
int recordsAffected = command.ExecuteNonQuery();
}
}
**Disclaimer
Syntax may be wrong as done without an IDE!
I want to build a custom interface (a separate aspx page) to manage the data that is put into the webforms for marketeers (WFFM) database, and that for just one form. It must be possible to edit the data and select records with particular sortings and pagings. The database is configured to be SQLite.
Is this possible and recommended, or is it just plain xml that is saved into the WFFM database? And how should I go about it?
This is completely doable, though the select query to get data out of WFFM is a bit funky because everything is stored loose in one huge table called "field" with only a trail of GUIDs to tie the stored values back to what form they came from and what field.
Provided below is part of an Export to Excel utility I wrote for WFFM data. It builds a DataTable object from submitted form results. You could adapt it to some other structure without much work though.
public string connectionStringWFFM = "user id=sitecore_admin;password=xxx;Data Source=SitecoreDBServer.com;Database=Sitecore_WebForms";
protected DataTable BuildDataTable(Item formItem)
{
List<FormResult> formResults = FormResults(formItem.ID.Guid);
List<Field> distinctFields = DistinctFields(formItem.ID.Guid);
var dt = new DataTable();
dt.Columns.Add("Submission_DateTime", typeof (string));
foreach (Field field in distinctFields)
{
var dataColumn = new DataColumn("_" + field.id.ToString("N"), typeof (string));
dataColumn.Caption = field.name.Replace(" ", "_");
dt.Columns.Add(dataColumn);
}
foreach (FormResult formResult in formResults)
{
var connection = new SqlConnection();
connection.ConnectionString = connectionStringWFFM;
var command = new SqlCommand();
command.Connection = connection;
command.CommandText = "select fieldid, value from field where formid=#formid order by fieldid";
command.Parameters.Add("#formid", SqlDbType.UniqueIdentifier).Value = formResult.id;
connection.Open();
SqlDataReader reader = command.ExecuteReader();
DataRow dataRow = dt.NewRow();
dataRow["Submission_DateTime"] = formResult.timestamp.ToString("MM/dd/yyyy HH:mm:ss");
while (reader.Read())
{
dataRow["_" + reader.GetGuid(0).ToString("N")] = reader.GetValue(1).ToString().Replace("<item>", "").Replace("</item>", "");
}
dt.Rows.Add(dataRow);
reader.Close();
connection.Close();
}
return dt;
}
public List<Field> DistinctFields(Guid formitemid)
{
var connection = new SqlConnection();
connection.ConnectionString = connectionStringWFFM;
var command = new SqlCommand();
command.Connection = connection;
command.CommandText = "select distinct fieldid from field where formid in (select id from form where formitemid=#formitemid) order by fieldid";
command.Parameters.Add("#formitemid", SqlDbType.UniqueIdentifier).Value = formitemid;
connection.Open();
SqlDataReader reader = command.ExecuteReader();
var results = new List<Field>();
int count = 0;
while (reader.Read())
{
var field = new Field();
field.id = reader.GetGuid(0);
Database database = Factory.GetDatabase("master");
Item i = database.GetItem(new ID(field.id));
if (i != null && i.DisplayName != null)
{
field.name = i.DisplayName;
}
else
{
field.name = "Field" + count;
}
results.Add(field);
count += 1;
}
reader.Close();
connection.Close();
return results;
}
public List<FormResult> FormResults(Guid formitemid)
{
var connection = new SqlConnection();
connection.ConnectionString = connectionStringWFFM;
var command = new SqlCommand();
command.Connection = connection;
command.CommandText = "select id, timestamp from form where formitemid=#formitemid";
command.Parameters.Add("#formitemid", SqlDbType.UniqueIdentifier).Value = formitemid;
connection.Open();
SqlDataReader reader = command.ExecuteReader();
var results = new List<FormResult>();
while (reader.Read())
{
var result = new FormResult();
result.id = reader.GetGuid(0);
result.timestamp = reader.GetDateTime(1);
results.Add(result);
}
reader.Close();
connection.Close();
return results;
}
public class FormResult
{
public Guid id { get; set; }
public DateTime timestamp { get; set; }
}
public class Field
{
public Guid id { get; set; }
public string name { get; set; }
}