【问题标题】:4 Tables SQL Join Problem4 表 SQL 连接问题
【发布时间】:2011-06-14 01:55:52
【问题描述】:

我有四个如下表:

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

如您所见,每辆车都有一个来自 "Makes" 表的 make_id。

还有一个单独的表格包含汽车的所有主要属性。 然后是“汽车属性”表,其中包含 car_id、property_id、property_value

现在我想进行以下查询: 买宝马自动变速箱,柴油里程1000。 假设表单可以提供以下内容: make_id = 1 (宝马) 属性=自动,1000,柴油

P.S: 如果我只得到结果 car_id 就可以了

【问题讨论】:

  • 假设不同property_id 的property_value 值之间没有重叠(例如,没有Transmission 是“Gasoline”),那么您不需要该查询的Properties 表。 (P.S. 我没有投反对票;这是一个有趣的问题。)

标签: mysql sql join


【解决方案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;

【讨论】:

  • 这仍然比它需要的复杂得多。
  • 比较复杂,但我选择了它,因为它不会导致属性之间的重叠......
【解决方案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”之类的值,而没有“Transmission,Mileage,Fuel”之类的值,您将不得不忽略属性表并祈祷您的属性类型永远不会包含重叠键(或超过一种数字类型)。此外,由于输入已经直接具有 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 和 Properties,给它一个别名并获取 car_id 数组,然后搜索 Cars join Cars Makes "IN" (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 
          

          【讨论】:

            猜你喜欢
            • 2022-06-16
            • 2017-07-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-03-28
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多