MYSQL: Select entries in relation to multiple rows of multiple table - mysql

I have three tables that I can't change the structure of:
facet
id name
-----------------
1 Series
2 Material
value
id facet_id name
----------------------------------
1 2 Glass
2 2 Metal
3 1 Series #1
4 1 Series #2
5 1 Series #3
product_facet_values
product_id value_id
-----------------------------------
1 1
1 3
2 1
2 4
3 2
3 5
4 1
I am trying to write two queries:
/1. One that will return the ids that represent the series facet from the values table where a product record is Glass and has any series. So an output like this:
id facet_id name
----------------------------------
3 1 Series #1
4 1 Series #2
Record 1 is not a series.
Record 2 is not a series.
Record 3 is returned because product #1 has both a series and material and the material is glass.
Record 4 is returned because product #2 has both a series and material and the material is glass.
Record 5 is not returned because product #3 has the material of metal even though it has both a series and material.
/2. Same as number one but return a list of product ids.
product_id
---------------
1
2
Product #1 is returned because it has both a series and material and the material is glass.
Product #2 is returned because it has both a series and material and the material is glass.
Product #3 is not returned because it has the material of metal even though it has both a series and material set.
Product #4 is not returned because it has no series set even though the material is glass.

FIRST QUERY:
try this.. I believe this will do the trick.
SELECT
v.id
FROM value v
JOIN product_facet_values pfv ON pfv.value_id = v.id
WHERE pfv.product_id IN
( SELECT
product_id
FROM product_facet_values
WHERE
product_id IN
( SELECT
product_id
FROM product_facet_values
GROUP BY product_id
HAVING COUNT(*) > 1
)
AND value_id = 1
)
AND v.facet_id = 1;
SECOND QUERY:
the inner part of the same query returns the products that have a value of 1 and a value of something other than one so it would be this
SELECT
product_id
FROM product_facet_values
WHERE
product_id IN
( SELECT
product_id
FROM product_facet_values
GROUP BY product_id
HAVING COUNT(*) > 1
)
AND value_id = 1
EXPLANATION:
INNERMOST SUBQUERY:
SELECT
product_id
FROM product_facet_values
GROUP BY product_id
HAVING COUNT(*) > 1
give me products that have more than one record per product (later to be filtered by 'Glass' and 'Series')
MIDDLE SUBQUERY:
SELECT
product_id
FROM product_facet_values
WHERE
product_id IN
(
INNERMOST SUBQUERY
)
AND value_id = 1
give me products that have the value_id = 1 (aka 'Glass') that have more than one record.
OUTERMOST QUERY:
SELECT
v.id
FROM value v
JOIN product_facet_values pfv ON pfv.value_id = v.id
WHERE pfv.product_id IN
(
MIDDLE SUBQUERY
)
AND v.facet_id = 1;
give me the value id for the products that are related to 'Glass' but whos facet_id = 1 (aka series)

Related

Joining multiple columns into one with union, exclude results with same id

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.

How to select data from one table and select count to another table and combine it in MySQL?

In one fruit there can be multiple tickets that can be raised. I need to display the number of tickets raised per fruit. Their key field is the fruit_id.
If I have the following tables:
fruit
id name
1 apple
2 orange
tickets
id fruit_id
1 1
2 1
3 2
4 2
5 2
Then I would use the following SQL syntax to output a table like the one you need:
SELECT fruit.id, fruit.name, COUNT(tickets.id)
FROM tickets
LEFT JOIN fruit ON fruit.id = tickets.fruit_id
GROUP BY fruit.id;
Output:
id name COUNT(tickets.id)
1 apple 2
2 orange 3
SELECT Fruit.Fruit ID,Fruit.Fruit Name, count(Ticket.Ticket Id) as match_rows FROM Fruit LEFT Join Ticket on (Fruit.Fruit ID = Ticket.Fruit ID) group by Fruit.Fruit Id ORDER BY Fruit.Fruit ID DESC

SELECT DISTINCT from a table with conditions and order from another table

I have this table called table_a:
|id |family |gender |stock
1 bag man 20
2 bag woman 23
3 clothing child 4
4 shoe man 0
5 shoe child 3
6 bag unissex 34
7 bag child 0
And another table called table_b:
|id |gender
1 man
2 woman
3 child
4 unissex
How could I code correctly the following query:
SELECT DISTINCT gender FROM table_a WHERE family = 'bag' AND stock > '0' ORDER BY table_b.id ASC
so that the result would be: ['man','woman','unissex']. Independently of what the result would be I would like that the resulting array always would have the same order, 'man' in first place, 'woman' in second and so on, and if 'man' is not a result then 'woman' comes to first and so on...
Using your current structure you need to join the tables:
SELECT table_a.gender
FROM table_a JOIN table_b ON table_a.gender=table_b.gender
WHERE table_a.family = 'bag' AND table_a.stock > 0
GROUP BY table_a.gender
ORDER BY table_b.id
Specify the order using ORDER BY FIELD
SELECT DISTINCT gender FROM table_a
WHERE family = 'bag' AND stock > '0'
ORDER BY FIELD(gender,'man','woman','child', 'unissex')
It will work for MySQL

Count duplicate values in sql server with primary key coloumn

id(PRIMARY KEY) item
--- -------
1 book
2 pen
3 computer
4 book
5 pen
6 mobile
7 book
This is main table. i want result(item count is >1) as
ID ITEM COUNT
---- ------- -------
1 BOOK 3
4 BOOK 3
7 BOOK 3
2 PEN 2
5 PEN 2
I am writing query as:
SELECT ID,ITEM,COUNT(ITEM)
FROM MAIN
GROUP by ID,ITEM
HAVING COUNT(ITEM)>1
ORDER BY ITEM
and getting result as:
ID ITEM COUNT
---- ------- -------
SELECT m.ID, m.ITEM, m1.`COUNT`
FROM MAIN m
JOIN (
SELECT ITEM, COUNT(*) AS `COUNT`
FROM MAIN
GROUP BY ITEM
HAVING `COUNT` > 1
) m1
ON m.ITEM = m1.ITEM
ORDER BY m.ITEM, ID
Your problem was that you had both ID and ITEM in the GROUP BY. Since IDs are unique, you never had any duplicates.
The subquery is used to get the count for each item. Then you join it with the original table so you can show each ID separately.

MySQL SELECT, JOIN, GROUP BY query optimizing

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.