【问题标题】:Filter from 2 tables and join 2 other tables从 2 个表中过滤并加入 2 个其他表
【发布时间】:2021-06-21 06:21:14
【问题描述】:

我有一个具有以下表格布局的 Postgres 数据库:

假设内容如下:

cars                                            properties
| id  |  name    |  desc     |                  |  id  |  name    |  type  |
------------------------------                  ----------------------------
|  1  | 'Toyota' | 'Japanese'|                  |  1   | 'length' |  'dim' |
------------------------------                  ----------------------------
|  2  | 'Ford'   | 'American'|                  |  2   | 'vin'    |  'reg' |
------------------------------                  ----------------------------

float_properties                                string_properties
| car_id | property_id |  min  |  max  |        | car_id | property_id |  value  |
----------------------------------------        ----------------------------------
|   1    |      1      | 10.5  |  12.5 |        |    1   |      2      |  'abc'  |
----------------------------------------        ----------------------------------
|   2    |      1      |  9.5  |  14   |        |    2   |      2      |  'def'  |
----------------------------------------        ----------------------------------

如何编写查询以从浮点和字符串属性表中获取给定值的汽车名称:

例如:给出'length' min > 10, max

我试过了

SELECT
      C.name,
      C.description,
      P.name,
      P.type
FROM 
      properties P
INNER JOIN float_properties FP 
    ON FP.property_id = P.id
INNER JOIN string_properties SP 
    ON SP.property_id = P.id
INNER JOIN cars C 
    ON C.id = FP.car_id AND C.id = SP.car_id
WHERE
    P.name = 'length' AND FP.min > 10 AND FP.max < 13
    AND
    P.name = 'vin' AND SP.value = 'abc';

但这会返回零行。这里的正确查询是什么?

编辑:阅读@ginkul 的评论后,我想到了 2 个用例——我最初的问题是针对下面的用例 1:

  1. 从两个表中找出必须满足条件的汽车:例如:

    条件 1:具有名为“length”的属性的汽车及其限制 min > 10 AND FP.max

    条件 2:汽车具有名为“vin”且值为“abc”的属性

  2. 找到只需要满足其中一个条件的汽车;换句话说,所有具有 10

【问题讨论】:

  • 现在你的条件是矛盾的,P.name = 'length' ... AND P.name = 'vin'。我想他们之间应该是OR,是错字吗?
  • @ginkul 现在想想,有2个用例,我会相应地更新问题。

标签: sql postgresql


【解决方案1】:

从内向外开始 - 首先找到房产的 ID,然后搜索该房产所需的值,然后找到具有这些值的汽车:

SELECT name, description
FROM cars
WHERE id IN
  (SELECT car_id 
  FROM string_properties AS sp
  WHERE car_id = 
    (SELECT car_id 
    FROM float_properties AS fp 
    WHERE property_id = 
      (SELECT id AS propID 
        FROM properties AS p1
        WHERE p1.name = 'length'
      )
      AND fp.min > 10
      AND fp.max < 13
    )
    AND property_id = (SELECT id AS propID FROM properties AS p2 WHERE p2.name = 'vin')
    AND sp.value = 'abc'
  )
ORDER BY name, description

对于案例 2,您将稍微修改相同的查询:

SELECT name, description
FROM cars
WHERE id IN
  (SELECT car_id 
  FROM string_properties AS sp
  WHERE property_id = 
    (SELECT id AS propID 
      FROM properties AS p2 
      WHERE p2.name = 'vin'
    )
    AND sp.value = 'abc'
  UNION ALL
  SELECT car_id 
  FROM float_properties AS fp 
  WHERE property_id = 
    (SELECT id AS propID 
      FROM properties AS p1
      WHERE p1.name = 'length'
    )
    AND fp.min > 10
    AND fp.max < 13
  )
)
ORDER BY name, description

【讨论】:

  • 阅读评论后,我用 2 个用例更新了这个问题。这个答案满足第一个用例对吗?对于第二个用例,我可以为单独的汽车 ID 做一个联合,并为这些汽车 ID 做一个WHERE id IN
  • @Dula 是的,你会先做一个 UNION,然后再做 IN()。
【解决方案2】:

基本上,你需要JOINproperties 两次,一次用于字符串表,一次用于浮点表:

SELECT C.name, C.description, PF.name, PF.type, PS.name, PS.type
FROM Cars C JOIN
     float_properties FP 
     ON C.id = FP.car_id JOIN
     properties PF
     ON FP.property_id = PF.id JOIN
     string_properties SP 
     ON c.id = SP.car_id JOIN
     properties PS
     ON SP.property_id = PS.id 
WHERE (PF.name = 'length' AND FP.min > 10 AND FP.max < 13) AND
      (PS.name = 'vin' AND SP.value = 'abc');

【讨论】:

  • 我认为第 8 行 ON SP.property_id = P.id JOIN 有错误。这里P.id 应该是PF.id 还是这条线应该是ON SP.car_id = C.id JOIN
【解决方案3】:

您不能从两个详细信息表进行内部联接。试试这个。

SELECT
      C.name,
      C.description,
      coalesce(Pfp.name, Psp.name) pname,
      coalesce(Pfp.type, psp.type) ptype
FROM cars C 
LEFT JOIN float_properties FP 
    ON FP.car_id = c.id
LEFT JOIN properties Pfp
    ON pfp.id = fp.property_id
LEFT JOIN string_properties SP 
    ON SP.car_id = c.id
LEFT JOIN properties Psp
    ON psp.id = sp.property_id
WHERE
    Pfp.name = 'length' AND FP.min > 10 AND FP.max < 13
    OR
    Psp.name = 'vin' AND SP.value = 'abc';

上述查询未经测试。

考虑到在您当前的设计中可能会返回多行。您不能同时要求一个属性描述和两个属性的过滤器。如果您愿意,您可以使用 string_agg() 之类的东西来聚合所有属性描述,因此每辆车有一个结果行。

【讨论】:

    猜你喜欢
    • 2013-10-03
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 2012-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多