【问题标题】:Search based on matched criteria根据匹配条件进行搜索
【发布时间】:2009-09-29 15:56:46
【问题描述】:

我正在使用以下查询返回至少有 2 个条件匹配的所有记录 (provided by Quassnoi)。

SELECT  *
FROM    (
        SELECT  ContentID
        FROM    (
                SELECT  ContentID
                FROM    VWTenantPropertiesResults
                WHERE   ContentStreet = 'Holderness Road'
                UNION ALL
                SELECT  ContentID
                FROM    VWTenantPropertiesResults
                WHERE   ContentTown = 'Hull'
                UNION ALL
                SELECT  ContentID
                FROM    VWTenantPropertiesResults
                WHERE   ContentPostCode = 'HU'
                ) qi
        GROUP BY
                ContentID
        HAVING  COUNT(*) >= 2
        ) q
JOIN    VWTenantPropertiesResults r
ON      r.ContentID = q.ContentID
WHERE   ContentBedrooms BETWEEN 1 AND 4
        AND ContentPrice BETWEEN 50 AND 500
ORDER BY
        ContentPrice

问题在于,在搜索 Street and Town(返回所有与请求的街道和城镇匹配的属性)时,它似乎有效,但在搜索 Street 和 Postcode(不返回任何结果)时无效。为了让 Street 和 Postcode 的搜索工作(返回结果),我必须删除以下行;

        UNION ALL
        SELECT  id
        FROM    VWTenantPropertiesResults
        WHERE   ContentTown = 'Hull'

但是显然城镇和邮政编码或城镇和街道搜索不起作用,因为我已经删除了上述 4 行以使街道和邮政编码搜索起作用。

我想知道是否有人可以提供一些帮助?

谢谢。

【问题讨论】:

  • 如何搜索街道和邮政编码?
  • 这个 UNION + HAVING 的意义何在?为什么不选择 DISTINCT ... WHERE (Street = X AND Town = Y) OR (Street = X AND PostCode = Z) OR (Town = Y AND PostCode = Z)?
  • 您的 ContentPostCode 字段的类型是什么?
  • 请向我们展示您的数据集和架构。
  • 大家好,很抱歉未能尽快回复。我在页面中有一个表单,允许用户输入街道、城镇和邮政编码。 Quassnoi 向我提供了代码,以便通过匹配 2 个或更多条件来返回更准确的搜索结果。但是,当我搜索特定街道和邮政编码时 - 结果显示甚至不在该街道上的记录。我认为拥有匹配 2 个或更多条件将使我只能返回该街道或邮政编码上的属性。相反,它只是返回具有邮政编码 HU 的所有内容。

标签: sql sql-server tsql asp-classic


【解决方案1】:

我不确定您是否应该在数据库中强制执行“至少两个条件”标准,因为您可能永远不知道填写了哪两个条件。也许这可能对您有用 - 这是一种模式我经常使用并且应该处理任何标准组合(我假设这是在存储过程中!):

DECLARE PROCEDURE PropertyList
@StreetName NVARCHAR(50) = NULL,
@Town NVARCHAR(50) = NULL,
@Postcode NVARCHAR(10) = NULL
AS

SET NOCOUNT ON

SELECT 
    *
FROM 
    VWTenantPropertiesResults
WHERE
    ContentBedrooms BETWEEN 1 AND 4
AND
    ContentPrice BETWEEN 50 AND 500
AND
    (@ContentStreet IS NULL OR ContentStreet = @ContentStreet)
AND 
    (@ContentTown IS NULL OR ContentTown = @ContentTown)
AND
    (@ContentPostcode IS NULL OR ContentTown = @ContentTown)
ORDER BY
    ContentPrice

要从您的 ASP 页面调用它,您需要一些类似这样的代码(这可能需要一些调试,我的 ADO 和 VBScript for ASP 相当生疏!):

Dim cnn 'As ADODB.Connection
Dim cmd 'As ADODB.Command
Dim prmStreet 'As ADODB.Parameter
Dim prmTown 'As ADODB.Parameter
Dim prmPostcode 'As ADODB.Parameter
Dim rstProperty 'As ADODB.RecordSet
Dim i 'As Integer

Set cnn = Server.CreateObject("ADODB.Connection")

cnn.ConnectionString = MyConnectionString

Set cmd = Server.CreateObject("ADODB.Command")

Set cmd.ActiveConnection = cnn

'Set the CommandText property to the name of the stored proc we want to call
cmd.CommandText = "PropertyList"
cmd.CommandType = 4 'or adCmdStoredProc if you're using ADOVBS.inc

If Request.Form("StreetTextBox") = "" Then
    'No street entered so don't pass it to the stored proc
Else
    'A street has been entered so create a parameter...
    Set prmStreet = cmd.CreateParameter("@StreetName", 203, 1, 50, Request.Form("StreetTextBox"))

    ' and add it to the Parameters collection of the Command object
    cmd.Parameters.Add(prmStreet)
End If

If Request.Form("TownTextBox") = "" Then
    'No town entered so don't pass it to the stored proc
Else
    'A town has been entered so create a parameter...
    Set prmTown = cmd.CreateParameter("@Town", 203, 1, 50, Request.Form("TownTextBox"))

    ' and add it to the Parameters collection of the Command object
    cmd.Parameters.Add(prmTown)
End If

If Request.Form("PostcodeTextBox") = "" Then
    'No postcode entered so don't pass it to the stored proc
Else
    'A postcode has been entered so create a parameter...
    Set prmPostcode = cmd.CreateParameter("@Postcode", 203, 1, 10, Request.Form("PostcodeTextBox"))

    ' and add it to the Parameters collection of the Command object
    cmd.Parameters.Add(prmPostcode)
End If

cnn.Open

'This is the line that'll actually call the stored procedure
Set rstProperty = cmd.Execute()

cnn.Close

If rstProperty.BOF And rstProperty.EOF Then
    'If BOF And EOF are true then this is an empty recordset - we got no records back
    Response.Write "No records returned"
Else
    'We have records so write them out into a table
    Response.Write "<table><tr>"
    For i = 0 To rstProperty.Fields.Count - 1
        Response.Write "<td>"
        Response.Write rstProperty.Fields(i).Name
        Response.Write "</td>"
        Response.Write "<td>&nbsp;</td>"
    Next

    Response.Write "</tr>"

    Do While rstProperty.Eof = False
        Response.Write "<tr>"
        For i = 0 To rstProperty.Fields.Count - 1
            Response.Write "<td>"
            Response.Write rstProperty.Fields(i).Value
            Response.Write "</td>"
        Next
        Response.Write "<td>"
        Response.Write "<a href='ViewDetails.asp?id='" & rstProperty.Fields("PropertyId").Value & "'>View Details for this property</a>"
        Response.Write "</td>"
        Response.Write "</tr>"
        rstProperty.MoveNext
    Loop

    Response.Write "</table>"
End If

应该适用于任何参数组合,无论您输入无、部分还是全部!

【讨论】:

  • 谢谢菲尔。我会试试你的解决方案。我是 ASP 新手,因为我在新工作中继承了旧网站。在您的解决方案中,PropertyList 过程是否还包含一些 SQL 查询?我一直在阅读参数化查询,但之前没有使用过存储过程。谢谢。
  • 存储过程就是查询!如果这对您有用,我可以添加一些 VBScript 代码来演示如何调用存储的过程?
  • 嘿菲尔。如果不是太麻烦就好了?
【解决方案2】:

查询方法看起来不错。

不工作是什么意思?它抛出错误,或不返回结果,或意外结果?

您是否希望使用完整的邮政编码匹配?我看到你的例子使用了 HU,不知道这与什么有关。看起来不像加拿大的邮政编码,您在搜索哪个地区?

你能告诉我们你的数据集吗?

【讨论】:

  • 这确实是英国的赫尔。我相信加拿大的赫尔会更令人兴奋。 ;) 我实际上稍微更改了查询,以便它使用 LIKE 来匹配输入邮政编码之前或之后的任何内容。
  • 我不知道加拿大有赫尔!
【解决方案3】:

如果你是正确的,你是说这个查询:

SELECT  ContentID
FROM    VWTenantPropertiesResults
WHERE   ContentStreet = 'Holderness Road'
UNION ALL
SELECT  ContentID
FROM    VWTenantPropertiesResults
WHERE   ContentTown = 'Hull'
UNION ALL
SELECT  ContentID
FROM    VWTenantPropertiesResults
WHERE   ContentPostCode = 'HU'

对于某些 ContentID 返回少于 2 行,而此查询:

SELECT  ContentID
FROM    VWTenantPropertiesResults
WHERE   ContentStreet = 'Holderness Road'
UNION ALL
SELECT  ContentID
FROM    VWTenantPropertiesResults
WHERE   ContentPostCode = 'HU'

为相同的 ContentID 返回 2 个或更多。

这在逻辑上似乎是不可能的,除非您的 DBMS 存在重大错误!对于某些出现问题的 ContentID,上述查询会返回什么?

【讨论】:

    【解决方案4】:

    你可能想要这个:

    SELECT  *
    FROM    (
            SELECT  ContentID
            FROM    (
                    SELECT  ContentID
                    FROM    VWTenantPropertiesResults
                    WHERE   ContentStreet LIKE '%Holderness Road%' -- Take off the leading % if you can
                    UNION ALL
                    SELECT  ContentID
                    FROM    VWTenantPropertiesResults
                    WHERE   ContentTown LIKE '%Hull%' -- Take off the leading % if you can
                    UNION ALL
                    SELECT  ContentID
                    FROM    VWTenantPropertiesResults
                    WHERE   ContentPostCode LIKE '%HU%' -- Take off the leading % if you can
                    ) qi
            GROUP BY
                    ContentID
            HAVING  COUNT(*) >= 2
            ) q
    JOIN    VWTenantPropertiesResults r
    ON      r.ContentID = q.ContentID
    WHERE   ContentBedrooms BETWEEN 1 AND 4
            AND ContentPrice BETWEEN 50 AND 500
    ORDER BY
            ContentPrice
    

    因为英国没有= 'HU' 的邮政编码,格式为'HU_ ___',所以需要通配符。

    通常我们将搜索限制为从字符串的开头匹配(通过搜索索引提供帮助),但有时用户想要任意搜索。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-13
      • 2022-09-23
      • 1970-01-01
      • 1970-01-01
      • 2020-11-26
      • 2011-04-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多