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() });
}
}
Related
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);
}
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.
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();
I have a DataTable which has a column "amount" for each rows and I'd like to have the total sum of all the rows. And also, I'd like to get total number of rows in the DataTable. Could anyone teach me how to have it done with LINQ instead of ordinary way?
Number of rows:
DataTable dt; // ... populate DataTable
var count = dt.Rows.Count;
Sum of the "amount" column:
DataTable dt; // ... populate DataTable
var sum = dt.AsEnumerable().Sum(dr => dr.Field<int>("amount"));
Aggregate allows you to avoid enumerating the rows twice (you could get the row count from the rows collection but this is more to show how to extract multiple aggregates in 1 pass):
var sumAndCount = table.AsEnumerable().Aggregate(new { Sum = 0d, Count = 0},
(data, row) => new { Sum = data.Sum + row.Field<double>("amount"), Count = data.Count + 1});
double sum = sumAndCount.Sum;
int count = sumAndCount.Count;
decimal[] Amount = {2,3,5 };
var sum = Amount.Sum();
var count = Amount.Count();
Based on Roy Goode's Answer you could also create an Extension
public static int Sum(this DataTable table, string Column)
{
return table.AsEnumerable().Sum(dr => dr.Field<int>(Column));
}
Unfortunately you can't be more generic her because there is no where T : numeric
I have a menu on my masterpage / defaultpage where I'm listing x categories.
I would like to make a count of how many products there are in each category.
EX:
Bananas(20)
Apples(8)
Strawberries(5)
So far, I have this:
var listSubMenu = __account.GetAllProductCategories();
var sb = new StringBuilder();
for (int i = 0; i < listSubMenu.Rows.Count; i++)
{
var r = listSubMenu.Rows[i];
var catid = Request.QueryString["thespecific_category_id_but_how_do_i_get_it?"];
var count = __account.GetSpecificCategory(id);
sb.AppendFormat(String.Format(#"<li{0}><a href='/account/products.aspx?categoryid={0}'>{1} ({2})</a></li>", r["cat_id"], r["cat_name"], count.Rows.Count));
}
active_sub_products.Text = sb.ToString();
My DataTable:
public DataTable GetAllProductCategories()
{
const string request =
#"
SELECT * FROM products_category
WHERE cat_active = 1
ORDER BY cat_name ASC
";
using (var query = new MySqlCommand(request))
{
return __dbConnect.GetData(query);
}
}
Obiously i need the specific categoryid, but how to I request that without having querystrings running since it is on the default page.
Am I missing something obious?
Thanks alot.
You should loop through your categories and get the ID from there. Not from the querystring since that is related to you page (as you wrote yourself as well).
Given your example, I would expect that __account.GetAllProductCategories() would return already the ID's you need
In that case you would use something like
var catid = listSubMenu.id;
But id depends on the type of what your __account returns.
If I'm correct in my guess at your result schema from GetAllProductCategories()...
["cat_id"]["cat_name"]
[1][Apples]
[2][Bananas]
[3][Oranges]
var cat_id = r["cat_id"]
or possibly
var cat_id = Int32.Parse(r["cat_id"])
I would also change:
sb.AppendFormat(String.Format(#"<li{0}><a href='/account/products.aspx?categoryid={0}'>{1} ({2})</a></li>", r["cat_id"], r["cat_name"], count.Rows.Count));
To:
sb.AppendFormat(String.Format(#"<li><a href='/account/products.aspx?categoryid={0}'>{1} ({2})</a></li>", cat_id, r["cat_name"], count.Rows.Count));
(There are two changes, (1) <li{0}> to <li> {proper html syntax} and (2) r["cat_id"] to cat_id {you already have it in a variable and string.Format doesn't mind recasting to a string for you})
Beyond that I would suggest looking into an ORM like LinqToSql so you could work directly with objects...
First render the category links in the master page:
** When you call GetAllProductCategories, each row of the result will have at least two columns (cat_id and cat_name).
When you get each row by index (var r = listSubMenu.Rows[i]) the row it returns will have the cat_id and cat_name for that record, I added (var name = r["cat_name"]) for illustration.
If you debug this and step through you should see each iteration through the for loop gives the id variable the next category's id which is then used in the line (var count = __account.GetSpecificCategory(id);)
var listSubMenu = __account.GetAllProductCategories();
var sb = new StringBuilder();
for (int i = 0; i < listSubMenu.Rows.Count; i++)
{
var r = listSubMenu.Rows[i];
var id = Int32.Parse(r["cat_id"]);
var name = r["cat_name"];
var count = __account.GetSpecificCategory(id);
sb.AppendFormat(String.Format(#"<li{0}><a href='/account/products.aspx?categoryid={0}'>{1} ({2})</a></li>", r["cat_id"], r["cat_name"], count.Rows.Count));
}
active_sub_products.Text = sb.ToString();
Then into another textbox or area of the actual page "products.aspx"
var sbProducts = new StringBuilder();
var selectedCat = Request.QueryString["categoryid"];
if(!string.IsNullOrWhitespace(selectedCat))
{
var selectedCatId = Int32.Parse(selectedCat);
var products = __account.GetSpecificCategory(selectedCatId);
for(int j = 0; j < products.Rows.Count; j++)
{
// ... do product listing stuff here
// sbProducts.Append(...);
}
}
else
{
sbProducts.AppendLine("Invalid Category Id Selected!");
}
active_selected_products.Text = sbProducts.ToString();
** Note: when you call Request.QueryString["value"] it will either:
Return null indicating that there isn't a querystring parameter with a matching name
or
Return the string representing the content between value= and the end of the url or the next & found.
** this isn't fully production quality code, there are additional checks you should be doing on the query string value, switch to tryparse for example, check number of products returned and show "No products found for that category" ... etc **