I have a database table where I am storing all the values from an external xml file. Since my project requirement demands me to deal with this unnormalized data. I need to help to extract data in an appropriate way.
I have two web pages (one for categories) and one for products.My database table looks like this:
**product_id Code Name ProductRange ProductSubRange WebCategory**
1 1002 Lid 30l Crystal;Uni LIDs Household products
2 10433 Casa Basket Silver Casa Casa Hipster BASKET Kitchenware
3 17443 Casa Basket Ice White Casa;Laundry LAUNDRY BASKET Laundry products
4 13443 Garden tub Eden Eden Garden Pots Household products
5 199990 Black Lid 201 Crystal Crystal Lids Household products
The product that belong to more than one productRange is indicated my semicolon(;). For example,above product_id 1 with name "Lid 301" belongs to two Product Ranges "Crystal" and "Uni". Same is for product_id 3. However product 2 belongs to single ProductRange.
MY QUESTIONs:
1) How can I construct a query so that it could return "ProductRange" based on my query_string values of "Webcategory"? For example:
if I get "Household Products" as my WebCategory from query string, it could give me distinct like this:
Household Products
|-Crystal
|-Uni
|-Eden
Laundry Products
|-Casa
|-Laundry
Kitchenware
|-Casa
2) Based on extracted ProductRanges, I want to display products separately in my webpages according to the product range and webcategory. For example, if I choose "Crystal" from above, it could give me Products with product_id "1" and "5" respectively like this:
Household Products|
|-Crystal
|-Lid 301 (product_id=1)
|-Balck Lid 201 (product_id=5)
|-Uni
|-Lid 301 (product_id=1)
|-Eden
|-Garden Tub
Kitchenware|
|-Casa
|-Casa Basket silver
Laundry Products|
|-Casa
|-Casa Basket Ice White
|
|-Laundry
|-Casa Basket Ice White
Can anyone guide me how can I retrieve records from the database and what I will need to do as I am new to programming? I would appreciate if anyone could help me in this regard.
In order to get distinct product ranges based on a give WebCategory input = 'XYZ', you can use the following - don't be intimidated by the numberstable, it's just a helpful table that contains rows each with increasing integer values from 1 ... up to N where N is the maximum number of characters in your ProductRange column. These can be made by hand or using a special insert/select query like the one found here:
http://www.experts-exchange.com/Database/MySQL/A_3573-A-MySQL-Tidbit-Quick-Numbers-Table-Generation.html
SELECT DISTINCT
SUBSTRING(ProductRange FROM number FOR LOCATE(';', ProductRange, number) - number) AS ProductRange
FROM (
SELECT ProductRange, CASE number WHEN 1 THEN 1 ELSE number + 1 END number
FROM (
SELECT mydatabasetable.ProductRange, numberstable.number
FROM mydatabasetable
INNER JOIN numberstable
ON numberstable.number >= 1
AND numberstable.number <= CHAR_LENGTH(mydatabasetable.ProductRange)
WHERE WebCategory = 'XYZ'
) TT
WHERE number = 1 OR (number + 1) <= CHAR_LENGTH(ProductRange)
) TT
WHERE SUBSTRING(ProductRange FROM number FOR 1) = ';'
OR numberstable.number = 1;
In order to retrieve a result set with all values WebCategory, ProductRange and Product for your website you can use the below slightly modified version derived from the above query. So that the results will appear more meaningful at first, I added an ORDER BY clause to keep all same-category, same-product-range products in sequence one after the other. This might or might not be desired as you might prefer to do that in your application/server-script code. In that case you can remove the ORDER BY clause without doing any harm.
SELECT WebCategory,
SUBSTRING(
ProductRange
FROM number
FOR LOCATE(';', ProductRange, number) - number
) AS ProductRange,
Product
FROM (
SELECT WebCategory, ProductRange, Product,
CASE number
WHEN 1 THEN 1
ELSE number + 1
END number
FROM (
SELECT WebCategory, ProductRange, Product, numberstable.number
FROM mydatabasetable
INNER JOIN numberstable
ON numberstable.number >= 1
AND numberstable.number <= CHAR_LENGTH(ProductRange)
) TT
WHERE number = 1 OR (number + 1) <= CHAR_LENGTH(ProductRange)
) TT
WHERE SUBSTRING(ProductRange FROM number FOR 1) = ';'
OR numberstable.number = 1
ORDER BY WebCategory, ProductRange, Product
You are probably going to want to do a GROUP BY clause in your query and maybe an JOIN if the detailed data is in a different table. If I understand you correctly it would look something like this.
SELECT T.WebCategory, T.ProductRange, T2.Product FROM table T
INNER JOIN table2 T2 ON T2.ProductRange = T.ProductRange
WHERE T.WebCategory = 'Household products'
GROUP BY T.WebCategory, T.ProductRange, T2.Product
It is tough to test my query without having a database setup to test against, but something like the above should return what you are looking for. You will of course need to rename your columns based on the actual names in the second table. Overall though, this should get you started if I understood the question correctly.
Related
► Context : I work in a museum (for real), people come everyday, they buy tickets for themselves (humans) and sometimes they also buy tickets for drinks and foods (objects). There are events, tickets have the same names per event but the prices are different.
► The problem : I have to create a report with 2 results : total sales (visitors + food + drinks) and how many people came (visitors only) for a specific event. Next is an image of the 3 tables in the database, how they relate and some sample data :
Table TICKETS relates to SALES_MAIN through EVENT_ID column.
Table SALES_MAIN relates to SALES_DETAIL through ID→MAIN_ID columns.
Table SALES_DETAIL have a column TICKET_NAME but it's not unique in table TICKETS.
► The question : How to get both results, total sales and human count, for event 555 in one "select" ? I tried next 2 "select" but when I combine them with another INNER JOIN I get cartesian results :
Get detail sales for event 555 :
SELECT sales_detail.* FROM sales_main
INNER JOIN sales_detail ON sales_detail.main_id = sales_main.id
WHERE sales_main.event_id = '555'
Get tickets for event 555 :
SELECT * FROM tickets WHERE tickets.event_id = '555'
Use:
SELECT
SUM(CASE WHEN sd.ticket_name IN ('adult', 'child') THEN sd.quantity
ELSE 0 END) AS total_visitors,
SUM(sd.quantity * t.price) AS total_sales
FROM sales_main sm
JOIN sales_detail sd
ON sd.main_id = sm.id
JOIN ticket t
ON t.event_id = sm.event_id
AND t.ticket_name = sd.ticket_name
WHERE sm.event_id = '555';
Conditional aggregation could also be based on type:
SUM(CASE WHEN t.ticket_type ='human' THEN sd.quantity ELSE 0 END)
I currently have an Array in PHP with product numbers. Lets call that products.
In my database I have a table containing combinations of product numbers and the price that belongs to that product.
Problem: My Array can hold duplicate entries if for instance article #1 is ordered twice.
If I use a query like
SELECT SUM(price) FROM articles WHERE article_number IN (products)
the duplicate entry of 1 get discarded. The query I am looking for gives the sum of 10 + 10 + 12.5 + 9.95.
Is there a way to do this within MySQL?
As a clarification to my data:
products = [1, 1, 2, 3];
articles| article_number | price
__________________________________
| 1 | 10.0
| 2 | 12.5
| 3 | 9.95
Thank you :)
winmutt has a solid answer. However, if you don't have such a table to to join with then you could build your query like so:
select sum (p) from (
(select price as p from articles where article_number = 1)
union all
(select price as p from articles where article_number = 1)
union all
(select price as p from articles where article_number = 2)
union all
(select price as p from articles where article_number = 3)
) s
If your products were in a table you could do a simple JOIN:
SELECT SUM(price) FROM articles JOIN products on article_number=product_number
I thought there might be an easier way of doing this in SQL. I solved it in PHP by querying all the prices of the array's products and then in iterating over my Array in PHP to sum up the price there.
I have a slight issue with a search function I am developing and I would need your help.
To summarize, there is a list of products displayed to the users; upon clicking on different criteria, the user can reduce the size of this list and find the right product.
Example of search criteria:
For instance, it will get all the products from category 222. Then if the user clicks on the color "D", it will show only the products with color "D". If the users adds the color "E", it will show products with either one.
The very important thing is, if the user clicks on color "D", color "E" and then on clarity "FL" and clarity "IF"; it has to show the products with ((color = D OR color = E) AND (clarity = FL OR clarity = IF)).
However, the database is not structured that way and all the different options (color D, color E, color E, clarity FL, clarity IF...) are under the same column entitled id_feature_value:
So far, here is my sql request (simplified for readability):
$sql = 'SELECT p.*
FROM `'._DB_PREFIX_.'product` p
LEFT JOIN `'._DB_PREFIX_.'category_product` c ON (c.`id_product` = p.`id_product`)
LEFT JOIN `'._DB_PREFIX_.'feature_product` f ON (f.`id_product` = p.`id_product`)
WHERE c.`id_category` = 222 '.$searchValues.
' GROUP BY f.`id_product` ORDER BY p.`id_product` DESC LIMIT '.$scroll.',20';
The $searchValues variable corresponds to what is explained above and - unfortunately and obviously - does not work.
The $scroll variable corresponds to the level of scroll of the users. This function gathers the 20 first items and, when the user reaches the bottom, will bring the 20 next entries.
I have had a look at the IN possibility however I couldn't not make it work because of the AND and OR combination.
Can you assist me a bit with this?
Let me know if you need additional information.
Thank you very much!
You can put your conditions inside of HAVING COUNT. For example, suppose id_feature = 20 represents the color and values 1142,1143 represent different colors. Then the query below would count how many of these two colors each product has and only return those that have 1 or more. You can add as many AND COUNT(CASE ... conditions as needed.
GROUP BY f.`id_product`
HAVING
COUNT(CASE
WHEN id_feature = 20
AND id_feature_value IN (1142,1143)
THEN 1
END) > 0
AND COUNT(CASE
WHEN id_feature = 23
AND id_feature_value IN (233,234)
THEN 1
END) > 0
Edit
Another approach, which may be faster, is to use EXISTS i.e.
SELECT p.* FROM product p
WHERE EXISTS (
SELECT 1 FROM feature_product
WHERE id_feature = 20
AND id_feature_value IN (1142,1143)
AND id_product = p.id
) AND EXISTS (
SELECT 1 FROM feature_product
WHERE id_feature = 23
AND id_feature_value IN (233,234)
AND id_product = p.id
)
I have a table named PRODUCTS with 3 columns for three different categories, i want to select all products which have any of the 3 values in any of the 3 columns.
What i'm trying to do is show related products based on any of the 3 categories.
Example table:
id,name,cat1,cat2,cat3
1,Keyboard,2,8,4
2,Mouse,2,NULL,NULL
3,Monitor,16,2,NULL
Let's supose i'm viewing ITEM id=1, i want to do a query to show the other 2 products that have category number 2 in any of the 3 columns.
How do I do that?
Thank you very much,
Andres
SELECT * FROM table_name WHERE id != 1 AND (cat1 = 2 OR cat2 = 2 OR cat3 = 2)
So, for any given ID, find the other "siblings" that have that same category as the chosen one, in their categories?
select id as chosen_id, p1.cat as p1_cat, p2.cat as p2_cat, p3.cat as p3_cat
from products p1, products p2, products p3
where
p1.cat = p2.cat
and
p1.cat = p3.cat
// and various other qualifications like, it's not a repeat
p1.id != p2.id
p1.id != p3.id
p2.id != p3.id
etc.
// you can also do join products p3 on p3.cat = p1.cat instead of
// the verbose way I did it
BTW this is a bad idea performance-wise. Best done programmatically and not in SQL.Any time you're dealing with cursor-ish queries like this, just do it with arrays in code, not in SQL
I have table of products, and there are 2 fields: price, currency. Possible values in currency fields are 1,2,3. 1 for MDL, 2 for USD, and 3 for EUR. I have to sort my products by price in mdl currency. So i have an array with rates:
$v = array(1,11.38,15.8);
Help my please with my query, I've tried something like this, but I've got errors:
$results = $this->Product
->query("SELECT `id`,`price`,`currency` FROM products
ORDER BY price*$v[currency] DESC");
Hmm... I`ll try to explain, through an example.
My table:
id|price|currency
_________________
1 | 500 | 2
2 | 300 | 3
It shows that first products price is saved in USD, and second products price is saved in EUR. But i have to sort them in MDL valute. So i get an array of rates for each value:
$rates = array([1] = > 1, [2] => 11.50, [3] => 15.50);
So i have to order my products by the result of formula: price*value rate
in first case: 500*$rates['currency value from db, in our case 2] = 500 * 11.50 etc.
Thanks in advance.
Because of the extended example on this problem I have edited this query.
Lets assume that the currencies are alse stored in some table, lets say currency (if not, it should be anyway).
Table currency should be as follows:
ID VALUE CODE
-----------------------------
1 1 USD
2 11.38 EUR
3 15.8 MDL
Then the query should be:
SELECT p.`id`, p.`price`, p.`price` * c.`value` AS 'ratio'
FROM products p
LEFT JOIN currency c ON c.`id` = p.`currency`
ORDER BY `ratio` DESC
By this query You select the currency value from the table currency depending on the currency ID from products table and finaly the results are ordered by the ration price * currency value.
I understand that maybe You have the currencies only hardcoded as array within some config, but it really would be better to put the currencies into the DB (if it is not).
You can`t use data base column name as array keys, because mysql is later instance than php. In php you simply generate query string that is passed to database managment system.
Your query should look like this:
$results = $this->Product->query
(
"SELECT `id`,`price`,
CASE `currency`
WHEN '1' THEN $v[0]
WHEN '2' THEN $v[1]
WHEN '3' THEN $v[2]
END AS 'ratio'
FROM products
ORDER BY price*ratio DESC
"
);