Recently I started creating a form to filter the database by using checkboxes.
I have the following data:
Category Type Country
Fruit Apple NL
Fruit Apple SU
Fruit Banana NL
Fruit Banana DE
Nuts Cashew NL
Nuts Cashew US
Nuts Almond UK
Nuts Almond GR
Now I build in my form the checkboxes for Fruit & Nuts, for Apple, Banana, Cashew & Almond and for NL, SU, DE, US, UK & GR.
At this moment I use only the OR statement in my SQL script, which works well. But if the user would like to know for example which fruit comes from NL and it marks both Fruit and NL then my output will be everything from Fruit and everything from NL (because of the OR statement).
How should I change my script that the filter is used based on the checkboxes that are checked? In my example: if the user checks both Fruit & NL then it will give the output --> Fruit Apple NL & Fruit Banana NL
Or another example: He wants Banana & Cashew, and gets as output --> Fruit Banana NL & Fruit Banana DE & Nuts Cashew NL & Nuts Cashew US
I hope my problem is clear; if not, do not hesitate to ask for clarification!
From what I understand you have a form with 2 Category check boxes, 4 Type check boxes and 6 Country check boxes.
It doesn't sound like any of these filter themselves, so it's possible try and return Nuts, Apple and UK which would return an empty table.
I think you'll have to make extensive use of the LIKE command so any NULL/FALSE values can be converted to *.
As a checkbox returns TRUE/FALSE rather than Apple/False an IIF statement can be used to change TRUE to Apple (you could probably use CHOOSE or SWITCH instead).
So the WHERE clause here says chkFruit is either Fruit or anything.
SELECT Category, Type, Country
FROM Table2
WHERE Category LIKE (IIF([Forms]![Form1]![chkFruit],'Fruit','*')) AND
Category LIKE (IIF([Forms]![Form1]![chkNuts],'Nuts','*')) AND
Type LIKE (IIF([Forms]![Form1]![chkApple],'Apple','*')) AND
Type LIKE (IIF([Forms]![Form1]![chkBanana],'Banana','*')) AND
Type LIKE (IIF([Forms]![Form1]![chkCashew],'Cashew','*')) AND
Country LIKE (IIF([Forms]![Form1]![chkNL],'NL','*')) AND
Country LIKE (IIF([Forms]![Form1]![chkSU],'SU','*')) AND
Country LIKE (IIF([Forms]![Form1]![chkDE],'DE','*'))
Edit:
Reading your comment below it sounds like you want it to filter by the ticked boxes, or if no boxes are ticked then show all of them (as if all boxes in the Category/Type or Country were ticked).
That could get quite complicated if you have lots of tick boxes.
So each section of check boxes needs breaking down to something similar to below.
WHERE ((
Category = IIF([Forms]![Form1]![chkFruit],'Fruit',NULL) OR
Category = IIF([Forms]![Form1]![chkNuts],'Nuts',NULL)
) OR IIF(NOT [Forms]![Form1]![chkFruit] AND
NOT [Forms]![Form1]![chkNuts],Category LIKE '*',NULL))
The full SQL would be:
SELECT Category, Type, Country
FROM Table2
WHERE ((
Category = IIF([Forms]![Form1]![chkFruit],'Fruit',NULL) OR
Category = IIF([Forms]![Form1]![chkNuts],'Nuts',NULL)
) OR IIF(NOT [Forms]![Form1]![chkFruit] AND
NOT [Forms]![Form1]![chkNuts],Category LIKE '*',NULL))
AND
((
Type = IIF([Forms]![Form1]![chkApple],'Apple',NULL) OR
Type = IIF([Forms]![Form1]![chkBanana],'Banana',NULL) OR
Type = IIF([Forms]![Form1]![chkCashew],'Cashew',NULL) OR
Type = IIF([Forms]![Form1]![chkAlmond],'Almond',NULL)
) OR IIF(NOT [Forms]![Form1]![chkApple] AND
NOT [Forms]![Form1]![chkBanana] AND
NOT [Forms]![Form1]![chkCashew] AND
NOT [Forms]![Form1]![chkAlmond],Type LIKE '*',NULL))
AND
((
Country = IIF([Forms]![Form1]![chkNL],'NL',NULL) OR
Country = IIF([Forms]![Form1]![chkSU],'SU',NULL) OR
Country = IIF([Forms]![Form1]![chkDE],'DE',NULL) OR
Country = IIF([Forms]![Form1]![chkUS],'US',NULL) OR
Country = IIF([Forms]![Form1]![chkUK],'UK',NULL) OR
Country = IIF([Forms]![Form1]![chkGR],'GR',NULL)
) OR IIF(NOT [Forms]![Form1]![chkNL] AND
NOT [Forms]![Form1]![chkSU] AND
NOT [Forms]![Form1]![chkDE] AND
NOT [Forms]![Form1]![chkUS] AND
NOT [Forms]![Form1]![chkUK] AND
NOT [Forms]![Form1]![chkGR], Country LIKE '*',NULL))
I've got a feeling this could be shortened quite a bit but it's starting to hurt my head now.
Related
I have a normalized database, where a superior table contains different products and a subordinated table characteristics. The subordinate table is linked to the superior table by a foreign key. This means that there may be several occurrences of one and the same characteristic_id (= foreign key) in the subordinate table if several characteristics match the properties of a product, e.g.
Superior table (product_main_table):
product_id product_name
23 apple
24 orange
25 strawberry
Subordinate table (product_characteristics):
characteristic_id product_name characteristic
23 apple green
23 apple sweet
23 apple small
23 apple american
24 orange orange
24 orange sourly
24 orange big
24 orange african
25 strawberry red
25 strawberry sweet
I have an html-form to read out the data and there should also be a possibility to search for all products that DO NOT match certain characteristics.
However, this does not work. When I enter the following request:
SELECT DISTINCT main.product_name
FROM product_main_table main, product_characteristics prodchar
WHERE prodchar.characteristic != 'sweet'
the result is 'apple', 'orange' and 'strawberry', wheresas it should be 'orange', only. The other two products are selected of course, because they have other characteristics than 'sweet' that are selected.
I would be more than happy, if the solution would fit into my general SQL-request
$sql = "SELECT DISTINCT $selection FROM $tabelle WHERE $masterarray";
where $selection, $tabelle and $masterarray get their contents from the html-entries.
How do I have to make my where-statement, so that a product is not selected, if it contains a single characteristic that should not be present?
http://sqlfiddle.com/#!9/7fd63b/5
SELECT pmt.product_name
FROM product_characteristics pc
JOIN product_main_table pmt
ON pmt.product_id = pc.characteristic_id
GROUP BY characteristic_id
HAVING SUM(characteristic IN ('sweet'))=0
I think you could use the NOT IN function:
... WHERE prodchar.characteristic NOT IN (SELECT characteristic FROM product_characteristics WHERE name = main.product_name)
You could do some thing like
SELECT DISTINCT prodchar.product_name
FROM product_characteristics prodchar
WHERE prodchar.product_name not in (select product_name from product_characteristics
where characteristic in ('sweet'))
http://sqlfiddle.com/#!9/ce6f6/7
Performance would be bad, Try using Joins. Join vs. sub-query
SET #characteristic='sweet,sour,bland';
...
WHERE FIND_IN_SET(prodchar.characteristic, #characteristic) = 0
or per your requested example
$sql = "SET #characteristic='sweet,sour,bland';SELECT DISTINCT $selection FROM $tabelle WHERE FIND_IN_SET(prodchar.characteristic, #characteristic) = 0;";
you can also use php string concatenation to echo in your variable into the $sql variable if needed.
Example question:
I have a table called Candy, with thousands of records, and has 10 columns with information about the candy. I want to pull up the data for 3 records, and I have the following information:
Candy 1: Color = Yellow, Type = Soft, Flavor = Lemon
Candy 2: Color = Yellow, Type = Hard, Flavor = Lemon
Candy 3: Color = Red, Type = Hard, Flavor = Cherry
How do I do this? In Psuedo-CodeEnglish, it would be:
Select *
From Candy
WHERE (Color = Yellow, Type = Soft, Flavor = Lemon)
AND (Candy 2: Color = Yellow, Type = Hard, Flavor = Lemon)
AND (Color = Red, Type = Hard, Flavor = Cherry);
But that doesn't work for me. I'm using PL/SQL.
The basic idea is that you want to find any row where any line is true, but all conditions on that line are true. That means you need something that's of the following structure: ___ OR ___ OR ___ where each ___ is itself a list of ands: ___ AND ___ AND ____:
Select *
From Candy
WHERE (Color = Yellow and Type = Soft and Flavor = Lemon)
or (Color = Yellow and Type = Hard and Flavor = Lemon)
or (Color = Red and Type = Hard and Flavor = Cherry);
While #Denise's answer is fine, in certain cases there is a better way to solve this type of problem using a relational database. If you are doing a single query using a where statement is fine. But you might have different requirements. For example, saving queries or storing candy requirements for many different users, etc.
Create a selection table. This table has 3 columns (color, type and flavor) in the same type as your candy table. Also add a unique identifier. Then add the following data to the table:
id color type flavor
1 Yellow Soft Lemon
2 Yellow Hard Lemon
3 Red Hard Cherry
Now you can select your candy with the following statement
SELECT *
FROM Candy C
JOIN Selection S ON C.color = S.color AND C.type=S.type AND C.flavor=S.flavor
Of course this can be expanded... if you want data for users add a user column to selection and then add the following to the above
WHERE S.User = 'Hogan'
to get the candies I like
Or maybe you want history. You could add a date column to the above and then say
WHERE S.date = '2014-01-01'
to get the new year's candies.
etc.
The reason your current query isn't working for you is because you're using AND instead of OR. There is not going to be a row in your table where color is both yellow and red. However, you do want to use AND in between each of the three conditions.
Try this instead:
SELECT *
FROM candy
WHERE (color = 'yellow' AND type = 'soft' AND flavor = 'lemon')
OR (color = 'yellow' AND type = 'hard' AND flavor = 'lemon')
OR (color = 'red' AND type = 'hard' AND flavor = 'cherry');
Here's an SQLFiddle example for you. Unfortunately, I don't know all 10 of your columns (and I don't need to) but you'll see that the query does in fact return the 3 rows expected.
I'm fairly new to Access 2007. I'm an ERP functional consultant with programming experience close to none.
I'm setting up an Access database for personal use. Let's say I have product categories as Male, Female, Unisex. I have product colors as black and white. When entering an order, I select a color (combo box) i.e black and then gender (combo box) i.e male. In the order form gender can be either male or female but not unisex.
In prodcut id field (combo box) I need to see black items with male and unisex gender.
When I set up the query in product id combo, the OR operator precedes the AND operator, then I see white items too. As a result I see all the male and unisex items.
I couldn't find a way put an OR operator within an AND operator so to speak.
I changed my approach and instead of placing Male, Female, Unisex in one field, I created two checkbox fields, Male and Female. This time I tried to query Products.Male=True if GenderCombo=Male, Products.Female=True if GenderCombo=Female along with color but no luck.
Which approach do you recommend and what should be the query like.
Thanks in advance for your help.
Bekir.
Check your query script, and note that AND has a higher precedence than OR. You will have to use brackets to get exactly what you want.
example:
where productcolor = 'Black' and gender = 'Unisex' or gender = 'Male'
this will give you all Black Unisex together with all Male of any color.
What you want is probably:
where productcolor = 'Black' and (gender = 'Unisex' or gender = 'Male')
You could also write that as:
where productcolor = 'Black' and gender in ('Unisex', 'Male')
If I have a column of possible choices:
choices
-------
Coke
Pepsi
7-Up
Water
And I have a table of user feedback, how could I check to see if the feedback contains the list of choices? Or more specific to my issue, I'm checking to see if the feedback contains the phrase: "I love {one of the choices}". The list of choices can grow over time, but the feedback may have phrases such as "I love Milk" which I don't want to show up in the results. Similarly, the feedback may say "I hate Water", which should not be in the results (unless, of course, they also say "I love Water" in the feedback). So just doing a keyword match wouldn't work.
Is there is a function similar to INSTR and IN, where I could say, maybe:
SELECT feedback_id FROM feedback where
INSET(feedback_note, SELECT CONCAT("I Love ", choices) FROM choice_list)
Update
I didn't know about the ANY operator worked until after asking, but my attempt to use it isn't working. I tried:
SELECT feedback_id, feedback_note FROM feedback
having feedback_note LIKE ANY
(SELECT distinct CONCAT("I love ", choices, "%") from choice_list);
This is just not allowed, I learned, so I thought I'd at least see if would work for a one line "I love Pepsi" so I did:
SELECT feedback_id, feedback_note FROM feedback
having feedback_note = ANY
(SELECT distinct CONCAT("I love ", choices, "%") from choice_list);
And after a minute or so, the query was still running (I executed it). So is there some way to use LIKE and ANY together, maybe not directly?
You could use the LIKE condition with wildcards.
For, example if you have the following table schema:
[choices]
id | text
1 | Coke
2 | Pepsi
[feedback]
id | note
1 | I love Pepsi.
2 | I really like Coke
3 | This comment has nothing to do with anything
In PostgreSQL you could do something like:
SELECT feedback.id
FROM feedback, choices
WHERE choices.text in (SELECT text FROM choices)
AND feedback.note LIKE '%' || text || '%'
or
SELECT feedback.id
FROM feedback
INNER JOIN choices ON feedback.note LIKE '%' || choices.text || '%'
(the second one is faster)
% is the wildcard operator, the LIKE condition will match anything that has choice between any other characters.
I have no way to test this code right now, but something similar should work in PostgreSQL.
ps: || is the string concatenation operator in PostgreSQL, beware that string concatenation varies between rdbms.
ps2: you can also use ILIKE instead of LIKE if you want it to be case insensitive
My approach:
SELECT feedback_id, feedback_note
FROM feedback
WHERE
SUBSTRING(feedback_note,1,7) = "I Love " and
SUBSTRING(feedback_note FROM 8) in
(SELECT choices from choice_list)
or:
SELECT feedback_id, feedback_note
FROM feedback
WHERE
SUBSTRING(feedback_note,1,7) = "I Love " and
exists
(SELECT 1 from choice_list
where choices = SUBSTRING(feedback_note FROM 8)
)
sql select in relation many-to-many not works as expected
i have the following tables in relation many-to-many:
table product:
prd_cod (pk)
cat_cod (fk)
prd_nome
table description_characteristic:
prd_cod(fk)
id_characteristic(fk)
description
table characteristic:
id_characteristic(pk)
name
we suppose that the cat_cod will be 1, so i want to show all the products that have the category code equals 1,that will be provided dynamically in php for parameter ...
I have done this select below to solve my problem:
select p.prd_cod,p.prd_name,c.name_characteristic,dc.description
from product p,description_characteristic dc, characteristic c
where p.prd_cod = dc.prd_cod and
dc.id_ccharacteristic = c.id_characteristic and
p.cat_cod = 1
but the data were shown this way:
Prd_cod Prd_name name_characteristic descript
1 pen Color pink
1 Pen manufacturer kingston
1 Pen type brush
1 Pen weight 0.020
I want to show the result this way:
Prd_cod Prd_name name_characteristic descript name_characteristic descript
1 pen Color pink type brush
2 Pen-drive manufacturer kingston weight 0.020
I would like to show all the characteristics of the same product, and not just two as above...
I can not do a select to solve this
please i need help
Thank you all
As stated by Tom H., your database layout may generally be a bad idea and you might reconsider it. That said, there is no really clean solution producing the mysql result set you want. But you might use something crazy with GROUP_CONCAT like this, reproducing the real data with some PHP-side postprocessing:
SELECT p.prd_cod, p.prd_name, GROUP_CONCAT(c.name_characteristic), GROUP_CONCAT(dc.description)
from product p,description_characteristic dc, characteristic c
where p.prd_cod = dc.prd_cod and
dc.id_ccharacteristic = c.id_characteristic and
p.cat_cod = 1
GROUP BY p.prd_cod
This should return something like
Prd_cod Prd_name name_characteristic descript
1 pen Color,manufacturer pink,Apple
this result set should be post-processed like this:
$out = array();
foreach ($result as $res) {
$p = array_combine(
explode(",", $res["name_characteristic"]),
explode(",", $res["descript"]));
$p["prd_cod"] = $res["prd_cod"];
$out[] = $p;
}
I would not call this a robust solution, though - for example, commas in your values screw things up. If you want to avoid madness like this, you'll have to postprocess the result you already get.
But if you want to show some mad sql aggregation skills (and you seem to be interested as you've chosen this database layout), this one is for you.