简体   繁体   中英

Mysql many-to-many realtionship multiple condition

I have three tables, for example:

watch table

id(int)  name(varchar)  ref(int)
1        tissot         1234567
2        addidas        7654321
3        nike           8976543

property table

id(int)  name(varchar)
1        water_resistant
2        material_body
3        material_bracelet
4        watch_type

property_material table

watch_id  property_id   value
1              1          200
1              2         steel
1              3         leather
1              4         quartz
2              1          50
2              2         plastic
2              3         leather
2              4         quartz
3              1         100
3              2         steel
3              3         rubber
3              4        mechanical

I want get all watches which have properties for example:

  • water_resistant >= 100
  • material_body = steel or plastic
  • material_bracelet = leather or rubber
  • watch_type = quartz.

Help me please create query. Properties can be about 100. In ideal i want get result:

watch_id name    ref   water_res mat_body mat_bracelet watch_type
1        tissot  1234   200       steel    leather      quartz

I'm try:

select 
 w.*, pm.value,pm.property_id 
from 
 watch w 
join 
  property_material pm 
 on w.id = pm.watch_id 
where 
  pm.pid in (1,2,3) 
and 
 pm.value in ('100','Steel','Leather');

But this query return all records, when value is Steel or Leather, bur I need where material_body is Steel and material_bracelet is Leather, for example.

UPDATE : What you are think about this query?

select 
  name, ref 
from
  watch w
join
(SELECT w.id
  FROM watch w
  JOIN property_material pm on w.id = pm.watch_id
  WHERE (pm.property_id = 1 AND pm.value > 100)
   OR (pm.property_id = 2 AND pm.value IN ('steel','plastic'))
   OR (pm.property_id = 3 AND pm.value IN ('leather','rubber'))
   OR (pm.property_id = 4 AND pm.value = 'quartz')
  Group by w.id
  Having count(*) = 4) as t1
 on t1.id = w.id;

LAST UPDATE :

select 
  w.name, 
  max(if(pm.property_id='1',pm.value,'')) water_resistant,
  max(if(pm.property_id='2',pm.value,'')) material_body,
  max(if(pm.property_id='3',pm.value,'')) material_bracelet,
  max(if(pm.property_id='4',pm.value,'')) watch_type
from
  watch w
join
(
    SELECT w.id
  FROM watch w
       JOIN property_material pm on w.id = pm.watch_id
  WHERE (pm.property_id = 1 AND pm.value > 100)
      OR (pm.property_id = 2 AND pm.value IN ('steel','plastic'))
      OR (pm.property_id = 3 AND pm.value IN ('leather','rubber'))
      OR (pm.property_id = 4 AND pm.value = 'quartz')
  Group by w.id
  Having count(*) = 4
  ) as t1 on t1.id = w.id
 join property_material pm on w.id = pm.watch_id
GROUP BY w.id

Here you have several queries that fill your needs. But as you see, they are all independent. That is why I ask in the comments what exactly you need.

For more tests use this SQL Fiddle sample code using your provided sample data.

EDIT Added new query to have all conditions and all results on one set. Check SQL Fiddle sample code here .

SELECT w.name,ref,property_id,value 
  FROM watch w
  JOIN property p on w.id = p.id
  JOIN property_material pm on p.id = pm.property_id 
 WHERE (p.id = 1 AND pm.value > 100)
    OR (p.id = 2 AND pm.value IN ('steel','plastic'))
    OR (p.id = 3 AND pm.value IN ('leather','rubber'))
    OR (p.id = 4 AND pm.value = 'quartz');

Independent queries:

SELECT w.name Watch_name, p.name Property_name, pm.value Property_value
  FROM watch w
  JOIN property_material pm ON w.id = pm.watch_id
  JOIN property p ON p.id = pm.property_id
 WHERE p.id = 1
   AND pm.value > 100;

WATCH_NAME  PROPERTY_NAME     PROPERTY_VALUE
tissot      water_resistant   200

Another one:

SELECT w.name Watch_name, p.name Property_name, pm.value Property_value
  FROM watch w
  JOIN property_material pm ON w.id = pm.watch_id
  JOIN property p ON p.id = pm.property_id
 WHERE p.id = 2
   AND pm.value IN ('steel','plastic');

WATCH_NAME   PROPERTY_NAME   PROPERTY_VALUE
tissot      material_body      steel
addidas     material_body      plastic
nike        material_body      steel

Another one:

SELECT w.name Watch_name, p.name Property_name, pm.value Property_value
  FROM watch w
  JOIN property_material pm ON w.id = pm.watch_id
  JOIN property p ON p.id = pm.property_id
 WHERE p.id = 3
   AND pm.value IN ('leather','rubber');

WATCH_NAME   PROPERTY_NAME      PROPERTY_VALUE
tissot      material_bracelet      leather
addidas     material_bracelet      leather
nike        material_bracelet      rubber

Another one:

SELECT w.name Watch_name, p.name Property_name, pm.value Property_value
  FROM watch w
  JOIN property_material pm ON w.id = pm.watch_id
  JOIN property p ON p.id = pm.property_id
 WHERE p.id = 4
   AND pm.value = 'quartz';

WATCH_NAME   PROPERTY_NAME   PROPERTY_VALUE
tissot         watch_type       quartz
addidas        watch_type       quartz

The only possibility i know is to make a join to the properties table for each property, like so (i modified your given example):

select w.*, pm1.value,pm1.pid ,pm2.value,pm2.pid
    from watch w 
        join property_material pm1 on w.id = pm1.watch_id AND pm1.pid = 1 and pm1.value = '100'
        join property_material pm2 on w.id = pm2.watch_id AND pm2.pid = 2 and pm2.value IN ('Steel','Lather');
select watch_table.id,watch_table.name,ref,property_id,value from watch_table join        property_table on watch_table.id=property_table.id
  join property_material on property_table.id=property_material.property_id 
 where WHERE property.id = 3 AND property_material.value IN ('leather','rubber');

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM