Можем ли мы использовать «Дело» в ColdFusion Query-of-Query - PullRequest
0 голосов
/ 02 ноября 2018

Я применяю 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 ]

0 голосов
/ 03 ноября 2018

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

Обратите внимание, как 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

Результат запроса к базе данных:

Database Query Result

* 1039 QoQ *

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

0 голосов
/ 02 ноября 2018

EDIT:

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

ORIGINAL:

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

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

Во-первых, у ColdFusion isNumeric() иногда могут быть неожиданные результаты. Это действительно не проверяет, является ли значение числом. Он проверяет, можно ли преобразовать строку в число. Таким образом, есть все виды значений, которые isNumeric() будут видеть как numeric. Пример: 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

0 голосов
/ 02 ноября 2018

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

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

    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>
0 голосов
/ 02 ноября 2018
<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

0 голосов
/ 02 ноября 2018

Обновление:

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

...