2012-05-14 2 views
0

Я унаследовал сайт coldfusion8, который использует некоторые функции поиска.Как преобразовать строку цикла coldfusion в хранимую процедуру MySQL?

Я пытаюсь хранить стандартизованные запросы базы данных в хранимых процедурах. Так как я новичок на обоих Coldfusion и MySQL я теперь интересно, могу ли я сделать это в MySQL:

<cfquery datasource="db" name="find_cats"> 
    SELECT wg.no, wg.type, wg.keywords, wg.lang 
    FROM cats AS wg 
    <cfloop list="searchForm.cats_search_string" delimiters=", " item="tag"> 
     WHERE wg.keywords LIKE <cfqueryparam value='%#tag#%' cfsqltype='cf_sql_varchar'> AND 
    </cfloop> 
    wg.lang = <cfqueryparam value="#Session.lang#" cfsqltype="cf_sql_varchar"> 
</cfquery> 
<cfset cond_cats = "AND (1=2"> 
    <cfoutput query="find_cats"> 
     <!--- check if found category belongs to either AAA or BBB classifcation ---> 
     <cfif wg.type is "AAA"> 
      <cfset cond_cats = cond_cats & " OR categoryID1 = #wg.no#"> 
     </cfif> 
     <cfif wg.typ is "BBB"> 
      <cfset cond_cats = cond_cats & " OR categoryID2 = #wg.no#"> 
     </cfif> 
    </cfoutput> 
    <cfset cond_cats = cond_cats & ")"> 

Поиск может быть либо ключевое слово или индекс (AAA, BBB) на основе. Я все еще пытаюсь понять, что happending, но до сих пор я думаю, что если пользователь вводит строку, как:

string1, string2, string3 string4 

Первая часть петли через четыре строки (разделитель запятая и пробел) и querys базу данных для соответствие ключевых слов. Затем он создает новую переменную cond_cats, которая используется, когда происходит фактический поиск. Я предполагаю, что это заменяет строку поиска, с соответствующими категориями, но я не уверен, что здесь, как и результат будет

AND (1=2 OR category1 = 12345 OR category2 = 88888) 

прилагается к фактическому поисковому запросу.

Мои вопросы:
Есть ли способ в MySQL, чтобы разделить введенную пользователем строку поиска, так что я смог запустить цикл? Вторая часть должна быть параметром хранимой процедуры, не так ли? Если это выполняется перед каждым поиском, должно ли оно быть хранимой процедурой вообще или я должен продолжать использовать запрос базы данных?

Спасибо за ввод!

ответ

1

Из того, что вы описали, я не вижу большой выгоды для его упаковки в хранимой процедуре/функции. Базы данных на самом деле не оптимизированы для обработки строк. В то время как цикл возможен, эквивалентный код sql обычно намного менее изящный. Кроме того, для безопасного использования может потребоваться использование динамического sql (или таблицы temp).

Однако, глядя на ваш код, я считаю, что вы могли бы устранить второй cfloop в целом, используя одно предложение IN (....) вместо того, чтобы строить условия OR. (Эти два эквивалентны.)

Просто измените первый запрос, чтобы получить только категорий для нужных типов, т.е. «AAA» и «BBB».

<cfquery datasource="db" name="find_cats"> 
    SELECT wg.no 
    FROM cats AS wg 
    WHERE wg.lang = <cfqueryparam value="#Session.lang#" cfsqltype="cf_sql_varchar"> 
    AND  wg.type IN ('AAA', 'BBB') 
    AND (1 = 2 
     <cfloop list="#searchForm.cats_search_string#" delimiters=", " item="tag"> 
       OR wg.keywords LIKE <cfqueryparam value='%#tag#%' cfsqltype="cf_sql_varchar"> 
      </cfloop> 
     ) 
</cfquery> 

Затем используйте ValueList для подачи результатов во второй запрос. Возможно, вы даже сможете объединить свои два запроса в один. Но все зависит от сложности вашего поискового запроса.

WHERE categoryID1 IN 
( 
    <cfqueryparam value="#valueList(find_cats.no)#" list="true" ... > 
) 

EDIT: Я думаю, что вы могли использовать Valuelist.Просто добавьте CASE заявления первого запрос, разделяющее значение соответствия на две колонки:

SELECT wg.no 
     , CASE WHEN wg.type = 'AAA' THEN wg.no ELSE NULL END AS ID1Values 
     , CASE WHEN wg.type = 'BBB' THEN wg.no ELSE NULL END AS ID2Values 
... 

Затем создать список значений в каждом столбце:

 <cfset firstList = valueList(find_cats.ID1Values)> 
    <cfset secondList = valueList(find_cats.ID2Values)> 

Наконец использовать эти списки в этой категории запрос.

WHERE 1 = 2 

    <cfif listLen(firstList)> 
     OR categoryID1 IN (<cfqueryparam value="#firstList#" list="true" cfsqltype="cf_sql_integer">) 
    </cfif> 

    <cfif listLen(secondList)> 
     OR categoryID2 IN (<cfqueryparam value="#secondList#" list="true" cfsqltype="cf_sql_integer">) 
    </cfif> 
+0

Спасибо за информацию. Не уверен, что это помогает, но я могу использовать значениеList. – frequent

+0

Ну, это звучит так, будто ваш вопрос был «будет ли это лучше, чем хранимая процедура?» ИМО №. Таким образом, приведенный выше код демонстрирует, как писать cfquery более эффективно * и безопасно * (без всякой конкатенации, то есть динамической sql). Но не стесняйтесь оставлять вопрос открытым какое-то время, чтобы получить другие мнения. – Leigh

+0

Извините. Я не был ясен. На вопрос ответили правильно. В моем примере кода была ошибка, поэтому ваш фрагмент работает для ошибочного кода примера. Проблема в категорииID1 должна быть категорииID1 и cateogryID2. ID1 - это название классификации продуктов для спортивных товаров, ID2 для одежды. Поэтому мне нужно проверить, соответствует ли какое-либо из ключевых слов какой-либо категории в обоих индексах, и возвращать номер категории в каждом индексе (если таковой имеется). Мой пример только опросил ID1, поэтому IN будет работать. Я не нашел способ использовать его с двумя отдельными идентификаторами. Я отредактировал мой вопрос. Еще раз спасибо за ваш вклад! – frequent

0

Я думаю, вам стоит попробовать «Полный текст» в mysql.

+0

Не совсем мой вопрос ... У меня есть полнотекстовый поиск, но, кроме того, существуют более мелкие критерии поиска, как указано выше. Я пытаюсь сделать это хранимой процедурой, поэтому любая помощь в этом будет высоко оценена. Спасибо! – frequent

Смежные вопросы