Save list to database - c#

This is what I have so far:
Veza.Open();
SqlCommand zadnjaN = new SqlCommand("SELECT TOP 1 id_n FROM Narudzba ORDER BY id_n DESC", Veza);
var id_zn = zadnjaN.ExecuteScalar(); //get 1 value for id_zn (last one entered)
List<int> proizvodi = new List<int>();
proizvodi = (List<int>)Session["kosarica"];
SqlCommand kupnja1 = new SqlCommand("INSERT INTO NarudzbaItemi ([narudzbaID], [proizvodID]) VALUES (#id_zn, #pro)", Veza);
for (int i = 0; i < proizvodi.Count; i++)
{
kupnja1.Parameters.AddWithValue("pro", proizvodi[i]); //also tried #pro
kupnja1.Parameters.AddWithValue("id_zn", id_zn); //#id_zn
kupnja1.ExecuteNonQuery();
}
Veza.Close();
I get a message saying that variable name #pro has allready been declared.
The point is, I need to insert a list of int items into column proizvodID, and however many times I insert a value in that column I need to insert an unchanging value that many times in column narudzbaID, which I get from a different table as the last value added. All 3 columns are int, and Session is List int. Using asp.net, c#, sql server 2008.

You keep adding parameters in the loop. On the second iteration, #pro is already defined.
Try this:
Veza.Open();
object id_zn; //get 1 value for id_zn (last one entered)
using (SqlCommand zadnjaN = new SqlCommand("SELECT TOP 1 id_n FROM Narudzba ORDER BY id_n DESC", Veza))
{
id_zn = zadnjaN.ExecuteScalar();
}
List<int> proizvodi = (List<int>)Session["kosarica"];
using (SqlCommand kupnja1 = new SqlCommand("INSERT INTO NarudzbaItemi ([narudzbaID], [proizvodID]) VALUES (#id_zn, #pro)", Veza))
{
kupnja1.Parameters.Add("pro");
kupnja1.Parameters.Add("id_zn");
for (int i = 0; i < proizvodi.Count; i++)
{
kupnja1.Parameters["pro"].Value = proizvodi[i]; //also tried #pro
kupnja1.Parameters["id_zn"].Value = id_zn; //#id_zn
kupnja1.ExecuteNonQuery();
}
}
Veza.Close();

Here how you can do this. But John Saunders's method is better I think
for (int i = 0; i < proizvodi.Count; i++)
{
//Add this line to clear parameters
kupnja1.Parameters.Clear();
kupnja1.Parameters.AddWithValue("pro", proizvodi[i]); //also tried #pro
kupnja1.Parameters.AddWithValue("id_zn", id_zn); //#id_zn
kupnja1.ExecuteNonQuery();
}

It's basically saying you can't keep reusing the same command, this should work, moving the declaration into the loop:
Veza.Open();
SqlCommand zadnjaN = new SqlCommand("SELECT TOP 1 id_n FROM Narudzba ORDER BY id_n DESC", Veza);
var id_zn = zadnjaN.ExecuteScalar(); //get 1 value for id_zn (last one entered)
List<int> proizvodi = new List<int>();
proizvodi = (List<int>)Session["kosarica"];
for (int i = 0; i < proizvodi.Count; i++)
{
SqlCommand kupnja1 = new SqlCommand("INSERT INTO NarudzbaItemi ([narudzbaID], [proizvodID]) VALUES (#id_zn, #pro)", Veza);
kupnja1.Parameters.AddWithValue("pro", proizvodi[i]); //also tried #pro
kupnja1.Parameters.AddWithValue("id_zn", id_zn); //#id_zn
kupnja1.ExecuteNonQuery();
}
Veza.Close();

Related

ASP.NET DropDown and SQL C#

I have a number in a database (e.g 12) and I want to display that number in the dropdown list on a webform, however, not the number itself but a range of numbers from 1 to 12 (so 1,2,3....12). Is there a property I can use or a way to get a list of numbers from SQL Statement?
Read the Number from Database
Display a full range of numbers from 1 to X (X = Number from Database)
Bind dropdown list to:
Enumerable.Range(1, <number from database>);
First create an array or list and then iterate till the number you read from database then add these numbers to your array or list then bind with your dropdown datasource
var numbers = new List<int>();
for(var i = DB_NUMBER; i >= 1; i--)
{
numbers.Add(i);
}
yourDropDown.DataSource = numbers;
yourDropDown.DataBind();
Hope it helps
Since, you wish to return the range of numbers from the SQL Query you might need a complex query, but it will always have some limit to it.
SQL Query as per your requirement:
Select Value from
(
SELECT ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n as Value
FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) ones(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) tens(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) hundreds(n),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) thousands(n)
) as tbl
Where value between 0 and 12
ORDER BY 1
I Modified above SQL from the Original Source : Answer
C#:
DropDownList.DataSource = DataTable;
DropDownList.DisplayField = Value;
DropDownList.ValueField = Value;
DropDownList.DataBind();
You just read the number from the database and then use a for loop:
for(int i = readNumber; i > 0; i--)
{
//Add i to your dropDown list or do anything you want with it
}
Based on the question
If I assume that you want SQL to generate and return the range then you want to use a recursive cte to build it from the value in your table ...
// construct the db connection and command object
var con = new SqlConnection("Your Connection String");
using(var cmd = new SqlCommand(con) { CommandType = CommandType.Text })
{
// tell the command what SQL query we want to execute
cmd.CommandText = #"
DECLARE #startnum INT=1
DECLARE #endnum INT= SELECT TOP 1 Number FROM ValueTable
;
WITH gen AS (
SELECT #startnum AS num
UNION ALL
SELECT num+1 FROM gen WHERE num+1<=#endnum
)
SELECT * FROM gen
option (maxrecursion 100)
";
// connect to the db and execute the command
con.Open();
using(var reader = cmd.ExecuteReader())
{
// build the range from the values generated by it
var range = new List<int>();
while(reader.Read()) { range.Add(reader.Read()); }
// bind the results to the drop down on the page
DropDownList.DataSource = range
.Select(i = > new { Key = i, Value = i })
.ToArray();
DropDownList.DisplayField = "Key";
DropDownList.ValueField = "Value";
DropDownList.DataBind();
}
con.Close();
}
The simplest approach
ok querying a db is a pretty well documented problem so I won't repeat that here.
But lets assume you have the following ...
// sourced from your db
int start = 1;
int end = 12;
... from there you can build a range of values ...
var range = Enumerable.Range(start, end)
.Select(i = > new { Key = i, Value = i })
.ToArray();
... and then bind that range to your drop down on the page ...
DropDownList.DataSource = range;
DropDownList.DisplayField = "Key";
DropDownList.ValueField = "Value";
DropDownList.DataBind();
Sources of information ...
How to generate a range of numbers between two numbers?
https://msdn.microsoft.com/en-us/library/fksx3b4f.aspx
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader(v=vs.110).aspx
To achieve this you need to
Take the desire number from database
then you have to write a for loop.
private void InitializeDropDownList(int number)
{
for (int i = 0; i < number; i++)
{
ddlNumberRange.Items.Add(new ListItem { Text = (i + 1).ToString(), Value = (i + 1).ToString() });
}
}

How to sort dataGridView in descending order by a specific column and rank them?

I am trying to create a leaderboard based on player's High score.
Each player's scores are entered randomly into DB.
I need to sort them based on their high score and also rank them.
this is my table structure
Here i want to display player_ID, player_name, player_nick and HP in datagridview.
any help is appreciated.
string query1 = "SELECT player_ID'Player ID',player_name'Player
Name',player_nick'Nick Name',HP'High Score' FROM player_profile ORDER
BY HP DESC";
My work so far, i don't know how to rank
You can use SQL to provide the rank with a user variable (I think there are also some Rank() functions). From something like Workbench:
SET #rank=0;
SELECT Name, HP, #rank:=#rank+1 As Rank FROM Demo ORDER BY HP ASC
You can also do it from code, with one small change:
string SQL = #"SET #rank=0;
SELECT Name, HP, StartDate, #rank:=#rank+1 As Rank
FROM Demo ORDER BY HP DESC;";
using (MySqlConnection dbcon = mySqlDB.GetMySQLConnection())
using (MySqlCommand cmd = new MySqlCommand(SQL,dbcon))
{
dbcon.Open();
DataTable dt = new DataTable();
dt.Load(cmd.ExecuteReader());
dgv1.DataSource = dt;
}
Results:
There is no Rank column in the table, that is added via the SQL statement above.
If you have ties, it gets more complicated. You'd have to introduce some other vars to track when the HP/Score changes and increment #rank only then. If you want to skip a rank on ties ({1,2,2,4} vs {1,2,2,3}) you'd have to also add a counter.
The one thing is that you have to allow user vars which can be specified in the connection string:
Server=SvrAddr;Database=myDB;Uid=myUsr;Pwd=myPass;Allow User Variables=True";
According to Connection Strings the option is available as of version 5.2.2
This Great Answer shows how to skip having to initialize the rank var:
string SQL = #"SELECT Name, HP, StartDate, #rank:=#rank+1 As Rank
FROM Demo, (SELECT #rank := 0) r ORDER BY HP DESC;";
Adding (SELECT #rank := 0) r prevents having to explicitly declare it. Very cool.
The following code adds the data to the dataGridView and then answers your question at the end.
// Add columns to the dataGridView
dataGridView1.Columns.Add("player_ID", "player_ID");
dataGridView1.Columns.Add("player_name", "player_name");
dataGridView1.Columns.Add("player_nick", "player_nick");
dataGridView1.Columns.Add("HP", "HP");
// Add some data to the dataGridView
object[] rowData = new object[dataGridView1.Columns.Count];
rowData[0] = 0; // Player_ID
rowData[1] = "Pancho"; // Player_Name
rowData[2] = "Speedy"; // Player Nick
rowData[3] = Convert.ToDecimal("58.7"); // HP
dataGridView1.Rows.Add(rowData);
rowData[0] = 1;
rowData[1] = "Ramon";
rowData[2] = "Sleepy";
rowData[3] = Convert.ToDecimal("39.6"); // HP
dataGridView1.Rows.Add(rowData);
rowData[0] = 2;
rowData[1] = "Cimitrio";
rowData[2] = "Grumpy";
rowData[3] = Convert.ToDecimal("41.2"); // HP
dataGridView1.Rows.Add(rowData);
rowData[0] = 3; // Player_ID
rowData[1] = "Panfilo"; // Player_Name
rowData[2] = "Gummy Bear"; // Player Nick
rowData[3] = Convert.ToDecimal("61.5"); // HP
dataGridView1.Rows.Add(rowData);
// Sort dataGridView by HP
dataGridView1.Sort(dataGridView1.Columns[3], ListSortDirection.Ascending);
// Add rank column
dataGridView1.Columns.Add("Rank", "Rank");
// Rank players
for (int i = 0; i < dataGridView1.Rows.Count-1; i++)
{
dataGridView1.Rows[i].Cells["Rank"].Value = Convert.ToString(i+1);
}

Add items to an array with no set size within a "while (reader.Read())"

I have this method:
int[] lowStockArray;
private void checkForLowStockTimer()
{
using (SqlConnection conn = new SqlConnection(connString))
using (SqlCommand comm = new SqlCommand("SELECT Id,Stock,LowStock FROM Beans WHERE id = #ID", conn))
{
comm.Parameters.AddWithValue("#ID", coffeeID);
conn.Open();
using (SqlDataReader reader = comm.ExecuteReader())
{
while (reader.Read())
{
if (Int32.Parse(reader["Stock"].ToString()) <= Int32.Parse(reader["LowStock"].ToString()))
{
lowStockArray = Int32.Parse(reader["Stock"].ToString());
}
}
}
}
}
and at:
lowStockArray = Int32.Parse(reader["Stock"].ToString());
I get the error "Cannot implicitly convert type 'int' to 'int[]'"
I'm use to loop with loop numbers and arrays with set sizes such as:
int[] foo= new int[400];
for (int bar= 0; runs < 400; bar++)
{
foo[bar] = value;
}
With the while (reader.Read() atleast however I don't know how to pull a loop number for the [] out of it if thats what I need.
I thought I could just add on to the array.
You can use a generic List to store your data and finally get an array from it.
var myList = new List<int>();
while (reader.Read())
{
if (Int32.Parse(reader["Stock"].ToString()) <= Int32.Parse(reader["LowStock"].ToString()))
{
myList.Add(Int32.Parse(reader["Stock"].ToString()));
}
}
var array = myList.ToArray();
The error is saying that you are trying to give your array the value of an int, instead of setting an element of your array.
This is true since
Int32.Parse(reader["Stock"].ToString())
returns an int, but lowStockArray is an array.
You could declare an int outside of the loop
int i = 0;
and then increment it's value every time you add something to your array.
lowStockArray[i] = Int32.Parse(reader["Stock"].ToString());
i++;
You will need to instantiate your array and keep track of the array index and increment it each pass in the loop.
Or to simplify things, change
int[] lowStockArray;
to
List<int> lowStockArray = new List<int>()
and change
lowStockArray = Int32.Parse(reader["Stock"].ToString());
to
lowStockArray.Add(Int32.Parse(reader["Stock"].ToString()));
Then later on, you can call lowStockArray.ToArray()
Change
int[] lowStockArray;
to
List<int> lowStockList = new List<int>();
and
lowStockArray = Int32.Parse(reader["Stock"].ToString());
to
lowStockList.Add(Int32.Parse(reader["Stock"].ToString()));
To get an array: lowStockList.ToArray()

C# Divide the values of one list by the values of the other to produce a new list

I wish to divide the corresponding values of each list in order to produce a new list containing the divided results of each corresponding index in my two lists. Both my lists are 8 values long and are both int lists. I am currently creating two lists that are to be divided like so:
private void StartSchedule_Click(object sender, EventArgs e)
{
string ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=F:\A2 Computing\C# Programming Project\TriHard.accdb";
string SelectQuery = "SELECT Time.AthleteID, Athlete.AthleteName, Time.EventTime, Event.EventDistance FROM Event INNER JOIN (Athlete INNER JOIN [Time] ON Athlete.[AthleteID] = Time.[AthleteID]) ON Event.[EventID] = Time.[EventID];";
OleDbConnection Connection = new OleDbConnection(ConnectionString);
OleDbCommand Command = new OleDbCommand(SelectQuery, Connection);
Command.Connection.Open();
OleDbDataReader Reader = Command.ExecuteReader(CommandBehavior.CloseConnection);
PaceCalculator pace = new PaceCalculator();
List<int> Distancelist = new List<int>();
List<int> Secondslist = new List<int>();
List<int> Pacelist = new List<int>();
while (Reader.Read())
{
pace = new PaceCalculator();
pace.Distance = (int)Reader["EventDistance"];
int DistanceInt = Convert.ToInt32(pace.Distance);
Distancelist.Add(DistanceInt);
pace = new PaceCalculator();
pace.Time = (string)Reader["EventTime"]; //Reads in EventTime
double Seconds = TimeSpan.Parse(pace.Time).TotalSeconds; //Converts the string into HH:MM:SS as a double
int SecondsInt = Convert.ToInt32(Seconds); //Converts the double into an integer, returning the seconds in the total time
Secondslist.Add(SecondsInt); //Adds the Seconds for each time to the list;
//Need to fix this currently returns just 0
var Pacelist2 = PaceCalc(Distancelist, Secondslist);
listBox3.DisplayMember = "PaceInt";
listBox3.DataSource = (Pacelist2);
}
listBox1.DisplayMember = "DistanceInt";
listBox1.DataSource = Distancelist;
listBox2.DisplayMember = "SecondsInt";
listBox2.DataSource = Secondslist;
Here is the function I am calling which attempts to divide the lists, but doesn't seem to be working:
public List<int> PaceCalc(List<int> Dlist, List<int> Slist)
{
PaceCalculator pace = new PaceCalculator();
List<int> Plist = new List<int>();
pace = new PaceCalculator();
for (int i = 0; i == Dlist.Count; i++)
{
int PaceInt = Dlist[i] / Slist[i];
Plist.Add(PaceInt);
}
return Plist;
}
I wish to display the outcomes of the division in listBox3. Am I dividing the lists correctly and how can I display it in the list box?
Your for loop is never executing because you're testing if i == Dlist.Count. It should be:
for (int i = 0;i < Dlist.Count; i++)
Alternatively, you could do this with LINQ:
public List<int> PaceCalc(List<int> Dlist, List<int> Slist)
{
return Dlist.Zip(Slist, (a, b) => a / b).ToList();
}
Couple of issues:
First you need to modify your check in for loop to i < Dlist.Count. Your current check i == Dlist.Count is wrong.
So your method would be:
public List<int> PaceCalc(List<int> Dlist, List<int> Slist)
{
List<int> Plist = new List<int>();
for (int i = 0; i < Dlist.Count; i++)
{
int PaceInt = Dlist[i] / Slist[i];
Plist.Add(PaceInt);
}
return Plist;
}
(I have removed PaceCalculator pace = new PaceCalculator();, since you don't need that at all in your method)
Second. You don't have to specify DisplayMember for ListBox3
var Pacelist2 = PaceCalc(Distancelist, Secondslist);
listBox3.DataSource = Pacelist2;
Although, the second issue will not cause any error/exception, since DisplayMember will not be found , it will use the default ToString overload and you will get the number.

How to find number of rows when grouped

I want to retrieve the number of rows grouped with condition for controlling the number of rows for display. With primary key there is no problem I get the count(*) but when in case of other fields such as date, nom where there is much rows with the same name and date I found a primitive way to find the number of rows wich will be displayed as below:
public static int GetRapportPgeNbr(string Qry, int param)
{
int counter = 0;
int result = 0;
using (MySqlConnection conn = new MySqlConnection(PublicVariables.cs))
{
using (MySqlCommand cmd = new MySqlCommand(Qry,conn))
{
conn.Open();
MySqlDataReader reader = cmd.ExecuteReader();
try
{
while (reader.Read())
{
result = result + Convert.ToInt16(reader["rows"]);
++counter;
}
}
catch(MySqlException e)
{
MessageBox.Show(e.Number.ToString() + " -> " + e.Message.ToString());
return result;
}
}
}
if (param == 1)
return counter;
else
return result;
}
The param variable guides me either I get the sum of rows (sometimes there is 2 or more tables with union) or counter.
Sqlfiddle
In this exemple I have 5 rows but I need only 4 rows so I take the result of the counter.
Is there a better way ?
I think you are looking for COUNT(DISTINCT nom) and remove the GROUP BY to get the total count:
SELECT COUNT(DISTINCT nom) AS rows
FROM ProdMacaron
SQL Fiddle Demo
This will give you 4 not 5.
You can, however, add the GROUP BY nom, but this is useless with COUNT(DISTINCT nom) this will give you ones for any values in your table.

Categories