我有一个基于不同id获取结果的查询,我的查询看起来是这样的:我缩短了查询,但是,还有两个where-in条件。
SELECT DISTINCT restaurant.*,branch.*
from restaurant,branch,restaurant_cuisines,restaurant_collections
WHERE restaurant.restaurant_id=branch.restaurant_id
AND restaurant_cuisines.cuisine_id IN (2,3)
AND restaurant_collections.collection_id IN ();
当second where in条件中没有值时,如何执行此查询?或者如何在应用程序级(java)中处理这个问题,我需要编写大约28个if-else条件来检查空条件。如何克服这个问题?
15条答案
按热度按时间ybzsozfc1#
如果不将“餐厅菜系”和“餐厅收藏”与其他项目联系起来,sql就没有真正的意义。如果这两个表与其他表不相关,那么sql就是这两个表的笛卡尔积。
例如y,表a和b有两列(c1和c2)
生成sql
选择a和b之间的所有组合,保持“孔”为空值。
首先,将表与所需字段关联起来。然后使用适当的联接(左联接或外联接)建立关系如果进行了更正,则与联接的第二部分没有关联的行将为空(就像空集合),并且可以选择其值为空的所有行(ej:restaurant\u collections.collection\u id为空)
示例:(需要填充缺少的关系)
hs1rzwqc2#
这是应用程序任务,不是sql任务。
当我有一个带有几个可选输入的api时,我构造
WHERE
动态地。类似于(抱歉,这是用php编写的,不是用java编写的):笔记:
如果没有进入
x
,那么WHERE
省略。如果没有提供任何参数,我甚至可以去掉
WHERE
从句。处理
IN
有点混乱,但还不错。处理日期范围和其他变化也是可能的。
zpqajqem3#
在这个场景中,我对自己的看法类似于@paulspiegel。虽然我不会先检查所有的空数组,甚至是放入查询中。对于小coct,它仍然会增加计时。我会附上
StringBuilder
如果数组不为空sql.append( AND restaurant_cuisines.cuisine_id IN (?,?) )
,相同条件适用于参数。9wbgstp74#
如果您的数据库支持它,您可以使用任何(如下面的jdbi3示例所示)
String sql = "SELECT * FROM table where collection_id = ANY (:ids);" List<Long>ids = ...; org.jdbi.v3.core.Handle db = getHandle(); db.createQuery(sql).bind("ids", ids.toArray(new Long[ids.size()]))
any也适用于空数组(至少在postgres中是这样)。yftpprvb5#
这完全取决于你的需要。通常你应该跳过整个部分。
当你使用
AND
对于所有条件,我假设通过空列表,您希望返回所有行(我猜最终用户有某种多个复选框或类似的东西)。如果列定义为
NOT NULL
您可以用java生成如下代码:如果需要特定值,请将其用作上一个值:
ljsrvy3e6#
如果方向正确,请编写if/else来去除空数组条件。
但是你不需要写那么多(~28个函数),只要把它们抽象成一个函数就行了。
希望你能明白。
hpcdzsge7#
这个问题似乎缺乏一些解释。别人帮助你的最好方法是对以下方面有一个很好的了解:
你的实体关系(er)模型。我看到有四个表,但不清楚表之间的关系
er代表了什么,你想要实现什么,简单的语言也会有帮助。
我可能会在您的提问中补充一些一般性的意见:
为了避免“笛卡尔积”,需要建立n-1 where子句来连接表。关于笛卡尔积的快速信息可以在这里找到:笛卡尔积。我假设您希望避免这种情况,但是您只使用一个子句连接了两个表,然后继续缩小结果的范围,因此缺少了另外两个where子句。那是你的意图还是疏忽?
您使用distinct关键字来避免重复,可能是为了处理笛卡尔(副)积。在你的案例中,它不如使用分组的方法。这可能会让你很好地理解为什么:https://sqlperformance.com/2017/01/t-sql-queries/surprises-assumptions-group-by-distinct
您正在使用隐式联接。我建议您开始改用显式联接,即左联接、内联接等。它使您的查询更易于阅读和维护。在其他主题中也提到了它,例如:隐式与显式sql连接
向in(空)倾斜。与其他建议或不断提示您在(null)中使用的答案不同,我建议您使用where x is null。在包含null或is null的in子句中读取更多信息
xmjla07d8#
我通常通过增加布尔变量来解决这类问题。在您的示例中,我有一个名为searchbycollectionids的附加布尔参数,这样它会像:
当:collectionids为空时,您将在其中输入-1,:searchbycollectionids设置为false,您的查询将转换为:
由于支架中的第一个条件不满足,因此不会检查第二个条件。所以你会得到一切。
dpiehjr49#
我是sql server开发人员,所以我会这样做:
然后从java代码中调用这个sp
gv8xihay10#
首先,下次尝试复制生成该查询的整个代码时,您对我说的方式是,您从几个输入字段中获取该查询,然后合并到in子句中
您应该创建一个集合来存储这些字段,然后再充气到in中
然后,您可以在创建查询之前检查id集是否为空,并按照您想要的方式处理它(简单地忽略查询,或者不使用此语句构建查询)
顺便说一下,您应该考虑使用hibernate或其他持久性框架,强烈建议不要使用java或任何其他语言通过连接字符串来构建查询。它导致sql注入
km0tfn4u11#
条件
IN ()
将在mysql中引发语法异常。您可以删除
AND
子句,如果该列表被检测为空。分析查询,如果()
如果检测到故障,则清除故障和状况。另一种方法是始终存在一个不符合数据中任何标准的条件。例如,
AND restaurant_collections.collection_id IN (-1)
然后继续添加到列表中。例如,AND restaurant_collections.collection_id IN (-1,10,12)
. 这样,就永远不会出现空名单的情况。hk8txs4812#
你可以试试这个:
quhf5bfb13#
假设在这些括号之间有一个变量,就可以做这个小把戏。
基本上,它测试
@VARIABLE
是NULL
不包括参数。iq3niunx14#
如何在应用程序级(java)中处理这个问题,我需要编写大约28个if else条件来检查空条件。
将查询更改为动态查询,如下所示
上面的代码总是用所有的值来执行(基本上说是真的),现在基于if/else条件,你只需要附加“and条件”不是空的
当second where in条件中没有值时,如何执行此查询?
因此,只有当u id不为空时,才会添加上述内容。这样做的目的是使您的查询只基于所需的条件运行,而不是添加不必要的附加条件,这些条件可能会改变您的结果或面临您当前遇到的问题。
希望这有帮助:)
sg2wtvxw15#
如果您只想让查询工作,那么您应该能够使用:
但这永远不会有结果。
如果你想要更灵活一点的东西,或者如果你期待所有的结果,如果
collection_id
没有任何值传递给它,我建议将隐式联接更改为显式联接。现在您正在使用隐式联接语法:
问题是如果
C.j
是空的,即使修改了语法,查询也不会返回任何结果。显式联接允许更细致的方法:
编写代码时,不要传递空字符串,而要传递null值(或者,如果不使用prepared语句,则传递包含
NULL
). 否则,将值作为列表传递。如果只需要在没有值时忽略行,可以执行以下操作:
当您添加
LEFT JOIN
然后在WHERE
子句,您可以轻松检查C.v
如果使用coalesce函数传递的值不为null,则包含值列表。场景1中有值,仅返回这些值。
场景2,and=null中没有值。归还所有东西。
总之,
LEFT
连接非常灵活,允许您稍后返回并可以选择强制执行严格的INNER JOIN
. 它们不应用于INNER JOIN
做的工作,但大多数肯定有他们的用途,如这里。关于
LEFT
与INNER
:如果希望即使列表为空也执行查询,请使用
LEFT JOIN
.如果希望查询仅在列表中有值时返回结果,请使用
INNER JOIN
.