Select multiple rows containing values from one column - mysql

Actually my question is almost the same with MySQL: Select multiple rows containing values from one column, I want to find the car_id of the cars that have MAKE='FORD' AND COLOR='SILVER', so in this case here it will returns car_id 1 and 2.
PS: There could be multiple criteria at once, like I can search by MAKE + CARLINE + COLOR, MAKE + CARLINE, and etc.
table_cars
+----+--------+----------+-----------+
| id | car_id | name | value |
+----+--------+----------+-----------+
| 1 | 1 | MAKE | FORD |
| 2 | 1 | CARLINE | FIESTA |
| 3 | 1 | COLOR | SILVER |
| 4 | 1 | TOPSPEED | 210KM/H |
| 5 | 2 | MAKE | FORD |
| 6 | 2 | CARLINE | FOCUS |
| 7 | 2 | COLOR | SILVER |
| 8 | 2 | TOPSPEED | 200KM/H |
| 9 | 3 | MAKE | HOLDEN |
| 10 | 3 | CARLINE | ASTRA |
| 11 | 3 | COLOR | WHITE |
| 12 | 3 | TOPSPEED | 212KM/H |
+----+--------+----------+-----------+
Thank you!

select car_id
from your_table
group by car_id
having sum(name = 'MAKE' and value = 'FORD') > 0
and sum(name = 'COLOR' and value = 'SILVER') > 0

Try with self join as below:
SELECT distinct car_id
FROM mytable mt1 INNER JOIN mytable mt2
ON mt1.car_id = mt2.car_id
WHERE mt1.name = 'MAKE'
AND mt1.value = 'FORD'
AND mt2.name = 'COLOR'
AND mt2.value = 'SILVER'

Related

SQL - Get rows with one result and selected option - Relation Table

I have a table that has the relations of products and colors. Each product has one or multiple colors. Is it possible to do a query that returns only the products that have one color only and the color wanted ?
Value from the api : color_slug = white ;
Sample table :
color_table
+----------+------------+
| color_id | color_slug |
+----------+------------+
| 1 | white |
| 2 | blue |
| 3 | black |
| 4 | green |
| 5 | red |
| 6 | yellow |
+----------+------------+
product_table
+------------+--------------+
| product_id | product_name |
+------------+--------------+
| 1 | shoes |
| 2 | shorts |
| 3 | t-shirt |
| 4 | jacket |
| 5 | watch |
| 6 | glasses |
+------------+--------------+
pc_relation
+----+------------+----------+
| id | product_id | color_id |
+----+------------+----------+
| 1 | 1 | 5 |
| 2 | 1 | 1 |
| 3 | 2 | 1 |
| 4 | 2 | 4 |
| 5 | 2 | 3 |
| 6 | 3 | 2 |
| 7 | 4 | 1 |
| 8 | 5 | 5 |
| 9 | 5 | 6 |
| 10 | 6 | 1 |
+----+------------+----------+
Select unique color values (if i put WHERE color_id = 1 the product colors are not longer of one color only) :
SELECT product_id
FROM pc_relation
// WHERE color_id = 1
GROUP BY product_id
HAVING MIN(color_id) = MAX(color_id)
pc_relation.id = 6,7,10
SELECT *
FROM color_table
INNER JOIN pc_relation ON pc_relation.color_id = color_table.color_id
INNER JOIN product_table ON pc_relation.product_id = product_table.product_id
WHERE colors.color_slug = 'white'
Values wanted (color_slug = white):
pc_relation.id = 7,10
product_table.product_name = jacket, glasses
*all the combinations are unique and indexed. For example I cannot have one product with the same color
twice.
You are on the right track with your first query. Move the color comparison to the HAVING clause:
SELECT product_id
FROM pc_relation
GROUP BY product_id
HAVING MIN(color_id) = MAX(color_id) AND
MIN(color_id) = 1;
You can also phrase this using NOT EXISTS:
select r.*
from pc_relation r
where r.color_id = 1 and
not exists (select 1
from pc_relation r2
where r2.product_id = r.product_id and r2.color_id <> r.color_id
);
However, the GROUP BY method is more general.

Joining multiple rows with same ID in one

I am having trouble with an SQL query. I have two tables.
My first table:
+------------+-------------+---------------+
| id_mission | Some column | Other column |
+------------+-------------+---------------+
| 1 | ... | ... |
| 2 | ... | ... |
+------------+-------------+---------------+
My second table:
+------------+-------------+---------+
| id_mission | id_category | points |
+------------+-------------+---------+
| 1 | 1 | 3 |
| 1 | 2 | 4 |
| 1 | 3 | 4 |
| 1 | 4 | 8 |
| 2 | 1 | -4 |
| 2 | 2 | 3 |
| 2 | 3 | 1 |
| 2 | 4 | -7 |
+------------+-------------+---------+
And I would like to have this kind of result with my SELECT request
+------------+-------------+--------------+---------------+----------------+
| id_mission | Some column | Other column | id_category 1 | id_category X |
+------------+-------------+--------------+---------------+----------------+
| 1 | ... | ... | ... | ... |
| 2 | ... | ... | ... | ... |
+------------+-------------+--------------+---------------+----------------+
I have tried this with the first two column but it doesn't work, I also tried GROUP_CONCAT, it works but it's not the result I want.
SELECT m.id_mission ,mc.id_category 1,mc1.id_category 2
from mission m
left join mission_category mc on m.id_mission = mc.id_mission
left join mission_category mc1 on m.id_mission = mc1.id_mission
Can someone help me?
You can use conditional aggregation. Assuming that you want to pivot the points value per category:
select
t1.*,
max(case when t2.id_category = 1 then points end) category_1,
max(case when t2.id_category = 2 then points end) category_2,
max(case when t2.id_category = 3 then points end) category_3
from t1
inner join t2 on t2.id_mission = t1.id_mission
group by t1.id_mission
This assumes that id_mission is the primary key of t1 (else, you need to enumerate the columns you want in both the select and group by clauses).

MySQL - custom, additional columns based on foreign keys with other table

I have the following database schema:
Table: products
| id | name | content |
|----|--------|---------|
| 1 | Pen | ... |
| 2 | Pencil | ... |
| 3 | Rubber | ... |
| 4 | Ruler | ... |
Table: feature_types
| id | name |
|----|----------|
| 1 | Color |
| 2 | Material |
| 3 | ... |
| 4 | ... |
Table: features
| id | product_id | feature_type_id | value |
|----|------------|-----------------|-----------|
| 1 | 1 | 1 | Red |
| 2 | 1 | 2 | Aluminum |
| 3 | 2 | 1 | Green |
| 4 | 2 | 2 | Wood |
| 5 | 3 | 1 | White |
| 6 | 4 | 2 | Plastic |
My question is how can I do something like this:
SELECT *, ... FROM products ...
With result:
| id | name | content | feature_type_1 | feature_type_2 |
|----|--------|---------|----------------|----------------|
| 1 | Pen | ... | Red | Aluminum |
| 2 | Pencil | ... | Green | Wood |
| 3 | Rubber | ... | White | NULL |
| 4 | Ruler | ... | NULL | Plastic |
So as you see, in results we have all columns from products table and additional columns for specified feature_types. Column names correspond to their identifiers, according to the pattern: "feature_type_{ID}".
I know feature_types IDs so it is not necessary to add all possible columns feature_types. I need only 2 additional columns with ID 1 and 2.
If you are only interested in the features: Color and Material, join the tables and group by product:
select
p.id, p.name, p.content,
max(case when t.name = 'Color' then f.value end) Color,
max(case when t.name = 'Material' then f.value end) Material
from products p
left join features f on f.product_id = p.id
left join feature_types t
on t.id = f.feature_type_id and t.name in ('Color', 'Material')
group by p.id, p.name, p.content
I guess in your sample data you did a mistake by setting 1 instead of 2 as feature_type_id for Plastic in the table features.
See the demo.
Results:
| id | name | content | Color | Material |
| --- | ------ | ------- | ----- | --------- |
| 1 | Pen | ... | Red | Aluminium |
| 2 | Pencil | ... | Green | Wood |
| 3 | Rubber | ... | White | |
| 4 | Ruler | ... | | Plastic |
Here's one solution to the part of the problem with which you are struggling...
SELECT product_id
, MAX(CASE WHEN feature_type_id = 1 THEN value END) feature_type_1
, MAX(CASE WHEN feature_type_id = 2 THEN value END) feature_type_2
FROM features
GROUP
BY product_id;
+------------+----------------+----------------+
| product_id | feature_type_1 | feature_type_2 |
+------------+----------------+----------------+
| 1 | Red | Aluminium |
| 2 | Green | Wood |
| 3 | White | NULL |
| 4 | Plastic | NULL |
+------------+----------------+----------------+
4 rows in set (0.03 sec)
or...
SELECT f1.product_id
, f1.value feature_type_1
, f2.value feature_type_2
FROM features f1
LEFT
JOIN features f2
ON f2.product_id = f1.product_id
AND f2.feature_type_id = 2
WHERE f1.feature_type_id = 1;
a semplified way is based on building a string using group_concat
select p.id, p.name, p.content , group_concat( concat(t.name,':',f.value )) all_features
from products p
inner join features f on f.product_id = p.id
inner join feature_types t on t.id = f.feature_type_id
group by p.id

Multiple select from one row from A table and insert result as multiple rows in B table and repeat in one query

I need insert data from static table to table with multiple custom options, so it looks like below.
A table:
+------+------+--------+-------+
| name | type | weight | color |
+------+------+--------+-------+
| 1 | A | 10 | green |
+------+------+--------+-------+
| 2 | B | 3 | blue |
+------+------+--------+-------+
| 3 | D | 9 | gold |
+------+------+--------+-------+
Desired Output:
+------+-------------+--------------+
| name | option_name | option_value |
+------+-------------+--------------+
| 1 | type | A |
+------+-------------+--------------+
| 1 | weight | 10 |
+------+-------------+--------------+
| 1 | color | green |
+------+-------------+--------------+
| 2 | type | B |
+------+-------------+--------------+
| 2 | weight | 3 |
+------+-------------+--------------+
| 2 | color | blue |
+------+-------------+--------------+
| 3 | type | D |
+------+-------------+--------------+
| 3 | weight | 9 |
+------+-------------+--------------+
| 3 | color | gold |
+------+-------------+--------------+
Is it possible?
You can use cross join trick to "UNPIVOT" the values:
select
t.name,
case x.i
when 1 then 'type'
when 2 then 'weight'
when 3 then 'color'
end option_name,
case x.i
when 1 then type
when 2 then cast(weight as char(50))
when 3 then color
end option_value
from your_table t
cross join (
select 1 i union all
select 2 i union all
select 3 i
) x
cast(weight as char(50)) is required for weight because the data types need to be consistent and weight is (probably) a numeric column and needs to be converted into string.
SQLFiddle

SQL Advanced SELECT Statement

translations
+---------+----------------+----------+---------+
| id_user | id_translation | referrer | id_word |
+---------+----------------+----------+---------+
| 1 | 3 | NULL | 4 |
| 1 | 17 | NULL | 3 |
| 2 | 17 | NULL | 5 |
| 2 | 17 | NULL | 1 |
| 2 | 17 | NULL | 7 |
words
+----+------+
| id | word |
+----+------+
| 4 | out |
+----+------+
users_translations
+---------+----------------+----------+---------+
| id_user | id_translation | referrer | id_word |
+---------+----------------+----------+---------+
| 1 | 17 | 1 | 4 |
| 2 | 17 | 2 | 4 |
| 3 | 18 | NULL | 4 |
I need to select all translations for current word and id_translation, but if in the row referrer = 1 (current user), then I don't need another results (translations from another users for current word), if there is no referrer = 1, show all.
SELECT DISTINCT `t`.*, `ut`.`id_user` AS tuser
FROM translations AS t
LEFT JOIN users_translations AS ut ON `t`.`id` = `ut`.`id_translation`
INNER JOIN words ON `words`.`id` = `ut`.`id_word` OR `words`.`id` = `t`.`id_word`
WHERE (`word` = 'help')
ORDER BY `t`.`translation` ASC
+----+-------------+---------+---------+-------+
| id | translation | id_word | id_user | tuser |
+----+-------------+---------+---------+-------+
| 17 | допомагати | 4 | 1 | 2 |
| 17 | допомагати | 4 | 1 | 1 |
First row doesn't need, because we have tuser = 1. When there is no tuser = 1, all results should be returned.
I don't understand how to build select statement and I will be very appreciative that somebody shows me how to make it work.
First thing that comes to mind
--add this to your where clause
id_user <=
CASE WHEN EXISTS(SELECT * FROM translations WHERE id_user = 1 AND id_word = words.id_word)
THEN 1
ELSE (SELECT MAX(Id) FROM translations)
END