sql查询中的可选搜索参数和具有空值的行

时间:2010-03-12 07:12:42

标签: c# mysql

好的,这是我的问题:

在我开始描述之前,让我告诉你我已经搜索了很多内容并且我发布了这个问题以获得一个很好的最佳解决方案:)

我正在WCF上构建一个休息服务以获取userProfiles ...用户可以通过提供类似userProfiles的内容来过滤userProfiles吗?location = London

现在我有以下方法

GetUserProfiles(string firstname, string lastname, string age, string location)

我构建的sql查询字符串是: select firstname, lastname, .... from profiles where (firstName like '%{firstname}%') AND (lastName like '%{lastName}%') ....等等,所有变量都被字符串格式化程序替换。

问题在于它过滤了具有空值的名字,姓氏,年龄或位置的任何行....

(firstName like '%{firstName}%' OR firstName IS NULL)这样的事情会很乏味,声明会变得难以理解! (在这个例子中只有4个参数,但在我的实际方法中有10个)

对此最好的解决办法是什么?....这种情况通常如何处理?

使用的数据库:MySql

4 个答案:

答案 0 :(得分:2)

这是NULL的一个基本属性,当你将它与任何 - 包括NULL进行比较时,它会返回false,这就是为什么你是做不起作用。

所以要回答的第一个问题是:为什么要在输入NULL“smith”时返回lastname lastname行?可能你的意思是要么 要返回的姓氏需要匹配,在这种情况下你没有运行正确的查询。最天真的解决方案是:

SELECT firstname, lastname, ....
FROM profiles
WHERE IFNULL(firstName LIKE'%{firstname}%'
OR lastName LIKE '%{lastName}%'

现在这将适用于数百甚至数千行,但由于以下几个原因而无法扩展:

  1. OR在性能方面通常很糟糕。尽可能避免使用它们。如果你看一下由经验丰富的程序员编写的数据库应用程序,你可能找不到一个OR条件(除了那些在曾经写过一个留言簿应用程序背后改变OR的优点的人。 3个用户,每月2次点击);
  2. 在前面执行LIKE %将意味着不会起诉索引。
  3. (2)有几种解决方案。可能MySQL最简单的方法是在MyISAM表上使用full text searching。如果你输入“han”,它就不会找到像“Johannes”这样的匹配,但通常就足够了。

    您经常在多个查询中使用OR或(最好)UNION来处理UNION ALL条件。例如:

    SELECT firstname, lastname, ....
    FROM profiles
    WHERE firstName LIKE'%{firstname}%'
    AND lastName LIKE '%{lastName}%'
    UNION ALL
    SELECT firstname, lastname, ....
    FROM profiles
    WHERE firstName LIKE'%{firstname}%'
    AND lastname IS NULL
    UNION ALL
    SELECT firstname, lastname, ....
    FROM profiles
    WHERE firstName IS NULL
    AND lastName LIKE '%{lastName}%'
    UNION ALL
    SELECT firstname, lastname, ....
    FROM profiles
    WHERE firstName IS NULL
    AND lastName IS NULL
    

    看起来又大又丑,但UNION ALL非常好(忽略了%条件开头的LIKE。它基本上是连接(在这种情况下)四个查询。 UNION会对结果行执行隐式DISTINCT,但我们知道此处不会重叠,因为我们会对NULL进行不同的检查。

    另一种可能性是不将NULL视为您要搜索的内容。这是一个更好,更直观的解决方案(imho)。如果有人输入“Smith”的姓氏,你真的想要显示NULL姓氏的行吗?

    或者你想让它们出现,因为你可能在名字上有匹配?如果是这样,您需要稍微不同的查询。例如:

    SELECT firstname, lastname, ....
    FROM profiles
    WHERE id IN (
      SELECT id 
      FROM profiles
      WHERE firstName LIKE'%{firstname}%'
      UNION ALL
      SELECT id 
      FROM profiles
      WHERE lastName LIKE '%{lastName}%'
    )
    

答案 1 :(得分:1)

您可以使用COALESCE(value,...)

coalesce(firstName, '') like '%{firstname}%'

答案 2 :(得分:0)

您可以使用COALESCE

select firstname, lastname, ....
from profiles
where (coalesce(firstName, '') like '%{firstname}%')
AND (coalesce(lastName, '') like '%{lastName}%')

答案 3 :(得分:0)

你总是可以首先禁止空值 - 毕竟,每个人都必须活着好几年并且在某个地理位置。

如果你绝对必须允许空值,那么就像其他人建议的那样使用COALESCE,或者可能是IFNULL,这是MySQL特有的,并且可能稍微更优,因为它只需要2个参数。