【问题标题】:CASE in MSSQL WHERE clause - odbc errorMSSQL WHERE 子句中的 CASE - odbc 错误
【发布时间】:2014-09-18 08:36:46
【问题描述】:

在我的 PHP Web 应用程序中,我试图完善逻辑,即用户定义的值组装一个 Transact-SQL 查询,该查询过滤该值。然后使用 ODBC 驱动程序执行查询。复杂之处在于过滤只会在派生字段上进行。除了派生字段是使用 CASE 表达式创建的字段之外,这绝对可以正常工作。

因此,例如,我有一个派生字段,如下所示:

CASE WHEN [text_result] IS NOT NULL THEN [text_result] ELSE
    CASE WHEN [last_event] = 1 THEN 'processed' ELSE 'unprocessed' END
END

如果我尝试使用“未处理”值对其进行过滤,那么最终组装的查询显然类似于以下内容:

SELECT * FROM table WHERE 
    CASE WHEN [text_result] IS NOT NULL THEN [text_result] ELSE
        CASE WHEN [last_event] = 1 THEN 'processed' ELSE 'unprocessed' END
    END = 'unprocessed'

但是,当它运行时,我收到以下错误:

Warning: odbc_execute(): SQL error: [Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near the keyword 'from'., SQL state 37000 in SQLDescribeParameter in 

我尝试运行 SQL 分析器,发现似乎是在初始语句准备期间引发了错误,并且语句准备 SQL 似乎正在从字段名称中截断表达式。所以它看起来像这样:

SET FMTONLY ON select  CASE WHEN [text_result] from table where 1=2 SET FMTONLY OFF go

当我通过 MSSQL 管理工作室运行生成的 SQL 语句时证实了这一点,它工作正常!

我希望一切都有意义。如果有人对这个问题是否可以解决或者只是驱动程序中的一个错误有任何建议,那就太好了!

这是我用来运行组装查询的 PHP(从类中提取):

$link = odbc_connect($strConnectionString,$username,$password);
$rResult = odbc_prepare($link,$qry);
$success = odbc_execute($rResult,$parameters);

var_dump($qry,$parameters):

string 'SELECT * FROM table WHERE 
        CASE WHEN [text_result] IS NOT NULL THEN [text_result] ELSE
            CASE WHEN [last_event] = 1 THEN 'processed' ELSE 'unprocessed' END
        END = ?'
array (size=1)
  0 => string 'unprocessed'

【问题讨论】:

  • 显示你的 php blahblah。
  • 请在您共享的代码之前运行var_dump($qry, $parameters)
  • 您的第二个 case 语句省略了 WHEN。
  • 您是否尝试过使用更标准的“AS [未处理]”语法为计算列命名? CASE WHEN blah blah END AS [ColumnName] 是首选语法。我不知道这是否让您感到困惑,但可能是这样。
  • Var_dumps 添加。 @ron tomambe 抱歉,这是我的错误,不是在代码中复制。

标签: php sql sql-server odbc case


【解决方案1】:

首先,您不需要嵌套的case 语句。你可以这样做:

CASE WHEN [text_result] IS NOT NULL THEN [text_result] 
     WHEN [last_event] = 1 THEN 'processed' 
     ELSE 'unprocessed'
END

我认为您的select 有问题的是=。你可以写:

SELECT unprocessed = (CASE WHEN [text_result] IS NOT NULL THEN [text_result] 
                           WHEN [last_event] = 1 THEN 'processed' 
                           ELSE 'unprocessed'
                      END)

SELECT (CASE WHEN [text_result] IS NOT NULL THEN [text_result] 
             WHEN [last_event] = 1 THEN 'processed' 
             ELSE 'unprocessed'
        END) as unprocessed

但是,当使用= 时,变量是第一位的。

那么,我认为您不能使用? 指定列别名。您必须在其中构造带有列别名的查询字符串。

【讨论】:

  • 那个?用户输入的占位符是由准备好的语句传入的,而不是列别名?那么应该吗?先来(使结果“...WHERE 'unprocessed' = (CASE..)”)?
  • @user1014679 。 . .这就是我的意思。我认为您不能在准备好的语句中将列别名指定为参数。
  • @user1014679 。 . .您的示例代码为END = 'unprocessed',这表明您想使用unprocessed 作为别名。
  • 好吧,我不知道,这是一个用户输入值。你对别名的定义是什么?
  • 我以为我是在我的代码中进行比较,但如果我实际上是在以某种方式创建别名,你能告诉我如何进行比较吗?我想看看CASE表达式解析的值是否等于用户传入的值
【解决方案2】:

你有太多的case stataments:

DECLARE  @tableA Table
(
    text_result varchar(20),
    last_event int
)

INSERT INTO @tableA
VALUES
    (null, 1),
    (null, 2),
    ('xxxx', 3)

SELECT *
FROM @tableA
WHERE 
    CASE WHEN text_result IS NOT NULL THEN text_result  
         WHEN last_event = 1 THEN 'processed' 
    ELSE 'unprocessed' END = 'unprocessed'

【讨论】:

  • 如果我删除嵌套的case语句(例如...WHERE CASE WHEN text_result IS NOT NULL THEN 'foo' ELSE 'bar' END = ?),也会出现同样的问题
  • 这有效:qry= new MSSQLQuery("SELECT 'hello' WHERE 'foo' = ( CASE WHEN 1 = 1 THEN 'foo' ELSE 'bar' END )");。这不会:qry= new MSSQLQuery("SELECT 'hello' WHERE ( CASE WHEN 1 = 1 THEN 'foo' ELSE 'bar' END ) = ?","foo");
  • 查看我对上一个答案的评论,我相信您在 ? 周围缺少引号。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-02
  • 2014-09-08
  • 2020-03-26
  • 2017-04-01
  • 1970-01-01
相关资源
最近更新 更多