Проблема с объединением 4 таблиц SQL

#mysql #sql #join

#mysql #sql #Присоединиться

Вопрос:

У меня есть четыре таблицы, подобные следующим :

 Cars:
car_id | make_id
1      | 1
2      | 3

Cars Makes 
make_id  | make_name
1        | BMW
2        | Ferrari
3        | Mercedes 


Car Properties 
car_id  | property_id | property_value
1       | 1           | Automatic
1       | 2           | 1000
1       | 3           | Diesel
2       | 1           | Manual
2       | 2           | 15000
2       | 3           | Gasoline

Properties
property_id | property_name
1           | Transmission
2           | Mileage
3           | Fuel
  

Как вы можете видеть, у каждого car есть make_id из таблицы «Makes» .

И там есть отдельная таблица, содержащая все основные свойства автомобилей. Затем есть таблица «Свойства автомобиля», которая содержит car_id, property_id, property_value

Теперь я хочу сделать следующий запрос: получить автомобили BMW с автоматической коробкой передач и пробегом 1000 на дизельном топливе. давайте предположим, что форма может предоставить следующее: make_id = 1 (BMW) свойства = Автоматический, 1000, дизельный

P.S: Все будет в порядке, если я просто получу результат car_id

Комментарии:

1. Предполагая, что значения property_value для разных property_id не совпадают (например, передача не является «Бензиновой»), тогда вам не нужна таблица свойств для этого запроса. (P.S. Я не понизил голос; это интересная проблема.)

Ответ №1:

Предполагая, что запрос должен удовлетворять всем трем свойствам:

 SELECT c.car_id
FROM
    Cars c INNER JOIN (
        SELECT car_id, COUNT(*) AS prop_count
        FROM
            CarProperties
        WHERE
            (property_id = 1 AND property_value = 'Automatic')
            OR (property_id = 2 AND property_value = '1000')
            OR (property_id = 3 AND property_value = 'Diesel')
        GROUP BY car_id
    ) AS cp ON c.car_id = cp.car_id AND cp.prop_count = 3
WHERE
    c.make_id = 1;
  

Затем это пришло мне в голову:

 SELECT c.car_id
FROM
    Cars c INNER JOIN (
        SELECT car_id FROM CarProperties
        WHERE property_id = 1 AND property_value = 'Automatic'
    ) AS t ON c.car_id = t.car_id INNER JOIN (
        SELECT car_id FROM CarProperties
        WHERE property_id = 2 AND property_value = '1000'
    ) AS m ON c.car_id = m.car_id INNER JOIN (
        SELECT car_id FROM CarProperties
        WHERE property_id = 3 AND property_value = 'Diesel'
    ) AS f ON c.car_id = f.car_id
WHERE
   c.make_id = 1;
  

Комментарии:

1. Это все еще намного сложнее, чем должно быть.

2. Это сложнее, но я выбрал его, потому что это не приведет к перекрытию свойств…

Ответ №2:

Не на 100% зависит от синтаксиса mysql (извините, что слишком много живу в TSQL), но это идея взаимосвязи для использования.

 FROM Car 
JOIN CarProperties Trans
    ON Car.car_id = Trans.CarID AND Trans.property_id = 1
JOIN CarProperties Mileage 
    ON Car.car_id = Mileage.CarID AND Mileage.property_id = 2
JOIN CarProperties Fuel 
    ON Car.car_id = Fuel.CarID AND Fuel.property_id = 3
  

Ваш выбор может основываться на пробеге, топливе или переходе, как и ваше предложение where

Ответ №3:

Поскольку входные данные содержат только такие значения, как «Automatic, 1000, Diesel», и ни одного значения, подобного «Трансмиссия, пробег, топливо», вам придется игнорировать таблицу свойств и молиться, чтобы ваши типы свойств никогда не включали перекрывающиеся ключи (или более одного числового типа). Кроме того, поскольку входные данные уже содержат make_id напрямую, мы также можем не использовать Cars Makes таблицу.

Другой трюк здесь заключается в том, что вы можете присоединиться к одной и той же таблице более одного раза.

 SELECT c.car_id 
FROM cars c
INNER JOIN `Car Properties` cp1 
    ON cp1.car_id = c.car_id AND cp1.property_value = 'Automatic'
INNER JOIN `Car Properties` cp2 
    ON cp2.car_id = c.car_id AND cp2.property_value = 'Diesel'
INNER JOIN `Car Properties` cp3 
    ON cp3.car_id = c.car_id  AND cp3.property_value = '1000'
  

Ответ №4:

вы можете сначала объединить свойства Car и Properties, присвоить им псевдоним и получить массив car_id, затем выполнить поиск Cars объединение Cars производится «В» (car_id_array).

Ответ №5:

Возможно, это могло бы сработать:

 SELECT car_id
FROM Cars LEFT JOIN CarMakes USING (make_id)
     JOIN (SELECT car_id
           FROM CarProperties JOIN Properties USING (property_id)
           WHERE property_name='Transmission' AND property_value='Automatic') a
     JOIN (SELECT car_id
           FROM CarProperties JOIN Properties USING (property_id)
           WHERE property_name='Mileage' AND property_value='1000') b
     JOIN (SELECT car_id
           FROM CarProperties JOIN Properties USING (property_id)
           WHERE property_name='Fuel' AND property_value='Diesel') c
WHERE make_name = 'BMW'
  

Ответ №6:

 select cars.car_id
   from
      cars 
         join `car properties` cp
            on cars.car_id = cp.car_id
            join properties p
               on cp.property_id = p.property_id
   where
         cars.make_id = 1
      and (   ( p.property_name = "Transmission" and cp.property_Value = "Automatic" )
           OR ( p.property_name = "Mileage" and cp.property_Value = "1000" )
           OR ( p.property_name = "Fuel" and cp.property_Value = "Diesel" )
          )
   group by
      cars.car_id
   having
      count(*) = 3