I'm creating a product search where users can search base of what they want or simply choose Any which means it will display all product.
since I'm searching based on what is in the dropdownList control, if user choose a product category i have query the database to display the product in that category. How can i query the database to display product in all category when the user select 'Any' from the dropdownList.
When you prepare your query include a IF
This is pseudo code, because Im not sure how you store the values in the combo or how you make your sql consult. So is just to give you the general idea.
if( dropdwonList.SelectedItem.Value == "any" ) {
select * from products ;
}
else {
select * from products where categoryID = dropdwonList.SelectedItem.Value;
}
Or use this query
SELECT *
FROM products
WHERE
( categoryID = ddCategory.SelectedItem.Value
OR ddCategory.SelectedItem.Value= -1 // `-1` is your ID for `ANY`
) AND
( modelID = ddModel.SelectedItem.Value
OR ddModel.SelectedItem.Value= -1
) AND ....
Related
I'm programming a C# Windows Forms Application in Visual Studio and I'm trying to get data about prices of products and the amount a user has added a product to its shopping list from my local MySQL-database into a List(int).
What I do is following:
If a user has added a product 4 times to their shopping list, I'm adding the barcode of the product 4 times to my List(int).
This is working but when I'm reading out all items of the List with the String.Join()-method into the IN-clause of my query and execute it, it only returns a row one time altough the IN-operator has the same barcode multiple times.
The following is how I'm adding barcodes to my List(int)
int count = 0;
List<int> barcodes = new List<int>();
MySqlCommand cmd = new MySqlCommand("SELECT product_barcode, amount FROM shopping_list_items WHERE shopping_list_id = " + current_shoppingListID + ";", db.connection);
cmd.ExecuteNonQuery();
var reader = cmd.ExecuteReader();
while (reader.Read())
{
do
{
barcodes.Add(Int32.Parse(reader["product_barcode"].ToString()));
count++;
} while (count < Int32.Parse(reader["amount"].ToString()));
}
reader.Close();
This is how I'm executing my query and assign the values to variables:
MySqlCommand cmdSum = new MySqlCommand("SELECT sum(price) AS 'total', supermarket_id FROM prices WHERE barcode IN (" + String.Join(", ", barcodes) + ") GROUP BY supermarket_id;", db.connection);
cmdSum.ExecuteNonQuery();
var readerSum = cmdSum.ExecuteReader();
while (readerSum.Read())
{
switch (double.Parse(readerSum["supermarket_id"].ToString()))
{
case 1:
sumSupermarket1 = double.Parse(readerSum["total"].ToString());
break;
case 2:
sumSupermarket2 = double.Parse(readerSum["total"].ToString());
break;
case 3:
sumSupermarket3 = double.Parse(readerSum["total"].ToString());
break;
}
}
A simplified query just to make it simple may look like this:
SELECT name FROM products WHERE barcode IN (13495, 13495, 13495);
If the above one is my query then I want it to return 3 the same rows.
So my question now is, how can I get multiple rows altough I use a same value multiple times in the IN-clause of a MySQL-query?
Q: how can I get multiple rows altough I use a same value multiple times in the IN-clause of a MySQL-query?
A: We don't. That's not how IN () works.
Note that
WHERE foo IN ('fee','fi','fi','fi')`
Is shorthand for
WHERE ( foo = 'fee'
OR foo = 'fi'
OR foo = 'fi'
OR foo = 'fi'
)
Understand what's happening here. MySQL is going to examine each row, and for each row it checks to see if this condition returns TRUE or not. If the row satisfies the condition, the row gets returned. Otherwise the row is not returned.
It doesn't matter that a row with foo value of 'fi' satisfies multiple conditions. All MySQL cares about is that the condition inside the parens ultimately evaluates to TRUE.
As an illustration, consider:
WHERE ( t.picked_by = 'peter piper'
OR t.picked_amount = 'peck'
OR t.name LIKE '%pickled%'
OR t.name LIKE '%pepper%'
)
There could be a row that satisfies every one of these conditions. But the WHERE clause is only asking if the entire condition evaluates to TRUE. If it does, return the row. If it doesn't, then exclude the row. We don't get four copies of a row because more than one of the conditions is satisfied.
So how do we get a set with multiple copies of a row?
As one possible option, we could use separate SELECT statements and combine the results with UNION ALL set operator. Something like this:
SELECT p1.name FROM product p1 WHERE p1.barcode IN (13495)
UNION ALL
SELECT p2.name FROM product p2 WHERE p2.barcode IN (13495)
UNION ALL
SELECT p3.name FROM product p3 WHERE p3.barcode IN (13495)
Note that the result from this query is significantly different than the result from the original query.
There are other query patterns that can return an equivalent set.
FOLLOWUP
Without an understanding of the use case, the specification, I'm just guessing at what we are attempting to achieve. Based on the two queries shown in the code (which follows a common pattern we see in code that is vulnerable to SQL Injection),
The shopping list:
SELECT i.product_barcode
, i.amount
FROM shopping_list_item i
WHERE i.shopping_list_id = :id
What is amount? Is that the quantity ordered? We want two cans of this, or three pounds of that? Seems like we would want to multiply the unit price by the quantity ordered to get the cost. (Two cans is going to cost twice as much as one can.)
If what we are after is the total cost of the items on the shopping list from multiple stores, we could do something like this:
SELECT SUM(p.price * s.amount) AS `total`
, p.supermarket_id
FROM ( SELECT i.product_barcode
, i.amount
FROM shopping_list_item i
WHERE i.shopping_list_id = :id
) s
JOIN price p
ON p.barcode = s.product_barcode
GROUP
BY p.supermarket_id
Note that if a particular product_barcode is not available for particular supermarket_id, that item on the list will be excluded from the total, i.e. we could get a lower total for a supermarket that doesn't have everything on our list.
For performance, we can eliminate the inline view, and write the query like this:
SELECT SUM(p.price * i.amount) AS `total`
, p.supermarket_id
FROM shopping_list_item i
JOIN price p
ON p.barcode = i.product_barcode
WHERE i.shopping_list_id = :id
GROUP
BY p.supermarket_id
If we absolutely have to rip through the shopping list query, and then use the rows from that to create a second query, we could form a query that looks something like this:
SELECT SUM(p.price * i.amount) AS `total`
, p.supermarket_id
FROM ( -- shopping_list here
SELECT '13495' AS product_barcode, '1'+0 AS amount
UNION ALL SELECT '13495', '1'+0
UNION ALL SELECT '13495', '1'+0
UNION ALL SELECT '12222', '2'+0
UNION ALL SELECT '15555', '5'+0
-- end shopping_list
) i
JOIN price p
ON p.barcode = i.product_barcode
WHERE i.shopping_list_id = :id
GROUP
BY p.supermarket_id
You would probably be better off investigating LINQ to SQL rather than using direct SQL and injection.
You can use an inline table join to accomplish what you want:
"SELECT sum(price) AS 'total', supermarket_id
FROM (select "+barcodes[0]+"as bc union all select "+String.Join(" union all select ", barcodes.Skip(1).ToArray())+") w
JOIN prices p ON p.barcode = w.bc
GROUP BY supermarket_id;"
Note: If you can name the column with the inline table alias (I couldn't test that) you could simplify the inline table generation.
This Code will be called through the object data source within the asp.net application.
In northwind database , there exist a table with name of Customer. so I want to filter the grid view like below :
as you can see in image above , there are two drop downs at top of the grid view . they will filter the Gridview with ContactTitle and Country Columns , So , I have written the code In DAL Like Below :
var q = (from customers in db.Customers
select new
{
customers.ContactName,
customers.ContactTitle,
customers.City,
customers.Country,
customers.Phone,
customers.Address
});
if (!country.Equals("All")) q = q.Where(e => e.Country == country);
if (!contactTitle.Equals("All")) q = q.Where(e => e.ContactTitle == contactTitle);
So the code works nice , but this code will call the database connection three times ! One for selecting all , Second for filtering country and third Time for filtering with contact Title , How Can I Optimize this queries into One query ?
My Second Question is : How Can I Delete Duplicated Values in Drop downs with out querying again ? I don't want to use select Distinct or other query .... Can I have something like this :
(Note DropDowns are Binded to database...)
OnDataBind (e) {
if(!DropDown1.Contains(e.value)) DropDown1.Add(e.Value);
}
UPDATE :
var q = (from customers in db.Customers
where (country.Equals("All") || customers.Country == country ) &&
(contactTitle.Equals("All") || customers.ContactTitle == contactTitle)
select new
{
customers.ContactName,
customers.ContactTitle,
customers.City,
customers.Country,
customers.Phone,
customers.Address
});
The code above will do the same but not faster , because the first code is Linq To Object !
I have a table name Students having (studentId, StudentName,Address,PhoneNo)
i have provided a filter for user to select only StudentId from Combobox to get the details of Students... and generate Report.
I have written following Query to get student Detail :
(select * from Students where StudentId = stdId)
Here stdId is a Parameter that i pass from code
It works fine if i select single studentId.... But in user selection Comobobox i have also provided "ALL" if user Select All from combobox i want to display details of all student
So what should I pass in stdId if user selects All ?
I used inline Query in C# (not using SQL Stored Procedure)
You can do it like this .
SELECT * from Students s
WHERE s.studentId = ISNULL(#StudentId,s.studentId)
When "All" is selected in combo box pass null in your #studentid parameter. If you can not pass null in parameter then pass -1 or anything which can not be contain in you combox option and do it like this:(if -1= All)
SELECT * from Students s
WHERE s.studentId = #StudentId or #StudentId=-1
You can also try the answer given by Curt.
If user selects all, pass NULL to #StudentId and change your query to:
select *
from Students
where (StudentId=#StudentId OR #StudentId IS NULL)
In your stored procedure header, change the definition of #StudentId so that it can be passed as NULL.
ALTER PROCEDURE dbo.WhateverYourProcedureIsCalled( #StudentId int = null )
Then change your WHERE clause as follows
...
SELECT * from Students
WHERE #StudentId IS NULL OR StudentId = #StudentId
From your code, if ALL is passed, you can omit the part where you set the value of the #StudentId parameter. SQL Server will use the default if not passed.
If the where clause is included in the query you also need to supply a valid parameter value and it is therefore not possible to get all students when the where clause is included.
You need to differentiate your query based on the value selected in the combobox. You can do something like the following.
int studentId = 0;
//Where selectedValue comes from your combobox
Int32.TryParse(selectedValue, out studentId);
var query = "select * from Students";
if (studentId > 0)
{
query = query + " where StudentId = #StudentId";
//Remember to add studentId as parameter value
}
I have three tables namely "Projects", "Platforms", "Details".
I have collected detail from the Projects table, then Platforms table and Details table. From the details table we may get the multiple values or single value.
I have written the Linq query like below:
using (PEntities CSProject = new PEntities())
{
projectId = (from _project in CSProject.Projects
where _project.ProjectName == project
select _project.ProjectId).SingleOrDefault();
platformId = (from platformID in CSProject.Projects
where platformID.ProjectName == project
select platformID.PlatformId).SingleOrDefault();
platformName = (from platfrmName in CSProject.Platforms
where platfrmName.PlatformId == platformId
select platfrmName.PlatformName).SingleOrDefault();
cSProjectId = (from _csproject in CSProject.Details
where _csproject.ProjectId == projectId
select _csproject.CsprojectId).ToList<long?>();
}
Can you please help me out to write the above all query in a single single line?
You could create a correlated subquery for each of the values that you want to get in the select statement, like so (in SQL):
select
(select ProjectId from Projects where ProjectName = #project) as ProjectId,
(select PlatformId from Projects where ProjectName = #project) as PlatformId,
...
In SQL, the above doesn't need a table to query against (it will return one row), but you'll need something in LINQ-to-Entities, which will force you to query against a context, make sure there is at least one value in the table, etc.
Needless to say, it's not worth it, and while you'll gain less calls to the database, the actual query that is sent will be very complex.
That said, you're better off doing one of two things. The first is to create a stored procedure that creates the correlated subqueries and returns one record like above and call that from LINQ-to-Entities.
The other, if you are really looking for one record that stores these values is to store them in a type. Here's how to do it in an anonymous type:
using (PEntities CSProject = new PEntities())
{
var results = new {
ProjectId = (
from _project in CSProject.Projects
where _project.ProjectName == project
select _project.ProjectId).SingleOrDefault(),
PlatformId = (
from platformID in CSProject.Projects
where platformID.ProjectName == project
select platformID.PlatformId).SingleOrDefault(),
PlatformName = (
from platfrmName in CSProject.Platforms
where platfrmName.PlatformId == platformId
select platfrmName.PlatformName).SingleOrDefault();
CsProjectId = (
from _csproject in CSProject.Details
where _csproject.ProjectId == projectId
select _csproject.CsprojectId).ToList<long?>();
};
}
You won't see a reduction in calls to the database, but if what you're going for is a single record with these values, then this will achieve it.
I have a products table and each product have a category field (this is not up to me to change and I need to read the data from it as it is), from the product table I wanted to update a category table with unique categories only (I also use a IFNULL to deal with empty categories), this is what I have so far that works:
string query = "INSERT INTO categories (name)
SELECT DISTINCT(IFNULL(category, \"Uncategorized\")) AS category_name
FROM products
WHERE NOT EXISTS (
SELECT name FROM categories
WHERE name = category_name)";
With the above query I am able to update the categories with unique category fields and every time I need to run it, it will add only categories that does not exist to the table.
But besides the above I also need to include a profile id with each category inserted something like this, which does not work:
string query = "INSERT INTO categories (profile_id, name)
SELECT " + profileId.ToString() + ",
DISTINCT(IFNULL(category, \"Uncategorized\")) AS category_name
FROM products
WHERE NOT EXISTS (
SELECT name FROM categories
WHERE name = category_name
AND profile_id = #profileId)";
Is there a way I could acomplish this with a query ?
The above gives me a message:
SQLite error near "DISTINCT": syntax error
SqliteMan error:
Query Error: near "DISTINCT": syntax error Unable to execute statement
Let me know if I havent been clear and what should I be more clear about.
You are using the DISTINCT keyword incorrectly: it is not a function. Try instead:
"INSERT INTO categories (profile_id, name)
SELECT DISTINCT '"+profileId.ToString()+"', IFNULL(category, 'Uncategorized')
FROM products
WHERE category_name NOT IN (
SELECT name FROM categories WHERE profile_id = "'+profileId.ToString()+"'
)
"
One assumes that profileId.ToString() is guaranteed to be safe from SQL injection, or else you would be escaping it/passing it as a parameter to a prepared statement?