Sql MS Access使用参数选择查询失败

Sql MS Access使用参数选择查询失败,sql,ms-access,asp-classic,Sql,Ms Access,Asp Classic,我正在使用Access DB作为经典asp网页的后端。我正在创建一个使用参数的已保存查询。我正在Access 2000中的查询生成器中进行测试。字段均为文本,默认值为NULL,[in_b]s允许长度为零,其中有9个,命名为B160、B80、B40、B30等 我的问题是: SELECT COUNT([in_b]) AS BCnt FROM tblScore WHERE UCALL=[in_call] and NOT ISNULL([in_b]); 这将返回给定UCALL的所有行的计数。如果

我正在使用Access DB作为经典asp网页的后端。我正在创建一个使用参数的已保存查询。我正在Access 2000中的查询生成器中进行测试。字段均为文本,默认值为NULL,[in_b]s允许长度为零,其中有9个,命名为B160、B80、B40、B30等

我的问题是:

 SELECT COUNT([in_b]) AS BCnt FROM tblScore 
 WHERE UCALL=[in_call] and NOT ISNULL([in_b]);
这将返回给定UCALL的所有行的计数。如果我将2[in_b]中的任何一个更改为实际的列名,则查询将提供我想要的内容(在本例中为0),但随后我必须运行9个查询

表格示例

Call  Zone B160   B80  B40
NF4L   1    NULL   X    NULL
NF4L   6    Null  Null  NULL
NF4L   20     X     X   Null
WA4B   2    NULL  NULL   X

If in_call is NF4L and in_b is B160, I expect 1
If in_call is NF4L and in_b is B80,  I expect 2
If in_call is NF4L and in_b is B40,  I expect 0

目标是获取给定调用中所有非空“B”列的计数。

在本例中,您使用参数([In_B])作为列的引用,而不是实际的数据值。我认为你的设计不会走得很远

除了构造9个不同的查询(不要这样做!),您还可以尝试两个其他选项:

  • 将表设计更改为更像一个键值对
  • 根据提供的条件动态构造查询
  • 对于选项1,您可以将表更改为如下所示:

    Call | Zone | BField | BFieldValue
    NF4L | 1    | B80    | X
    NF4L | 1    | B160   | NULL
    NF4L | 1    | B40    | NULL
    NF4L | 6    | B160   | NULL
    NF4L | 6    | B80    | NULL
    NF4L | 6    | B40    | NULL
    NF4L | 20   | B160   | X
    NF4L | 20   | B80    | X
    NF4L | 20   | B40    | NULL
    ...
    
    SELECT COUNT(*) 
    FROM Test
    WHERE CASE 
       WHEN @col = 'col1'
       THEN col1 
       WHEN @col = 'col2' 
       THEN col2 END IS NOT NULL
    
    然后,您的查询可能如下所示:

    SELECT BField, COUNT([BFieldValue]) AS BCnt 
    FROM tblScore 
    WHERE UCALL=[in_call] and [BFieldValue] IS NOT NULL
    GROUP BY BField;
    
    这两个选项中,此选项的扩展性更强。如果您需要在某个时候添加额外的“BFields”,那么这样做很简单,但代价是必须重新设计表以及如何向表中添加数据

    选项2是在运行时动态构造查询,以便您可以根据所概述的条件替换实际列名。例如:

    Dim SQL as String
    Dim BField as String
    Dim InCall as String
    
    'These would typically be passed in, not hardcoded as they are here
    Set InCall = "NF4L"
    Set BField = "B160"
    
    SET SQL = "SELECT Count([" & BField & "] FROM tblScore WHERE [Call] ='" & InCall & "' AND NOT ISNULL([" & BField & "]);"
    
    'From here, either open up a recordset based on this SQL or create a new QueryDef object and execute it.
    

    我知道使用SQL Server,您可以传递一个参数并使用
    CASE
    语句,如下所示:

    Call | Zone | BField | BFieldValue
    NF4L | 1    | B80    | X
    NF4L | 1    | B160   | NULL
    NF4L | 1    | B40    | NULL
    NF4L | 6    | B160   | NULL
    NF4L | 6    | B80    | NULL
    NF4L | 6    | B40    | NULL
    NF4L | 20   | B160   | X
    NF4L | 20   | B80    | X
    NF4L | 20   | B40    | NULL
    ...
    
    SELECT COUNT(*) 
    FROM Test
    WHERE CASE 
       WHEN @col = 'col1'
       THEN col1 
       WHEN @col = 'col2' 
       THEN col2 END IS NOT NULL
    
    其中@col是传入的参数。我认为您可以在MS Access中使用
    IIF
    来实现这一点--尝试一下:

    SELECT COUNT(*) 
    FROM Test
    WHERE NOT ISNULL(IIF(@col = 'col1', col1, IIF(@col = 'col2', col2, ...))
    
    或者,您可以使用动态SQL在服务器端执行此操作,但请确保使用参数化查询。这里有一个很好的例子:

    Const ad_nVarChar = 202
    Const ad_ParamInput = 1
    
    strSQL = "SELECT Count(*) FROM tblScore WHERE [Call] = ? AND NOT ISNULL(?); "
    
    Set cmd = Server.CreateObject("ADODB.Command")    
    cmd.ActiveConnection = connStr
    cmd.CommandText = strSQL
    cmd.CommandType = adCmdText
    cmd.Parameters(0) = "NF4L"
    cmd.Parameters(1) = "B160"
    
    Set rst = cmd.Execute()
    

    祝你好运。

    你能发布一些样本数据和期望的结果吗?谢谢你,我感谢你的时间和努力。在我阅读您的答案之前,我改变了我的表格设计,使其只包含通话、区域和波段的COL,并用B160、B80等值填充波段。