Объединение строк запроса в цикле

У меня есть следующий код ColdFusion 9:

<cfloop from="1" to="#arrayLen(tagArray)#" index="i">
    <cfquery name="qryGetSPFAQs" datasource="#application.datasource#">
        EXEC searchFAQ '#tagArray[i]#'
    </cfquery>
</cfloop>

EXEC выполняет хранимую процедуру на сервере базы данных, которая возвращает строки данных в зависимости от параметра. Я пытаюсь объединить запросы в один объект запроса. Другими словами, если он повторяется 3 раза и каждый цикл возвращает 4 строки, мне нужен объект запроса, содержащий все 12 строк в одном объекте. Как мне этого добиться?


person Icemanind    schedule 28.05.2010    source источник


Ответы (3)


Возможно, вы захотите использовать другой подход (изменить хранимую процедуру, чтобы она принимала несколько аргументов, или использовать список и fnSplit) и сразу вернуть весь набор данных. Однако, чтобы напрямую ответить на ваш вопрос, вот как вы можете комбинировать запросы, как вы просите:

Вы можете использовать UNION в запросе запросов, чтобы объединить все наборы данных.

<cfloop from="1" to="#arrayLen(tagArray)#" index="i">
    <cfquery name="qryGetSPFAQs#i#" datasource="#application.datasource#">
        EXEC searchFAQ '#tagArray[i]#'
    </cfquery>
</cfloop>

<cfquery name="combined" dbtype="query">
    <cfloop from="1" to="#arrayLen(tagArray)#" index="i">
        select * from qryGetSPFAQs#i#
        <cfif i lt arrayLen(tagArray)>UNION</cfif>
    </cfloop>
</cfquery>
person Adam Tuttle    schedule 28.05.2010

Более прямым способом может быть что-то вроде этого:

<cfset bigQ = queryNew("column")>
<cfloop from="1" to="#arrayLen(tagArray)#" index="i">
    <cfquery name="qryGetSPFAQs" datasource="#application.datasource#">
        EXEC searchFAQ '#tagArray[i]#'
    </cfquery>
    <cfset queryAddRow(bigQ)>
    <cfset querySetCell(bigQ, "column". qryGetSPFAQs)>
</cfloop>

Вам понадобится назначение querySetCell() для каждого столбца. Ознакомьтесь с функциями запросов в текущей документации. Дополнительная информация.

person Ben Doom    schedule 28.05.2010

Вот готовое решение, отказывающееся от StoredProc для представления SQL (я объясню).

Отказ от ответственности: не видя исходный код SP, я не могу сказать, подходит ли мое решение. Я предполагаю, что SP является довольно простым, и я признаю, что обычно предпочитаю скомпилированное выполнение SP, а не представление, но однократное выполнение представления SQL должно превосходить зацикливание SP в x раз.

Сначала создайте представление, похожее на оператор SELECT в SP (конечно, за вычетом параметризации — вы расскажете об этом в предложении WHERE в CFQUERY вашего нового представления.

Во-вторых, настройте свой цикл так, чтобы он делал не более чем создание набора данных, который мы собираемся использовать для предложения WHERE. Вам нужно будет использовать ArrayToList и немного манипулировать строками, чтобы привести его в порядок, а конечным продуктом будет строка, хранящаяся в одной переменной CF, которая выглядит следующим образом:

('ValueOfArrayElement1','ValueOfArrayElement2','Value_And_So_On')

Строить строку довольно легко, используя атрибут delimeter ArrayToList, и после завершения цикла добавьте левую скобку и одинарную кавычку в крайнее левое положение строки; и добавьте одинарную кавычку и правую скобку в самую правую позицию в строке.

Теперь напишите оператор CFQUERY, чтобы ВЫБРАТЬ нужные вам столбцы из вашего представления (вместо выполнения вашего SP). И вместо того, чтобы передавать параметр SP, вы поместите предложение WHERE в CFQUERY.

О, кстати, я утверждаю, что вам нужно представление SQL, но весь SELECT может быть встроен в CFQUERY. Лично, когда у меня есть JOIN с несколькими таблицами, мне нравится определять это в представлении SQL, где оно выполняется быстрее, чем JOIN в CFQUERY. В конечном счете, StoredProc работает еще быстрее, но наше предложение WHERE гораздо удобнее кодировать и читать таким образом, чем отправлять в StoredProc без циклического входа и выхода из SQL.

Хорошая цель - совершить только один переход к базе данных и обратно, если это возможно. Вот почему мы зациклились на массиве, чтобы записать строку, соответствующую всем значениям в наборе данных. Таким образом, мы выполним только один запрос, один раз.

SELECT Col1, Col2, Col_etc
FROM SQL_View_Name
WHERE ColumnName in #BigStringWeMadeFromArrayToList#

когда наш CFQUERY будет обработан, предложение будет выглядеть в SQL так:

WHERE ColumnName in 
     ('ValueOfArrayElement1','ValueOfArrayElement2','Value_And_So_On')

Итак, у вас есть это. Как я уже сказал, это хорошо, потому что это делает только одно обращение к БД, и, поскольку мы создаем представление, производительность все равно будет довольно хорошей — лучше, чем запуск StoredProc 4+ раза. (не обижайся)

Я должен повторить... не видя кода SP, я не уверен, что это выполнимо. Кроме того, довольно странно отказываться от StoredProc для представления SQL, «меньшего» объекта в СУБД, но я уверен, что мы добьемся большей производительности, и я думаю, что это также довольно читабельно.

person Chris Adragna    schedule 25.09.2010