Запрос Coldfusion MySQL внутри запроса

Я пытаюсь получить записи, выпадающие на определенный год и месяц, из полного набора записей для конкретного пользователя. Во-первых, рассматриваемое поле itemdate имеет тип MySql Datetime (например, 2016-08-15 20:00:25). Для пользователя существует 4 строки записей:

2016-08-15 20:00:25
2015-06-01 20:25:05
2016-08-15 20:26:00
2016-08-15 23:30:35

Эти записи для конкретного пользователя извлекаются:

<cfquery datasource="userdatbase"name="reportlist">
select itemid, itemdate, itemvalue
from itemlib
where userid = '#currentuserid#'
</cfquery>

Текущий год и месяц определяются:

<cfset thisyear = #Year(Now())#>
<cfset thismonth = #Month(Now())#>

Теперь отфильтруйте исходный запрос и получите только те, которые относятся к текущему году и месяцу:

    <cfquery dbtype="query" name="detail"> 
        select itemid, itemdate, itemvalue
        from reportlist
        where year(itemdate) = #thisyear#
        and month(itemdate) = #thismonth#
    </cfquery>

Я получаю следующую ошибку:

Ошибка выполнения запроса к базе данных.

Синтаксическая ошибка Query Of Queries. Обнаружен год. Неверное условное выражение. Ожидалось одно из условий [like|null|between|in|comparison],

Вместо этого я попытался сделать это:

    <cfquery dbtype="query" name="detail"> 
        select itemid, itemdate, itemvalue
        from reportlist
        where #year(reportlist.itemdate)# = #thisyear#
        and #month(reportlist.itemdate)# = #thismonth#
    </cfquery>

который избавит от ошибки. Однако я получил все 4 строки записей в запросе detail вместо ожидаемых 3. Я не ожидаю, что запись 2015-06-01 20:25:05 будет быть избранным, но это так. Я ломаю голову над этим. Любая помощь приветствуется. Заранее спасибо.


person Jack    schedule 16.08.2016    source источник
comment
Вы уверены, что функции месяца/года поддерживаются, несмотря на тип соединения/драйвера, который вы используете? Месяц/год, по-видимому, поддерживается MySQL, поэтому я не думаю, что у движка возникают проблемы с анализом запроса. and-time-functions.html#function_month" rel="nofollow noreferrer">dev.mysql.com/doc/refman/5.5/en/   -  person xQbert    schedule 16.08.2016
comment
Тем не менее, я получил все 4 строки Поскольку SQL-запрос не делает то, что вы думаете... Вы выполняете сравнение двух литеральных значений, таких как WHERE 1 = 1. Он всегда будет истинным (или ложным) для каждой строки в запросе.   -  person Leigh    schedule 17.08.2016
comment
Что произойдет с вашей страницей, если вы укажете диапазон дат в исходном запросе к базе данных?   -  person Dan Bracuk    schedule 17.08.2016
comment
@DanBracuk Мне нужно проверить, есть ли что-нибудь для пользователя. Поэтому я не указал диапазон дат в запросе к базе данных. Я выполняю QofQ только в том случае, если что-то возвращается от пользователя. Я считаю, что диапазон дат будет работать с исходным запросом к базе данных. Проблема с QofQ. Я хочу предотвратить повторное попадание в базу данных, если есть записи, возвращаемые пользователем.   -  person Jack    schedule 17.08.2016
comment
Q of Q не всегда лучший вариант, чем несколько ударов по дб. Если вы имеете дело с большими объемами данных, вы можете столкнуться с проблемами памяти. В вашей ситуации это может быть, а может и не быть. Другой вариант, который у вас есть, — выполнить проверку с помощью запроса select count(*). Это все неточная наука.   -  person Dan Bracuk    schedule 17.08.2016
comment
@DanBracuk Спасибо за отличный совет. Думаю, я рассмотрю это. Количество записей может быть огромным, так как записи будут храниться в течение 2 лет для каждого пользователя. Я думаю о том, чтобы кешировать его на 5 минут для каждого запроса и позволять пользователю просматривать разные месяцы.   -  person Jack    schedule 25.08.2016


Ответы (1)


Coldfusion Query of Queries (QofQ) не обладает полной функциональностью dbms. year() не поддерживается в синтаксисе QofQ.

Ваш второй запрос синтаксически верен, потому что он передает значение reportlist.itemdate, которое будет значением itemdate в первой строке запроса reportlist (при условии, что вы не зацикливаетесь на reportlist). ColdFusion интерпретирует это как сравнение двух литеральных значений вместо сравнения значений строки в запросе.

В качестве альтернативы вы можете установить переменную (fromDate) на первую дату нужного месяца, а затем отфильтровать свой запрос, где дата элемента будет >= fromDate и < fromDate плюс 1 месяц. Смотри ниже:

<!--- set fromDate to the first date of the month --->
<cfset fromDate = createDate(thisyear, thismonth, 1) />
<cfquery dbtype="query" name="detail"> 
    select itemid, itemdate, itemvalue
    from reportlist
    where itemdate >= <cfqueryparam value="#fromDate#" cfsqltype="cf_sql_date" />
          and itemdate < <cfqueryparam value="#dateAdd('m', 1, fromDate)#" cfsqltype="cf_sql_date" />
</cfquery>

То же самое достигается с помощью компараторов, поддерживаемых ColdFusion QoQ.

Некоторая полезная документация здесь: http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec0e4fd-7ff0.html

person beloitdavisja    schedule 16.08.2016
comment
Спасибо, @beloitdavisja. Я не знал, что ГОД и МЕСЯЦ не будут работать в QofQ, но я думал, что MySQL также имеет эти функции. Почему функция MySQL не сработала при моей первой попытке QofQ? Я также не знал, что CF не будет работать с отдельными значениями строк, потому что он возвращает 4 строки, а не одну. Если бы у меня был цикл, разве он не вернул бы 16 строк (4x4)? Я впервые использую QofQ, и это сводит меня с ума. - person Jack; 17.08.2016
comment
@Jack MySQL имеет эти функции. Однако запрос запросов не выполняется в MySQL. QofQ чаще всего используется для фильтрации или изменения набора результатов запроса к базе данных в памяти. Это мощный инструмент, но он может разочаровать, так как имеет свои собственные правила и ограниченный синтаксис. Это не полнофункциональный язык запросов к базам данных, такой как MySQL, и он не использует никаких функций этих языков запросов к базам данных, даже если набор результатов происходит из базы данных MySQL. - person beloitdavisja; 17.08.2016
comment
Мне нужно проверить, есть ли что-нибудь для пользователя Также стоит отметить, что вам может вообще не понадобиться несколько запросов (или QoQ). Есть ли причина, по которой вы не можете использовать JOIN для itemlib и reportlist и фильтровать его по идентификатору пользователя? - person Leigh; 19.08.2016
comment
@Ли, спасибо, Ли. Список отчетов - это запрос, полученный из запроса из itemlib для пользователя. Я не уверен, что я получу от JOIN после первоначального запроса пользователя? - person Jack; 25.08.2016
comment
@ Джек - Хм ... тогда что тебе даст двойной запрос? Почему бы просто не применить фильтры даты в исходном запросе БД? - person Leigh; 25.08.2016
comment
@Leigh Мне нужен первый проход, чтобы проверить, есть ли вообще какая-либо запись для пользователя. если их нет, я просто отображаю сообщение, сообщающее пользователю, что для элемента вообще нет записей. Если я просто покажу текущую запись даты, а ее нет, пользователь может попробовать разные даты и ничего не найти. Но он попадет в дб много раз. - person Jack; 25.08.2016
comment
@Jack - попадание в БД - это не всегда плохо, потому что вы на самом деле не сильно экономите, если вы все еще каждый раз извлекаете X записей (т.е. 50 100 1000) из базы данных, и если совпадений нет, записи просто отбрасываются. Добавление подвыборки с помощью count(*), вероятно, было бы более эффективным. Кроме того, вы можете изучить кэширование и/или показать пользователям диапазон дат, которые у них есть, чтобы сократить фактор угадывания. Все зависит от приложения... - person Leigh; 25.08.2016
comment
@Leigh Я планирую реализовать то, что предложил Дэн Бракук. Используйте «Выбрать счетчик (*)» в первом запросе (и кэшируйте счет на 5 минут вместо всей записи пользователя). Затем сначала выполните запрос БД на текущую дату, а затем последующие запросы на разные даты. Будет ли это работать лучше? (Программа вызывает себя, я кэширую счетчик, чтобы он не проверял счетчик снова каждый раз, когда пользователь выбирает другую дату.) - person Jack; 25.08.2016
comment
@Leigh Это может быть глупый вопрос: если я создал кеш для данных пользователя, этот кеш доступен только пользователю или всем пользователям на сайте? - person Jack; 25.08.2016
comment
Есть ли конкретная причина, по которой вы считаете, что это является проблемой, или это просто преждевременная оптимизация? Как правило, простой count(*) не так дорог и может даже выполняться в том же запросе с помощью подзапроса, если это необходимо. - person Leigh; 27.08.2016