Можем ли мы использовать "Дело" в ColdFusion Query-of-Query

Я подаю заявку case в запросе ColdFusion запроса, но он выдает ошибку.

Запрос:

<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" ... ")" ... "=" ... "." ... "!=" ... "#" ... "<>" ... 
    ">" ... ">=" ... "<" ... "<=" ... "+" ... "-" ... "*" ... 
    "||" ... "/" ... "**" ... "(" ...

5 ответов

Обновить:

Первоначальное предложение не сработает, потому что оно смотрит только на один ряд. На самом деле вам нужно пройти через ваш 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 будет работать правильно. Я все равно заключил его в квадратные скобки.

РЕДАКТИРОВАТЬ:

Я подумал об этом и решил изменить его на фактический ответ. Поскольку вы используете CF2016+, у вас есть доступ к некоторым из более современных функций, которые предлагает CF. Во-первых, Query of Query - отличный инструмент, но он может быть очень медленным. Особенно для меньшего количества записей. И затем, если в вашем базовом запросе много записей, это может поглотить память вашего сервера, поскольку это операция в памяти. Мы можем достичь нашей цели без необходимости QoQ.

Один из способов, которым мы можем что-то дублировать, - это найти некоторые новые функции CF. filter, each а также sort все работают над объектом запроса. Эти member function Версии эти, но я думаю, что они выглядят чище. Кроме того, я использовал синтаксис cfscript.

Я в основном повторно использовал свой оригинальный запрос 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 пункт, поэтому не было никакой дополнительной фильтрации по первоначальным результатам. Но если бы нам было нужно, мы могли бы дублировать это с QueryFilter или же .filter,

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

Это занимает all_employees запрос и применяет функцию, которая будет возвращать только те строки, которые соответствуют требованиям нашей функции. Так что любая строка запроса, где f == "takeMe", Это как WHERE f = 'takeMe' в запросе. Это устанавливает новые отфильтрованные результаты в новый объект запроса filt,

Тогда мы можем использовать QueryEach или же .each просмотреть каждую строку нашего нового отфильтрованного запроса, чтобы изменить то, что нам нужно. В этом случае мы создаем новый массив для значений, которые мы хотим. for/in цикл, вероятно, будет быстрее; Я не проверял.

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

Теперь, когда у нас есть новый массив с желаемыми результатами, оригинальный QoQ хотел упорядочить эти результаты. Мы можем сделать это с ArraySort или же .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-m-r/queryfilter.html

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

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

ОРИГИНАЛ:

Это скорее комментарий, чем ответ, но он слишком длинный для комментария.

Я хотел бы упомянуть пару вещей, на которые стоит обратить внимание.

Во-первых, ColdFusion's isNumeric() иногда может иметь неожиданные результаты. Это на самом деле не проверяет, является ли значение числом. Он проверяет, можно ли преобразовать строку в число. Таким образом, есть все виды ценностей, которые isNumeric() увидим как numeric, EX: 1e3 это научное обозначение 1000, isNumeric("1e3") вернусь true,

Мое второе предложение заключается в том, как бороться с начальным и конечным пробелом в "числовом" значении, например: " 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

В случае, если кто-то еще решит попробовать QoQ ниже, следует отметить одну очень важную вещь: даже если он выполняется без ошибок, он НЕ делает то же самое, что и CASE, CASE Оператор применяет логику к значениям в каждой строке таблицы - индивидуально. В версии QoQ выражение CFIF работает не со всеми значениями в запросе. Он только проверяет значение в 1-й строке, а затем применяет решение для этого единственного значения ко ВСЕМ строкам в запросе.

Обратите внимание, как QoQ ниже (неправильно) сообщает, что все значения являются числовыми? В то время как запрос к базе данных (правильно) сообщает о сочетании "числовых" и "нечисловых" значений. Таким образом, код QoQ не эквивалентен CASE.

Данные TestTable:

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>

QoQ Результат

QoQ Результат

Что вы пытаетесь сделать именно? Пожалуйста, поделитесь некоторым контекстом цели для вашего поста.

Мне кажется, ваш запрос может быть отформатирован неправильно. Это будет означать что-то вроде:

    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>
<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

Другие вопросы по тегам