我有一堆表,我正在使用一个唯一的商品ID加入。大多数where子句条件将以编程方式从用户求和表单(搜索框)构建,并且通常会针对同一个表测试多个条件,在本例中为项目标记。
我对SQL的经验很少,但我理解基础知识。我想找到标记有特定类型标记的活动(status = 1)项的ID,其值为“cats”和“kittens”。标签存储为(id,product_id,tag_type_id,value),id是唯一需要唯一值的列。我的第一次尝试是;
select
distinct p2c.product_id
from '.TABLE_PRODUCT_TO_CATEGORY.' p2c
inner join '.TABLE_PRODUCT.' p on p2c.product_id = p.id
inner join '.TABLE_PRODUCT_TAG.' pt on p.id = pt.product_id
inner join '.TABLE_TAG_TYPE.' tt on pt.tag_type_id = tt.id
where
tt.id = '.PRODUCT_TAG_TYPE_FREE_TAG.'
and p.status = 1
and lower(pt.value) = "cats"
and lower(pt.value) = "kittens"
但是没有回复。我意识到最终的AND条件是问题,所以尝试使用自连接;
select
distinct p2c.product_id
from '.TABLE_PRODUCT_TO_CATEGORY.' p2c
inner join '.TABLE_PRODUCT.' p on p2c.product_id = p.id
inner join '.TABLE_PRODUCT_TAG.' pt on p.id = pt.product_id
inner join '.TABLE_PRODUCT_TAG.' pt2 on p.id = pt2.product_id
inner join '.TABLE_TAG_TYPE.' tt on pt.tag_type_id = tt.id
where
tt.id = '.PRODUCT_TAG_TYPE_FREE_TAG.'
and p.status = 1
and lower(pt.value) = "cats"
and lower(pt2.value) = "kittens"
现在一切都按预期工作,结果集正确。那么我想知道什么?要重新迭代,我所追求的结果是活动(状态= 1)项目的ID,这些项目已使用特定类型的标记进行标记,值为“cats”和“kittens”......
答案 0 :(得分:4)
这不会在你的第一个查询中起作用吗?
而不是
and lower(pt.value) = "cats"
and lower(pt.value) = "kittens"
这样做
and lower(pt.value) in ("cats","kittens")
答案 1 :(得分:3)
select
distinct p2c.product_id
from '.TABLE_PRODUCT_TO_CATEGORY.' p2c
inner join '.TABLE_PRODUCT.' p on p2c.product_id = p.id
inner join '.TABLE_PRODUCT_TAG.' pt on p.id = pt.product_id
inner join '.TABLE_TAG_TYPE.' tt on pt.tag_type_id = tt.id
where
tt.id = '.PRODUCT_TAG_TYPE_FREE_TAG.'
and p.status = 1
and (lower(pt.value) = "cats" or lower(pt.value) = "kittens")
答案 2 :(得分:0)
初始查询的问题是:
and lower(pt.value) = "cats"
and lower(pt.value) = "kittens"
不存在值为“cats”和“kittens”的标记,因此不会返回任何记录。使用IN子句作为SQLMenace建议将是解决方案 - 这就是你说的,“给我回复任何被标记为'cats'或'kittens'的活动项目。”
但是如果你想要任何有BOTH标签的活动项目 - 那么你需要做类似你的第二个查询。你的问题并不完全清楚,那就是你所追求的。
类似于问题#3:
“猫”和(“小猫”或“狗”)不是“鹦鹉”。
你会想要pt1,pt2和(在子查询中)pt3,以及类似的东西:
and lower(pt1.value) = "cats"
and lower(pt2.value) in ("kittens", "dogs")
and not exists (select * from '.TABLE_PRODUCT_TAG.' pt3 where pt3.product_id = p.id and lower(pt3.value) = "parrots")
广泛的一般情况可能会变得非常混乱......
答案 3 :(得分:0)
您的回答是“是的,这是一种可扩展的技术”。至于增加复杂性,我认为在你遇到有效查询问题之前,你会超出用户理解他们正在做什么的能力。
答案 4 :(得分:0)
您正在构建另一个实体 - 属性 - 值数据模型。由于您询问了可伸缩性,这里有一个警告:EAV模型通常不会扩展,也不会在RDBMS之上执行。最终,这种“灵活”的数据模型最终会破坏优化器,您将扫描数百万行来获取您的少数狗和小猫。维基百科有一个topic covering this model and some of the downsides。不知道你的目标数据库是什么,例如SQL Server CAT published a white paper在EAV模型中有常见问题。
答案 5 :(得分:0)
好的,让我重新陈述这个问题,以确保我理解:
您正在尝试显示所有具有两种不同特定标签的产品(“猫”和“小猫”),但标签存储在1对多的表格中。
双连接确实有效,但这是另一种选择:
SELECT ...
FROM P
WHERE p.status = 1
AND p.ProductID IN (SELECT Product_ID FROM tags WHERE value = "cats")
AND p.ProductID IN (SELECT Product_ID FROM tags WHERE value = "kittens")
根据用户选择的选项添加其他AND语句。
SQL优化器实际上应该以对待连接的方式对待它,所以我认为性能不会比你的版本扩展任何更差。但是,值得测试您的数据集,以确保。
答案 6 :(得分:0)
AIR CODE
select
distinct p2c.product_id
from '.TABLE_PRODUCT_TO_CATEGORY.' p2c
inner join '.TABLE_PRODUCT.' p on p2c.product_id = p.id
where
and p.status = 1
and 2 = (
SELECT COUNT(1)
FROM '.TABLE_PRODUCT_TAG.' pt
INNER JOIN '.TABLE_TAG_TYPE.' tt ON pt.tag_type_id = tt.id
WHERE tt.id = '.PRODUCT_TAG_TYPE_FREE_TAG.'
AND pt.product_id = p.id /* edit */
lower(pt.value) IN( "cats", "kittens" )
)