Sql 仅当记录的所有关联记录都符合条件时才返回记录
我们有:Sql 仅当记录的所有关联记录都符合条件时才返回记录,sql,ruby-on-rails,ruby,postgresql,Sql,Ruby On Rails,Ruby,Postgresql,我们有: class Campaign::Item < ActiveRecord::Base belongs_to :campaign has_many :criteria end class Campaign::Item::Criterium < ActiveRecord::Base belongs_to :campaign_item # This model has a +type+ field. end class Campaign::Item::Cri
class Campaign::Item < ActiveRecord::Base
belongs_to :campaign
has_many :criteria
end
class Campaign::Item::Criterium < ActiveRecord::Base
belongs_to :campaign_item
# This model has a +type+ field.
end
class Campaign::Item::Criterium::Gender < Campaign::Item::Criterium
belongs_to :campaign_item
# This model uses the a +gender+ field.
end
class Campaign::Item::Criterium::Age < Campaign::Item::Criterium
belongs_to :campaign_item
# This model uses the +age_min+ and +age_max+ fields.
end
class User
# This model has a +gender+ and +birth_date+ field.
end
这一个不起作用,因为它试图找到一个同时具有Campaign::Item::criterium::Gender
和Campaign::Item::criterium::Age
类型的标准,显然,这种情况不会很快出现
SELECT "campaign_items".*
FROM "campaign_items"
INNER JOIN "campaign_item_criteria"
ON "campaign_item_criteria"."campaign_item_id" = "campaign_items"."id"
WHERE
CASE
WHEN "campaign_item_criteria"."type" = 'Campaign::Item::Criterium::Gender'
AND "campaign_item_criteria"."gender" = 'female'
THEN 1
WHEN "campaign_item_criteria"."type" = 'Campaign::Item::Criterium::Age'
AND "campaign_item_criteria"."age_min" <= 17
AND ("campaign_item_criteria"."age_max" IS NULL OR "campaign_item_criteria"."age_max" >= 17)
THEN 1
ELSE 0
END = 1
选择“活动项目”*
从“活动项目”
内部联接“活动项目标准”
在“活动项目标准”上,“活动项目id”=“活动项目id”
哪里
案例
当“活动项目标准”时,“键入”=“活动::项目::标准::性别”
及"运动项目标准","性别"为"女性"
那么1
当“活动项目标准”时,键入“=“活动::项目::标准::年龄”
和“活动项目标准”。“年龄最小值”=17)
那么1
其他0
结束=1
当一个条件与用户信息匹配时,即使其他条件与用户信息不匹配,ony也会返回Campaign::Item
现在我们的想法都快用完了。我们是否有可能在纯SQL中实现预期的行为?有人有线索吗
提前谢谢 为什么不在where子句中使用
exists
?(因为f***又把这些都打出来了,所以用速记法)
我能够找到一个查询,它完全符合我的意图:
SELECT DISTINCT "campaign_items".*
FROM "campaign_items"
INNER JOIN "campaign_item_criteria"
ON "campaign_item_criteria"."campaign_item_id" = "campaign_items"."id"
WHERE
(NOT EXISTS (SELECT 1
FROM "campaign_item_criteria"
WHERE "campaign_item_criteria"."campaign_item_id" = "campaign_items"."id"
AND "campaign_item_criteria"."type" = 'Campaign::Item::Criterium::Gender')
OR EXISTS (SELECT 1
FROM "campaign_item_criteria"
WHERE "campaign_item_criteria"."campaign_item_id" = "campaign_items"."id"
AND "campaign_item_criteria"."type" = 'Campaign::Item::Criterium::Gender'
AND "campaign_item_criteria"."gender" = 'female'))
AND (NOT EXISTS (SELECT 1
FROM "campaign_item_criteria"
WHERE "campaign_item_criteria"."campaign_item_id" = "campaign_items"."id"
AND "campaign_item_criteria"."type" = 'Campaign::Item::Criterium::Age')
OR EXISTS (SELECT 1
FROM "campaign_item_criteria"
WHERE "campaign_item_criteria"."campaign_item_id" = "campaign_items"."id"
AND "campaign_item_criteria"."type" = 'Campaign::Item::Criterium::Age'
AND "campaign_item_criteria"."age_min" <= 17
AND ("campaign_item_criteria"."age_max" IS NULL
OR "campaign_item_criteria"."age_max" >= 17)))
选择不同的“活动项目”*
从“活动项目”
内部联接“活动项目标准”
在“活动项目标准”上,“活动项目id”=“活动项目id”
哪里
(不存在(选择1
来自“活动项目标准”
其中“活动项目标准”。“活动项目id”=“活动项目”。“id”
和“活动项目标准”。“类型”=“活动::项目::标准::性别”)
或存在(选择1
来自“活动项目标准”
其中“活动项目标准”。“活动项目id”=“活动项目”。“id”
和“活动项目标准”。“类型”=“活动::项目::标准::性别”
及"运动项目标准","性别"为"女性")
和(不存在)(选择1
来自“活动项目标准”
其中“活动项目标准”。“活动项目id”=“活动项目”。“id”
和“活动项目标准”。“类型”=“活动::项目::标准::年龄”
或存在(选择1
来自“活动项目标准”
其中“活动项目标准”。“活动项目id”=“活动项目”。“id”
和“活动项目标准”。“类型”=“活动::项目::标准::年龄”
及"运动(项目)准则","年龄(分钟)为17岁)
这是对2个条件的查询,它有4个子查询。我们已经知道,我们最终会有10个不同的标准。最后一个请求总共有20个子查询。目前(有2个标准),数据库中有2个
Campaign::Item
需要约2.5ms,数据库中有2000个Campaign::Item
需要约16ms。它不像我们想象的那样是指数型的,所以我们会说它“足够好”
我们暂时保留这个。有人有什么要添加或改进的路径吗?您对使用复杂ON子句的每个条件的内部联接有什么想法?
存在的地方
将在得到肯定结果后立即停止,联接
比较整体table@JohnHC您的解决方案在提供了所有现有条件的项目上运行良好。但是,如果我删除Age
标准,用户将不再匹配。不存在的标准暗指“匹配”标准。顺便说一句,我不知道存在表达式,谢谢!
SELECT ci.*
FROM campaign_items ci
WHERE exists (select 1
from campaign_item_criteria cic
where cic.campaign_item_id = ci.id
and cic.type = '::gender'
and (cic.gender = 'female' or cic.gender is null)
)
and exists (select 1
from campaign_item_criteria cic
where cic.campaign_item_id = ci.id
and cic.type = '::age'
and (cic.age = '35' or cic.age is null)
)
SELECT DISTINCT "campaign_items".*
FROM "campaign_items"
INNER JOIN "campaign_item_criteria"
ON "campaign_item_criteria"."campaign_item_id" = "campaign_items"."id"
WHERE
(NOT EXISTS (SELECT 1
FROM "campaign_item_criteria"
WHERE "campaign_item_criteria"."campaign_item_id" = "campaign_items"."id"
AND "campaign_item_criteria"."type" = 'Campaign::Item::Criterium::Gender')
OR EXISTS (SELECT 1
FROM "campaign_item_criteria"
WHERE "campaign_item_criteria"."campaign_item_id" = "campaign_items"."id"
AND "campaign_item_criteria"."type" = 'Campaign::Item::Criterium::Gender'
AND "campaign_item_criteria"."gender" = 'female'))
AND (NOT EXISTS (SELECT 1
FROM "campaign_item_criteria"
WHERE "campaign_item_criteria"."campaign_item_id" = "campaign_items"."id"
AND "campaign_item_criteria"."type" = 'Campaign::Item::Criterium::Age')
OR EXISTS (SELECT 1
FROM "campaign_item_criteria"
WHERE "campaign_item_criteria"."campaign_item_id" = "campaign_items"."id"
AND "campaign_item_criteria"."type" = 'Campaign::Item::Criterium::Age'
AND "campaign_item_criteria"."age_min" <= 17
AND ("campaign_item_criteria"."age_max" IS NULL
OR "campaign_item_criteria"."age_max" >= 17)))