我相当擅长 PHP (OOP & flat)。在过去一年左右的时间里,我的任务是维护 Ruby 代码库;我还在学习的一项技能。我不太清楚如何使用续集因此采用正确的过滤链AND,以及OR语句可以适当遏制。
这是我想要的 MySQL 查询结构:
SELECT * FROM `some_objects`
WHERE (
(
((`datebegin` >= 1950) AND (`datebegin` <= 1959)) OR ((`dateend` >= 1950) AND (`dateend` <= 1959))
)
OR
((`datebegin` <= 1950) AND (`dateend` >= 1959))
AND
(NOT `datebegin` = 0) AND (NOT `dateend` = 0)
)
;
Run Code Online (Sandbox Code Playgroud)
这是我正在使用的 Sequel 代码片段:
some_objects = where{((datebegin >= start_year) & (datebegin <= end_year)) | ((dateend >= start_year) & (dateend <= end_year))}.
or{(datebegin <= start_year) & (dateend >= end_year)}.
where(~:datebegin => 0, ~:dateend => 0)
Run Code Online (Sandbox Code Playgroud)
这就是我实际得到的:
SELECT * FROM `some_objects`
WHERE (
(
((`datebegin` >= 1950) AND (`datebegin` <= 1959)) OR ((`dateend` >= 1950) AND (`dateend` <= 1959))
OR
((`datebegin` <= 1950) AND (`dateend` >= 1959))
)
AND
(NOT `datebegin` = 0) AND (NOT `dateend` = 0)
)
;
Run Code Online (Sandbox Code Playgroud)
我还尝试了相同 Sequel 代码的不同变体,例如:
some_objects = where(:datebegin => start_year..end_year).
or(:dateend => start_year..end_year).
or{|o|(o.datebegin <= start_year) & (o.dateend >= end_year)}.
where(~:datebegin => 0, ~:dateend => 0)
Run Code Online (Sandbox Code Playgroud)
和这个:
some_objects = where(:datebegin => start_year..end_year).
or(:dateend => start_year..end_year).
or{(datebegin <= start_year) & (dateend >= end_year)}.
where(~:datebegin => 0, ~:dateend => 0)
Run Code Online (Sandbox Code Playgroud)
但我最终还是得到了第一个 SQL 结构,其中整个块基本上是((AND OR AND OR)):
(
((`datebegin` >= 1950) AND (`datebegin` <= 1959)) OR ((`dateend` >= 1950) AND (`dateend` <= 1959))
OR
((`datebegin` <= 1950) AND (`dateend` >= 1959))
)
Run Code Online (Sandbox Code Playgroud)
当我想要((AND OR AND) OR):
(
((`datebegin` >= 1950) AND (`datebegin` <= 1959)) OR ((`dateend` >= 1950) AND (`dateend` <= 1959))
)
OR
((`datebegin` <= 1950) AND (`dateend` >= 1959))
Run Code Online (Sandbox Code Playgroud)
您初始查询的问题在于您依赖于 OR/AND 优先规则而不是使用显式括号。您的初始查询可以表示为:
SELECT * FROM `some_objects`
WHERE (
((`datebegin` >= 1950) AND (`datebegin` <= 1959))
OR
((`dateend` >= 1950) AND (`dateend` <= 1959))
OR
((`datebegin` <= 1950) AND (`dateend` >= 1959) AND (NOT `datebegin` = 0) AND (NOT `dateend` = 0))
)
Run Code Online (Sandbox Code Playgroud)
您可以在 Sequel 中将其表示为:
DB[:some_objects].where{((datebegin >= start_year) & (datebegin <= end_year)) | ((dateend >= start_year) & (dateend <= end_year))}.
or{((datebegin <= start_year) & (dateend >= end_year)) & Sequel.negate(:datebegin => 0)}
Run Code Online (Sandbox Code Playgroud)
这会产生以下 SQL:
SELECT * FROM `some_objects` WHERE (
((`datebegin` >= 1950) AND (`datebegin` <= 1959))
OR
((`dateend` >= 1950) AND (`dateend` <= 1959))
OR
((`datebegin` <= 1950) AND (`dateend` >= 1959) AND (`datebegin` != 0))
)
Run Code Online (Sandbox Code Playgroud)
这应该与您使用的 SQL 执行相同的操作,但它更具可读性(例如,datebegin != 0而不是NOT datebegin = 0)。请注意,您不需要NOT dateend = 0过滤器,因为它是dateend >= 1959过滤器的一个子集。