I have a catID column in product table, it is contain category ids as string,
Something like that '142,156,146,143'
and i Have a query '?catID=156,141,120'
i want to search each id in catID column.
I use this query:
SELECT * FROM product WHERE catID REGEXP '156|141|120'
this code return products which have any id in catID column , but I want to return products which is have all id,
So , I'am looking for and operator in REGEXP , but I'am couldn't find.
I want to use REGEXP or something like that which function provide to find product with one query , I don't wan to use
catID LIKE '156' AND catID LIKE '141' ....
if it is posibble.
EDIT : I don't want to perform a function one more time , because the query can be have 100+ id so it's make more harder to write code,
You need to use find_in_set() for each category id parameter in order to find the values in set,also if you can alter the schema then do normalize it, by having another junction table which holds the relation from this table to category table
select * from
product
where
find_in_set('142',catID ) > 0
For multiple values like find_in_set('161,168,234,678',preferred_location ) > 0 no it can't be possible doing like this you have to perform for each location id like
select * from
product
where
find_in_set('142',catID ) > 0
and find_in_set('156',catID ) > 0
and find_in_set('146',catID ) > 0
and find_in_set('143',catID ) > 0 ... for more
Database normalization
find_in_set
Sample Schema
Table
Products (id,other columns)
Categories (id,other columns)
Product_categories (id,product_id,category_id)
Product_categories is a junction table which will hold product_id and one category_id per each product so each will have a relation with single category and single product at a time
For example
Products
id name
1 product 1
2 product 2
Categories
id name
142 category 1
156 category 2
146 category 3
143 category 4
Product_categories
id product_id category_id
1 1 142
2 1 156
3 1 146
4 1 143
Now you can join these tables and query like below using in() and count should be equal to the no of category ids provided as parameter
select p.* from
Products p
join Product_categories pc on (p.id = pc.product_id)
where pc.category_id in(142,156,146,143)
group by p.id
having count(distinct pc.category_id) = 4
Sample Demo
or if you can't count the provided category ids as parameter you can do this by following query
select p.* from
Products p
join Product_categories pc on (p.id = pc.product_id)
where pc.category_id in(142,156,146,143)
group by p.id
having count(distinct pc.category_id) =
ROUND (
(
LENGTH('142,156,146,143')
- LENGTH( REPLACE ( '142,156,146,143', ",", "") )
) / LENGTH(",")
) + 1
Sample Demo 2
Related
I want to join columns from multiple tables to one column, in my case column 'battery_value' and 'technical_value' into column 'value'. I want to fetch data for only given category_ids, but because of UNION, I get data from other tables as well.
I have 4 tables:
Table: car
car_id model_name
1 e6
Table: battery
battery_category_id car_id battery_value
1 1 125 kW
Table: technical_data
technical_category_id car_id technical_value
1 1 5
3 1 2008
Table: categories
category_id category_name category_type
1 engine power battery
1 seats technical
3 release year technical
From searching, people are suggesting that I use union to join these columns. My query now looks like this:
SELECT CARS.car_id
category_id,
CATEGORIES.category_name,
value,
FROM CARS
left join (SELECT BATTERY.battery_category_id AS category_id,
BATTERY.car_id AS car_id,
BATTERY.value AS value
FROM BATTERY
WHERE `BATTERY`.`battery_category_id` IN (1)
UNION
SELECT TECHNICAL_DATA.technical_category_id AS category_id,
TECHNICAL_DATA.car_id AS car_id,
TECHNICAL_DATA.value AS value
FROM TECHNICAL_DATA
WHERE `TECHNICAL_DATA`.`technical_category_id` IN (3))
tt
ON CARS.car_id = tt.car_id
left join CATEGORIES
ON category_id = CATEGORIES.id
So the result I want is this, because I only want to get the data where category_id 1 is in battery table:
car_id category_id category_name technical_value
1 1 engine power 125 kW
1 3 release year 2008
but with the query above I get this, category_id 1 from technical table is included which is not something I want:
car_id category_id category_name value
1 1 engine power 125 kW
1 1 seats 125 kW
1 3 release year 2008
How can get exclude the 'seats' row?
For the results you want, I don't see why the cars table is needed. Then, you seem to need an additional key for the join to categories based on which table it is referring to.
So, I suggest:
SELECT tt.*, c.category_name
FROM ((SELECT b.battery_category_id AS category_id,
b.car_id AS car_id, b.value AS value,
'battery' as which
FROM BATTERY b
WHERE b.battery_category_id IN (1)
) UNION ALL
(SELECT td.technical_category_id AS category_id,
td.car_id AS car_id, td.value AS value,
'technical' as which
FROM TECHNICAL_DATA td
WHERE td.technical_category_id IN (3)
)
) tt LEFT JOIN
CATEGORIES c
ON c.id = tt.category_id AND
c.category_type = tt.which;
That said, you seem to have a problem with your data model, if the join to categories requires "hidden" data such as the type. However, that is outside the scope of the question.
I have the following SQL tables, and require a solution compatible with both MySQL and Postgresql
create table price_level (
id serial primary key,
name varchar(200)
);
create table product (
id serial primary key,
name varchar(200),
base numeric not null,
vat int not null
);
create table product_price (
id serial primary key,
base numeric,
vat numeric,
product_id int not null references product(id) on update cascade on delete cascade,
price_level_id int not null references price_level(id) on update cascade on delete cascade,
unique(product_id,price_level_id)
);
For the SQL structure above I've created a view:
create view view_product as
select
p.id as product_id,
coalesce(pp.base, p.base) as base,
coalesce(pp.vat, p.vat) as vat,
pp.price_level_id
from
product as p
left join
product_price as pp on pp.product_id=p.id
;
These are sample data:
Table price_level
id name
1 A
2 B
3 C
4 D
5 E
Table product
id name base vat
1 Test 100 20
Table product_price
id base vat product_id price_level_id
1 NULL NULL 1 1
2 200 NULL 1 2
3 NULL 10 1 3
Output of the view view_product is:
product_id base vat price_level_id
1 100 20 1
1 200 20 2
1 100 10 3
... and the question is: How do I get output like this?:
product_id base vat price_level_id
1 100 20 1
1 200 20 2
1 100 10 3
1 100 20 4
1 100 20 5
As you see in the example above I need to get D and E price_level as additional rows. How do I create such view/join? It should have good performance also because tables can get big with additional price levels.
Thanks for help.
I would use union to add those records from price_level table that do not have corresponding record in product_price table for a certain product:
select
p.id as product_id,
coalesce(pp.base, p.base) as base,
coalesce(pp.vat, p.vat) as vat,
pp.price_level_id
from
product as p
left join
product_price as pp on pp.product_id=p.id
union distinct
select
p.id as product_id,
p.base,
p.vat,
pl.price_level_id
from
price_level pl
join
product as p
where (p.id, pl.id) not in (select product_id, price_level_id from product_price)
I would use following approach, cross join tables price_level and product. Then just lookup if override exists in product_price table.
SELECT
product.id as product_id,
IFNULL(product_price.base, product.base) as `base`,
IFNULL(product_price.vat, product.vat) as `vat`,
price_level.id as price_level_id
FROM price_level
CROSS JOIN product
LEFT JOIN product_price ON
product_price.price_level_id = price_level.id AND
product_price.product_id = product.id
WHERE product.id = 1
ORDER BY product.id, price_level.id
just remember to use product.id and not product_id in WHERE conditions
Try with:
create view view_product as
select
p.id as product_id,
coalesce(pp.base, p.base) as base,
coalesce(pp.vat, p.vat) as vat,
coalesce(pp.price_level_id,pl.id) --modified row
from
product as p
left join
product_price as pp on pp.product_id=p.id
LEFT JOIN price_level pl on pp.price_level_id=pl.id -- modified row
;
(not tested, but for sure you have to catch the price levels from the properly table)
I have a table with data similar to this:
id job_id filename status revision product
----------------------------------------------------------
1 1 1r0.jpg P 0 Product 1
2 1 2r0.jpg P 0 Product 2
3 1 3r0.jpg P 0 Product 3
4 1 2r1.jpg P 1 Product 2
I want to run an SQL query that returns the following:
id job_id filename status revision product
----------------------------------------------------------
1 1 1r0.jpg P 0 Product 1
3 1 3r0.jpg P 0 Product 3
4 1 2r1.jpg P 1 Product 2
i.e. if there's two rows with the same product name, I want to get the one with the highest revision number.
I've tried lots of queries using groupby, max, distinct to no avail. I've tried self-joins but cannot get the results I'm after.
For example, the query SELECT *, MAX(revision) FROM artworks GROUP BY product gives me data that looks fine at first glance but the row contains the data from the one with the lowest revision number, not the highest.
You can do it without GROUP BY, like this:
SELECT *
FROM artworks a
WHERE NOT EXISTS (
SELECT *
FROM artworks aa
WHERE a.product=aa.product AND a.revision < aa.revision
)
You may get the same result without a sub-query:
SELECT a.*
FROM artworks a
left join artworks b
on a.produc = b.produc
and a.revision < b.revision
where b.id is null;
I have 332 products in a selection table and would like to return exactly 332 results. Each product has been rated or not by a given user in the matching table. These are the results from two tables using the following query
SELECT a.product_id,a.brand,b.user_id,b.rating,b.comment
FROM selection a
LEFT JOIN matching b ON a.product_id = b.product_id
product_id brand user_id rating comment
1 A & P 30 4.5 NULL
1 A & P 30 4.5 NULL
1 A & P 52 1 NULL
2 A & W 1 3 good flavor
2 A & W 24 5 NULL
I want to return all the products with a rating and comment where user_id = 1 and then the remaining products where user 1 did not rate or comment on the product. I have tried
WHERE user_id = 1 OR
user_id <> 1 AND rating ID NULL and comment IS NULL
This will just return the same as WHERE user_id = 1. I have also tried GROUP BY product_id This returns the correct number of results but not all of the user's ratings or comments were controlled by this alone. Is there a way to define the user that it will select when returning the grouped results? Any other suggestions? Thanks!
If you meant for the WHERE statement to include two separate conditions you need to surround the second statement in parenthesis; otherwise SQL would treat each operator as its own condition:
WHERE user_id = 1 OR
(user_id <> 1 AND rating ID NULL and comment IS NULL)
I am trying to select DISTINCT products from within categories with category ids (1, 5, 12), ORDERED by cat_order + prod_order from MySQL database
The problem:
if a product is found in more than 1 category I need to show the first result,
ie: product number 1 is assigned to categories 1 and 5, I need to display product number 1 from category 1 along with its prod_order and skip the listing in category 5,
essentually I need to display all products from category 1, than move on to category 5 and display all products from there, where product id was not shown previously, and move on to another category in the list (12)
if I run something like:
SELECT
prod_to_cat.prod_id AS prod_to_cat_prod_id,
prod_to_cat.prod_order AS prod_to_cat_prod_order,
prod_to_cat.cat_id AS prod_to_cat_cat_id,
prod_to_cat.cat_order AS prod_to_cat_cat_order,
products.id,
products.name
FROM
prod_to_cat, products
WHERE
prod_to_cat.prod_id = products.id
AND prod_to_cat.cat_id IN (1, 5, 12)
GROUP BY
prod_to_cat.prod_id
ORDER BY
prod_to_cat_cat_order ASC,
prod_to_cat_prod_order DESC
I get inconsistent results (product 1 will not be selected from the first category in the list), that is why I opted to select without "GROUP BY prod_id" and wrap that with another select which than groups by prod_id.
like so:
SELECT
prod_to_cat_prod_id,
prod_to_cat_prod_order,
prod_to_cat_cat_id,
name
FROM
(
SELECT
prod_to_cat.prod_id AS prod_to_cat_prod_id,
prod_to_cat.prod_order AS prod_to_cat_prod_order,
prod_to_cat.cat_id AS prod_to_cat_cat_id,
prod_to_cat.cat_order AS prod_to_cat_cat_order,
products.id,
products.name
FROM
prod_to_cat, products
WHERE
prod_to_cat.prod_id = products.id
AND prod_to_cat.cat_id IN (1, 5, 12)
ORDER BY
prod_to_cat_cat_order ASC,
prod_to_cat_prod_order DESC
) AS prod
GROUP BY
prod_to_cat_prod_id
ORDER BY
prod_to_cat_cat_order ASC,
prod_to_cat_prod_order DESC
LIMIT 0, 10;
What I am trying to do:
I am trying to find a more efficiant way to do this.
Table structure:
prod_to_cat:
prod_id | cat_id | cat_order | prod_order |
1 1 1 2
2 1 1 0
3 1 1 0
1 5 2 4
4 5 2 0
products:
id | name | descr | price |
1 name_1
2 name_2
3 name_3
4 name_4
each product can be in any number of categories, for example product id 1 is in categories id 1 and 5 in the example above.
Thanks a lot for any replies.
Pasha
You want the groupwise minimum:
SELECT prod_to_cat.*,
products.name
FROM prod_to_cat NATURAL JOIN (
SELECT prod_id,
MIN(cat_id) AS cat_id
FROM prod_to_cat
WHERE cat_id IN (1, 5, 12)
GROUP BY prod_id
) t
JOIN products ON t.prod_id = products.id
ORDER BY prod_to_cat.cat_order ASC,
prod_to_cat.prod_order DESC
See it on sqlfiddle.