在我的数据库中有3列,分别是姓名,年龄,性别。 在程序中,我只想使用1个搜索按钮。单击该按钮时,程序将确定文本框中的哪三个已输入并搜索正确的数据。
您如何使用查询?例如,如果Name和Gender有文本,则查询:
“Select * from table Where (Name = @name) AND (Gender = @gender)
”
当只输入名称时,我只查询名称。我是否必须按文本框检查文本框是否有用户输入,然后为每个文本框写入多个查询?或者有更好的方法吗?
编辑(29/5/16):我尝试用另一种方式做这个
myCommand = New MySqlCommand("Select * from project_record Where
(FloatNo = @floatNo OR FloatNo = 'None') AND
(DevCompanyName = @devCompanyName OR DevCompanyName = 'None') AND
(DevType = @devType OR DevType = 'None') AND
(LotPt = @lotPt OR LotPt = 'None') AND
(Mukim = @mukim OR Mukim = 'None') AND
(Daerah = @daerah OR Daerah = 'None') AND
(Negeri = @negeri OR Negeri = 'None') AND
(TempReference = @tempRef OR TempReference = 'None')", sqlConn)
但正如你可以猜到的那样它也不会有效地工作,因为如果我只输入DevType
的输入并将其他文本框留空,则查询不会仅提取DevType
的所有记录。它只会显示为无记录。
答案 0 :(得分:4)
Select * from table
Where (Name = @name OR @name is Null)
AND (Gender = @gender OR @gender is Null)
...
它应该是一个查询
答案 1 :(得分:3)
其他答案解释了如何简化查询。摆脱ORs
尤其重要,因为它们会禁止使用索引。
一旦干净地构建了查询,您需要考虑数据集并确定通常用于过滤的列。然后为他们制作一些INDEXes
。您将无法提供“所有”可能的索引,因此我会警告您考虑数据集。
构建索引时,可以使用单列索引或多列索引。对于您的数据类型,我建议从几个2列索引开始。确保每个索引都以不同的列开头。
对于Where (Name = @name) AND (Gender = @gender)
,以下是一些注意事项:
INDEX(gender) is useless because of low 'cardinality';
INDEX(gender, name) might be useful, but the following would be better:
INDEX(name)
name
和DevCompanyName
之类的内容几乎是唯一的,因此1列索引可能很好。
如果您有gender
和age
,则INDEX(age, gender)
可能有用。
MySQL几乎不会为单个SELECT
使用两个索引。
顺便说一下,WHERE
的构造可以在存储过程中完成。您需要CONCAT
,PREPARE
等
答案 2 :(得分:2)
(向下滚动以查看更新)
您可以尝试以下方法:
代码如下所示:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim Predicate1 As String = Me.TextBox1.Text
Dim Predicate2 As String = Me.TextBox2.Text
Dim Predicate3 As String = Me.TextBox3.Text
Dim PredicateList As New List(Of String)
Dim WhereClause As String
Dim Query As String
If Predicate1 <> String.Empty Then
PredicateList.Add("Name=""" & Predicate1 & """")
End If
If Predicate2 <> String.Empty Then
PredicateList.Add("Age=""" & Predicate2 & """")
End If
If Predicate3 <> String.Empty Then
PredicateList.Add("Gender=""" & Predicate3 & """")
End If
WhereClause = String.Join(" AND ", PredicateList.ToArray)
Query = "SELECT * FROM TABLE WHERE " & WhereClause
MessageBox.Show(Query)
End Sub
除了SQL注入的注释之外,这里还有一个更新的样本。
Dim Command As SqlClient.SqlCommand
Dim Predicate1 As String = Me.TextBox1.Text
Dim Predicate2 As String = Me.TextBox2.Text
Dim Predicate3 As String = Me.TextBox2.Text
Dim ParameterList As New List(Of SqlClient.SqlParameter)
Dim PredicateList As New List(Of String)
Dim BaseQuery As String = "SELECT * FROM TABLE WHERE "
If Predicate1 <> String.Empty Then
PredicateList.Add("name = @name")
ParameterList.Add(New SqlClient.SqlParameter("@name", Predicate1))
End If
If Predicate2 <> String.Empty Then
PredicateList.Add("age = @age")
ParameterList.Add(New SqlClient.SqlParameter("@age", Predicate2))
End If
If Predicate3 <> String.Empty Then
PredicateList.Add("gender = @gender")
ParameterList.Add(New SqlClient.SqlParameter("@gender", Predicate3))
End If
Command = New SqlClient.SqlCommand(BaseQuery & String.Join(" AND ", PredicateList.ToArray))
Command.Parameters.AddRange(ParameterList.ToArray)
答案 3 :(得分:2)
COALESCE是你的朋友。您可以使用它来使where子句忽略参数为NULL的比较。
Select * from table Where (Name = COALESCE(@name,table.Name))
AND (Gender = COALESCE(@gender,table.Gender))
因此,如果@name
参数为NULL,COALESCE(@name,table.Name)
将返回&#39;名称&#39;的值。当前行的列和(Name = COALESCE(@name,table.Name))
将始终为真。
这假设如果在文本框中没有输入任何值,则相应的参数将为NULL。如果它是一个诸如“无”之类的值,则可以使用NULLIF
函数来映射“无”和“无”。为NULL
Select * from table Where
(Name = COALESCE( NULLIF( @name, 'None'), table.Name))
AND (Gender = COALESCE( NULLIF( @gender, 'None'), table.Gender))
答案 4 :(得分:1)
How to implement a more efficient search?
答案部分取决于您对效率的定义。我怀疑你意味着更少的代码和更少的块等等。但从根本上说,运行一个新的SELECT *
查询来应用过滤器是低效的,因为你的基础数据集可以是所有行,你只是摆弄用户查看它
我有一个数据库,其中包含 Fish , Color (字符串), Bird , Group 列中的随机数据>(int)和 Active ,对于问题中的名称,年龄和性别应该足够相似 - 或者最底层的其他事情。
填充数据表并将其绑定到DGV:
' form level object
Private dtSample As DataTable
...
' elsewhere
Dim sql = "SELECT Id, Name, Descr, `Group`, Fish, Bird, Color, Active FROM Sample"
Using dbcon As MySqlConnection = New MySqlConnection(MySQLConnStr)
' create SELECT command with the Query and conn
Dim cmd As New MySqlCommand(sql, dbcon)
...
daSample.Fill(dtSample)
daSample.FillSchema(dtSimple, SchemaType.Source)
End Using
dgv2.DataSource = dtSample
展望未来,我们可以在不发出新查询的情况下过滤该表的用户 视图 。
如果某些字段仅限于某些选择,例如Gender
,则可以使用ComboBox
代替TextBox
。这是为了帮助用户成功并避免拼写错误(制作或 Mael 而不是男性;或者在这里,正确拼写 Baracuda 我的意思是 Baraccuda ,呃 Barracuda 正确。
为了便于说明, Fish 是用户可以输入任何内容的东西,但 Bird 被限制为一组选择。如果有Bird
表,则可以绑定或填充cboBird
。但您也可以从主/基表中填充它:
Dim birds = dtSample.AsEnumerable.Where(Function(d) d.IsNull(5) = False).
Select(Function(d) d.Field(Of String)("Bird")).
Distinct.
ToArray()
cboBird.Items.AddRange(birds)
如果&#34; Finch&#34;是一个合法的选择,但数据库中没有,它不会显示在列表中。根据应用程序的不同,这可能是一件好事:
Finch
上过滤并且没有结果记录,则您不需要MessageBox
或StatusBar
消息来解释空结果集。 Dialog
或不同TabPage
,则可以根据需要轻松完成。取决于应用程序,这两种方法是否有价值。
我不确定你为什么要添加&#39;没有&#39;每个条款。如果有人想要查看所有“John”或所有“Cod&#39;记录,似乎他们也不会对“没有”感兴趣。就个人而言,Null / DBNull似乎是一种更好的处理方式,但很容易添加或不添加任何一种形式。
使用DBNull / None过滤只是那些似乎更多有价值。鸟类列表的上述代码会过滤掉DBNull
,我也会过滤none
。然后,在将结果添加到ComboBox
之前,添加“无”#39;首先是项目,所以它位于顶部。
这又取决于应用程序的功能; Or = 'None'
,在这种情况下可能非常有意义。
使用{{1>}用于 Fish 和群组,{{1>}用于 Bird 和 Color < / em>和 Active 的TextBox
,代码可以形成过滤器:
ComboBox
CheckBox
Dim filterTerms As New List(Of String)
Dim filterFmt = "{0} = '{1}' "
' OR:
' Dim filterFmt = "{0} = '{1}' OR {0} Is Null"
' OR:
' Dim filterFmt = "{0} = '{1}' OR {0} = 'none'"
If String.IsNullOrEmpty(tbSearchFish.Text) = False Then
Dim txt = tbSearchFish.Text.Replace("'", "''")
filterTerms.Add(String.Format(filterFmt, "Fish", txt))
End If
If cboBird.SelectedIndex > -1 Then
filterTerms.Add(String.Format(filterFmt, "Bird", cboBird.SelectedItem.ToString))
End If
If String.IsNullOrEmpty(tbGroup.Text) = False Then
Dim n As Int32
If Int32.TryParse(tbGroup.Text, n) Then
filterTerms.Add(String.Format(filterFmt, "[Group]", n))
End If
End If
If cboColor.SelectedIndex > -1 Then
filterTerms.Add(String.Format(filterFmt, "Color", cboColor.SelectedItem.ToString))
End If
If chkActive.Checked Then
' NOTE: I do not have TreatTinyAsBoolean turned on
' for some reason
filterTerms.Add(String.Format(filterFmt, "Active", "1"))
End If
If filterTerms.Count > 0 Then
Dim filter = String.Join(" AND ", filterTerms)
dtSample.DefaultView.RowFilter = filter
Dim rows = dtSample.DefaultView.Count
End If
,它会转义任何嵌入的标记,例如可能在filterFmt
或TextBox
等名称中找到的标记。它用两个滴答代替。O'Malley
输入D'Artgnan
列表中有元素,则会创建过滤字符串Int32
(您也可以使用filterTerms
或DefaultView.Filter
),以便代码无需查询数据库即可提供过滤功能强> DataView
会告诉您当前视图中有多少行。唯一有一半棘手的问题是像性别或 Active 这样的布尔值,因为这些布尔实际上解决了三个选择:BindingSource
。为此,我会使用Rows
并将其忽略为SelectedIndex 0。我没有为此烦恼,因为{Any/Either, A, B}
概念已被充分涵盖。结果:
仍然取决于
它不会重新查询数据库以获取应用已经拥有的行
没有创建新的ComboBox
,Combo
或其他DBProvider对象,只是列表。
无需在循环中动态创建带有N个参数的SQL语句,以避免SQL注入/特殊字和字符。
它甚至无法在数据库中查询过滤条款的项目。如果DB中有静态列表,则第一次使用过滤器时可以加载一次
删除过滤器很容易,不需要在没有DBConnection
子句的情况下再次查询
适用的DBCommand
可帮助用户找到所需内容,避免拼写错误
SQL&#34;更清洁&#34;。更多&#34;高效?代码并没有真正搞乱新SQL,只是一些WHERE子句。
代码少吗?我不知道,因为我们只看到了结果。它并没有把我作为很多代码来做它所做的事情。
答案 5 :(得分:1)
在我的数据库中有3列,分别是姓名,年龄,性别。在程序中,我只想使用1个搜索按钮。单击该按钮时,程序将确定文本框中的哪3个输入并搜索正确的数据。
当只输入名称时,我只查询名称。我是否必须按文本框检查文本框是否有用户输入,然后为每个文本框写入多个查询?或者有更好的方法吗?
SELECT * FROM `table`
WHERE (`name` = @name AND `name` IS NOT NULL)
OR (`age` = @age AND (`age`>0 OR `age` IS NOT NULL))
OR (`gender` = @gender AND `gender` IS NOT NULL);
如果所有文本框都有值,则使用上述查询,结果将不是一条记录(就像在字段之间使用逻辑AND
一样)。如果你只想要那条记录,你将使用php从其他结果中过滤服务器端。
您可以在Fiddle
中自行查看结果修改强>
为了解决上述不便(在需要时不会轻易带来单个结果),我从answer获得了一些帮助,并将上述查询重写为:
SELECT *, IF(`name`=@name, 10, 0) + IF(`age`=@age, 10, 0) + IF(`gender`=@gender, 10, 0) AS `weight`
FROM `table`
WHERE (`name` = @name AND `name` IS NOT NULL)
OR (`age` = @age AND (`age`>0 OR `age` IS NOT NULL))
OR (`gender` = @gender AND `gender` IS NOT NULL)
HAVING `weight`=30;
SELECT *, IF(`name`=@name, 10, 0) + IF(`age`=@age, 10, 0) + IF(`gender`=@gender, 10, 0) AS `weight`
FROM `table` WHERE (`name` = @name AND `name` IS NOT NULL)
OR (`age` = @age AND (`age`>0 OR `age` IS NOT NULL))
OR (`gender` = @gender AND `gender` IS NOT NULL)
ORDER BY `weight` DESC;
答案 6 :(得分:1)
你非常接近。我们来看看
(FloatNo = @floatNo OR FloatNo = 'None')
所以你希望字段是给定输入还是'None'?但是(表示)你的表中没有FloatNo'无'的记录。你真正想做的是找出输入是否为空(即为空):
(FloatNo = @floatNo OR @floatNo = '')
对于用户错误输入空白的情况,您也可以忽略这一点:
(FloatNo = @floatNo OR TRIM(@floatNo) = '')
整件事:
myCommand = New MySqlCommand(
"Select * from project_record Where
(FloatNo = @floatNo OR TRIM(@floatNo) = '') AND
(DevCompanyName = @devCompanyName OR TRIM(@devCompanyName) = '') AND
(DevType = @devType OR TRIM(@devType) = '') AND
(LotPt = @lotPt OR TRIM(@lotPt) = '') AND
(Mukim = @mukim OR TRIM(@mukim) = '') AND
(Daerah = @daerah OR TRIM(@daerah) = '') AND
(Negeri = @negeri OR TRIM(@negeri) = '') AND
(TempReference = @tempRef OR TRIM(@tempRef) = '')", sqlConn)
答案 7 :(得分:0)
您的方法有什么问题?
改变
(FloatNo = @floatNo OR FloatNo =&#39;无&#39;)
到
(FloatNo = @floatNo OR FloatNo =&#39;&#39;或FloatNo IS NULL)
为每个标准做到这一点 在此之后,您的查询将考虑空值和NULL值。