4

我正在申请caseColdFusion 查询查询,但它抛出了一个错误。

询问:

<cfquery name="qEmployees1" dbtype="query">
    select (
        case 
          when ISNUMERIC(u.userdefined)=1
          then right('00000000'+u.userdefined,8)
          else userdefined
        end
      ) as hello
    from all_employees
    order by hello ASC
</cfquery>

错误信息:

Encountered "when" at line 3, column 22. Was expecting one of: 
    "AND" ... "BETWEEN" ... "IN" ... "IS" ... "LIKE" ... "NOT" ... 
    "OR" ... ")" ... "=" ... "." ... "!=" ... "#" ... "<>" ... 
    ">" ... ">=" ... "<" ... "<=" ... "+" ... "-" ... "*" ... 
    "||" ... "/" ... "**" ... "(" ...
4

5 回答 5

2

更新:

最初的建议是行不通的,因为它只查看一行。确实,您需要遍历all_employees记录集并将其应用于每一行。

如果您只是将结果输出到页面,则可能无需 QoQ 即可实现此目的。像这样:

<cfoutput>
    <cfloop query="all_employees">
     <cfif isNumeric(all_employees.userdefined)>
      #Right('00000000'&all_employees.userdefined,8)#
     <cfelse>
      #all_employees.userdefined#
     <cfif>
    </cfloop>
</cfoutput>

原答案:

像这样的东西怎么样?:

<cfquery name="qEmployees1" dbtype="query">
SELECT 
<cfif isNumeric([all_employees].[u.userdefined])>
  right('00000000'+u.userdefined,8) 
<cfelse>
 u.userdefined
</cfif> AS hello
FROM all_employees
ORDER by hello
</cfquery>

我没有对此进行测试,但我认为 SQL 列名中的点表示法在这种情况下不会正常工作。无论如何,我将它括在方括号中。

于 2018-11-02T12:19:40.863 回答
1

如果其他人决定尝试下面的 QoQ,需要注意的一件非常重要的事情是,即使执行没有错误,它也不会做与CASE. 语句将CASE逻辑应用到表的每一行中的值 -单独。在 QoQ 版本中,CFIF 表达式不会对查询中的所有值进行操作。它只检查第一行中值,然后将该值的决定应用于查询中的所有行。

请注意下面的 QoQ(错误地)如何报告所有值都是数字的?而数据库查询(正确)报告“数字”和“非数字”值的混合。所以 QoQ 码等同于 CASE。

测试表数据:

id  userDefined
1   22
2   AA
3   BB
4   CC

数据库查询:

   SELECT CASE
            WHEN ISNUMERIC(userDefined)=1 THEN 'Number: '+ userDefined
            ELSE 'Not a number: ' + userDefined
        END AS TheColumnAlias
   FROM TestTable
   ORDER BY ID ASC

数据库查询结果:

数据库查询结果

环比

<cfquery name="qQueryOfQuery" dbtype="query">
  SELECT 
      <cfif isNumeric(qDatabaseQuery2.userDefined)>
         'Number: '+ userDefined
      <cfelse>
         'Not a number: ' + userDefined
      </cfif>
      AS TheColumnAlias
   FROM qDatabaseQuery2
   ORDER by ID
</cfquery>

环比结果

环比结果

于 2018-11-02T23:29:37.293 回答
1

编辑:

我考虑了这一点,并决定将其更改为实际答案。由于您使用的是 CF2016+,因此您可以访问 CF 提供的一些更现代的功能。首先,Query of Query 是一个很棒的工具,但它可能会慢。特别是对于较低的记录数。然后,如果您的基本查询中有很多记录,它可能会占用您服务器的内存,因为它是一个内存操作。我们可以在不需要 QoQ 的情况下实现我们的目标。

我们可以复制您正在寻找的功能的一种方法是使用一些较新的 CF 功能。filtereach并且sort都在查询对象上工作。这些是这些的member function版本,但我认为它们看起来更干净。另外,我使用了cfscript-syntax。

我主要重用了创建查询对象的原始 CFSCript 查询 (all_employees),但我在其中添加了一个f列,其中包含要过滤的文本。

all_employees = QueryNew("userdefined,hello,f", "varchar,varchar,varchar",
    [
      ["test","pure text","takeMe"],
      ["2","number as varchar","takeMe"],
      ["03","leading zero","takeMe"],
      [" 4 ","leading and trailing spaces","takeMe"],
      ["5        ","extra trailing spaces","takeMe"],
      ["        6","extra leading spaces","takeMe"],
      ["aasdfadsf","adsfasdfasd","dontTakeMe"],
      ["165e73","scientific notation","takeMe"],
      ["1.5","decimal","takeMe"],
      ["1,5","comma-delimited (or non-US decimal)","takeMe"],
      ["1.0","valid decimal","takeMe"],
      ["1.","invalid decimal","takeMe"],
      ["1,000","number with comma","takeMe"]

    ]
) ;

原始的基本查询没有WHERE子句,因此没有对初始结果进行额外的过滤。但如果需要,我们可以使用QueryFilteror复制它.filter

filt = all_employees.filter( function(whereclause){ return ( whereclause.f == "takeMe"); } ) ;

这需要all_employees查询并应用一个函数,该函数将只返回符合我们函数要求的行。所以查询的任何一行 where f == "takeMe"。这就像WHERE f = 'takeMe'在查询中一样。这会将新过滤的结果设置为新的查询对象filt

然后我们可以使用QueryEachor.each遍历新过滤查询的每一行来修改我们需要的内容。在这种情况下,我们正在为我们想要的值构建一个新数组。循环for/in可能会更快;我没有测试过。

filt.each(
        function(r) {
            retval.append(
                ISNUMERIC(r.userDefined) ? right("00000000"&ltrim(rtrim((r.userdefined))),8) : r.userDefined
            ) ;
        }
    )  ;

现在我们有了一个包含我们想要的结果的新数组,原来的 QoQ 想要对这些结果进行排序。我们可以用ArraySortor来做到这一点.sort

retval.sort("textnocase") ;

在我的测试中,CF2016 似乎retval.sort()作为布尔值传递并且没有返回排序后的数组,但 CF2018 确实如此。这是预期的行为,因为返回类型在 CF2018 中已更改。无论如何,两者都会对retval数组进行排序,因此当我们转储retval数组时,它会按照选择的顺序排列。

正如我一直建议的那样,使用您的数据对您的系统进行负载测试。就像我说的,这只是你想要做的事情的一种方式。还有其他可能更快。

https://cffiddle.org/app/file?filepath=dedd219b-6b27-451d-972a-7af75c25d897/54e5559a-b42e-4bf6-b19b-075bfd17bde2/67c0856d-bdb3-4c92-82ea-840e6b8b0214.cfm

(CF2018) > https://trycf.com/gist/2a3762dabf10ad695a925d2bc8e55b09/acf2018?theme=monokai

https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-mr/queryfilter.html

https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-mr/queryeach.html

https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-ab/arraysort.html

原来的:

这更像是评论而不是答案,但是评论太长了。

我想提几件需要注意的事情。

首先,ColdFusionisNumeric()有时会产生意想不到的结果。它并没有真正检查一个值是否是一个数字。它检查字符串是否可以转换为数字。所以有各种各样的值isNumeric()会被视为numeric. EX:1e3是科学记数法1000isNumeric("1e3")将返回true

我的第二个建议是如何处理“数字”值 EX: 中的前导和尾随空格" 4 "isNumeric()将返回true这个,但是当你附加和修剪你的最终值时,它会以"000000 4". 我处理这些问题的建议是使用val()ltrim(rtrim())围绕您的专栏。val()将其减少为基本数字 ( " 1.0 " >> "1") 但ltrim(rtrim())将保留数字但去掉空格 ( " 1.0 " >> "1.0") 并保留“科学记数法”值 ( " 1e3 " >> "1e3")。两者都仍然错过1,000,所以如果这是一个问题,你需要处理它。但是您使用的方法完全取决于您的数据包含的值。号码验证并不总是像看起来那么容易。

我一直坚信 GIGO -- Garbage In, Garbage Out。我将基本数据清理视为我工作的一部分。但如果它是极端的或常规的,我会告诉源来修复它,否则他们的东西将无法正常工作。在数据方面,不可能考虑所有可能性,但我们可以检查共同的期望。白名单总是比黑名单更容易。

<cfscript>
all_employees = QueryNew("userdefined,hello", "varchar,varchar",
    [
      ["test","pure text"],
      ["2","number as varchar"],
      ["03","leading zero"],
      [" 4 ","leading and trailing spaces"],
      ["5        ","extra trailing spaces"],
      ["        6","extra leading spaces"],
      ["165e73","scientific notation"],
      ["1.5","decimal"],
      ["1,5","comma-delimited (or non-US decimal)"],
      ["1.0","valid decimal"],
      ["1.","invalid decimal"],
      ["1,000","number with comma"]

    ]
)

//writedump(all_employees) ;

retval = [] ;

for (r in all_employees) {
    retval.append(
        {
          "1 - RowInput"   : r.userdefined.replace(" ","*","all") , // Replace space with * for output visibility.
          "2 - IsNumeric?" : ISNUMERIC(r.userdefined) ,
          "3 - FirstOutput": ( ISNUMERIC(r.userDefined) ? right("00000000"&r.userdefined,8) : r.userDefined ) ,
          "4 - ValOutput"  : ( ISNUMERIC(r.userDefined) ? right("00000000"&val(r.userdefined),8) : r.userDefined ) ,
          "5 - TrimOutput"  : ( ISNUMERIC(r.userDefined) ? right("00000000"&ltrim(rtrim((r.userdefined))),8) : r.userDefined )
        } 
    ) ;
}

writeDump(retval) ;
</cfscript>

https://trycf.com/gist/03164081321977462f8e9e4916476ed3/acf2018?theme=monokai

于 2018-11-02T16:34:06.457 回答
0

你到底想做什么?请为您的帖子分享一些目标背景。

在我看来,您的查询格式可能不正确。它会评估为:

    select ( 0000000099
      ) as hello
    from all_employees
    order by hello ASC

尝试这样做。<cfabort>在这里放一个……然后让我知道当你运行它时屏幕上产生了什么查询。

<cfquery name="qEmployees1" dbtype="query">
    select (
        case 
          when ISNUMERIC(u.userdefined)=1
          then right('00000000'+u.userdefined,8)
          else userdefined
        end
      ) as hello
    from all_employees
    order by hello ASC
<cfabort>
</cfquery>
于 2018-11-02T12:46:02.337 回答
-1
<cfquery name="qEmployees1" dbtype="query">
  SELECT 
    (
      <cfif isNumeric(all_employees.userdefined)>
         right('00000000'+all_employees.userdefined,8) 
      <cfelse>
         all_employees.userdefined
      </cfif>
    ) AS hello
FROM all_employees
ORDER by hello
</cfquery>

感谢@volumeone,它是无语法的答案

于 2018-11-02T12:54:00.357 回答