我为标题道歉,但我不知道如何用几句话更好地解释我的问题。 我有一个包含汽车ID,属性ID和属性值的表。 这样的事情:
CarID | propertyID | propertyValue
1 1 black
1 2 diesel
1 3 automatic gear
1 4 80 kW
2 1 blue
2 2 gasoline
2 3 manual gear
2 4 120 kw
3 1 blue
3 2 gasoline
3 3 manual gear
3 4 90 kw
我无法获得有效查询以获得具有属性值的汽车,例如黑色和自动装备和柴油。 我尝试过交叉和联合但没有结果。
select distinct t.* from table t where value ilike 'blue' intersect select t.* from table t where value ilike 'manual gear' union select t.* from table t where value ilike '90 kw'
请帮忙。 感谢。
编辑:我必须再次道歉,但我忘了添加更多信息。我添加的情况是所有属性都相同,除了电源,我想得到90千瓦的汽车。 数据库是PostgreSQL。提前谢谢。
答案 0 :(得分:5)
实现所需内容的一种规范方法是按CarID
聚合,仅保留具有所需属性的记录,然后检查以确保不同的属性数与所需列表中的所有属性匹配。
WITH cte AS (
SELECT CarID
FROM table
WHERE propertyValue IN ('black', 'automatic gear', 'diesel')
GROUP BY CarID
HAVING COUNT(DISTINCT propertyValue) = 3
)
SELECT * FROM cte
如果您想要返回所有匹配的汽车的记录及其所有列,那么您可以按如下方式使用CTE:
SELECT *
FROM table t1
INNER JOIN cte t2
ON t1.CarID = t2.CarID
在这里演示:
答案 1 :(得分:2)
您遇到困难的最大原因是您的桌面设置不佳并且没有充分利用关系数据库的全部潜力。而不是具有字段的表
CarID | propertyID | propertyValue
你应该
CarID | Color | FuelType | TransmissionType
然后您的查询更加简单:
SELECT * FROM tablename
WHERE Color LIKE 'black'
AND FuelType LIKE 'diesel'
AND TransmissionType LIKE 'auto'
我知道这是一个不同于您现有设置的答案,但如果您按照建议修改您的桌子,您将使您的生活变得相当容易。
修改强>
根据您现有的表格结构,我想出了一种不同的方法。使用WITH语句通过选择主键将表更改为更好的表,然后使用子查询为每个单独的属性值加入同一个表。然后,从中选择:
WITH newtable AS (
SELECT ot.CarID, p1.propertyValue AS CarColor, p2.propertyValue AS FuelType,
p3.propertyValue AS TransType, p4.propertyValue AS EnginePower
FROM oldtable ot
LEFT JOIN (SELECT CarID, propertyValue FROM oldtable WHERE propertyID = 1) p1
ON p1.CarID = ot.CarID
LEFT JOIN (SELECT CarID, propertyValue FROM oldtable WHERE propertyID = 2) p2
ON p2.CarID = ot.CarID
LEFT JOIN (SELECT CarID, propertyValue FROM oldtable WHERE propertyID = 3) p3
ON p3.CarID = ot.CarID
LEFT JOIN (SELECT CarID, propertyValue FROM oldtable WHERE propertyID = 4) p4
ON p4.CarID = ot.CarID)
SELECT * FROM newtable
WHERE CarColor LIKE 'blue' AND TransType LIKE 'manual' AND EnginePower LIKE '90 KW'
ORDER BY CarID
答案 2 :(得分:1)
单程
select * from (
select your_table.*, count(*) over(partition by CarID) property_cnt
from your_table where propertyValue in ('black', 'diesel', 'automatic gear' )
) t where property_cnt = 3
答案 3 :(得分:1)
为了完整起见,您确实可以使用intersect
查询获取结果,如下所示:
select t.CarID
from t
where propertyID = 1 and propertyValue = 'blue'
intersect
select t.CarID
from t
where propertyID = 3 and propertyValue = 'manual gear'
intersect
select t.CarID
from t
where propertyID = 4 and propertyValue = '90 kW'
您自己的查询的主要问题是您的SQL读取from table t
而不是from t
。此外,您引入union
而不是继续使用intersect
。
最后,我在我的查询中添加了propertyID
,如果您不明白原因,请阅读Tim回答下的评论。
话虽如此,我仍然倾向于Tim的问题设置答案,并且几乎完全支持SandPiper提出的设计异议。
答案 4 :(得分:0)
有效查询以获得具有属性值的汽车,例如黑色和自动齿轮和柴油
如果我们想要颜色=黑色的汽车,则传输=自动装备&燃料类型=柴油,其中,从样本数据推断颜色,传输&燃料类型具有属性ID 1,2和&分别为3个
然后我们可以在汽车上使用json聚合'属性和检查我们的过滤条件是汽车属性的子集。
SELECT
"CarID"
, JSONB_OBJECT_AGG("propertyID", "propertyValue") properties
FROM cars
GROUP BY 1
HAVING JSONB_OBJECT_AGG("propertyID", "propertyValue") @> '{"1":"black"}'::JSONB
这在posgresql 9.4+中有效。它返回与密钥和&匹配的CarID
。 HAVING
子句中指定的值过滤器。如果您只需要properties
CarID
列
我们也可以使用Array Aggregation&这样的HAVING
比较。阵列已经在postgres很长一段时间了。包含运算符@>
也已经在postgres中使用了很长时间。这适用于所有最近的postgresql版本。
SELECT
"CarID"
, ARRAY_AGG(("propertyID"::INT, "propertyValue"::TEXT)) properties
FROM cars
GROUP BY 1
HAVING ARRAY_AGG(("propertyID", "propertyValue")) @> ARRAY[(1::INT,'black'::TEXT),(2,'diesel'::TEXT),(3,'automatic gear'::TEXT)];