#mysql #coldfusion #cfquery #cfoutput
#mysql #coldfusion #cfquery #cfoutput
Вопрос:
Я работаю над проектом для нашей бухгалтерии. У меня есть таблица базы данных (MySQL) с кодами главной книги. У нашей компании есть несколько разных офисов, и каждый из этих кодов может применяться к одному или нескольким офисным местоположениям. Каждое местоположение офиса может иметь один или несколько применимых кодов главной книги. Итак, у меня есть отношения «многие ко многим» с таблицей мостов, содержащей code_id
и location_id
. Мой SQL выглядит следующим образом:
SELECT gl.`code_id`, gl.`account_code`, gl.`account_type`, gl.`account_desc`, glloc.`location_id`
FROM `gl_codes` as gl
LEFT JOIN `gl_codes_locations` as glloc
ON gl.`code_id` = glloc.`code_id`
ORDER BY gl.`code_id`, glloc.`location_id`
В результате получается таблица с отдельной строкой для каждой code_id
/ location_id
пары. Я хочу отобразить это в таблице, используя cfoutput
. Мне нужна только одна строка для каждого code_id
, но я буду использовать столбец в каждой строке, чтобы отметить, применим ли этот код к данному location_id
, например:
| CodeAccount | CodeType | CodeDescription | Code Location |
| | | | 1 | 2 | 3 | 4 |
|SomeAcct | SomeCode | Some Desc | X | | X | |
Я знаю, что я не могу вложить cfoutput
теги с несколькими query
атрибутами. Я пробовал некоторую группировку, но, похоже, не могу понять это правильно. Пожалуйста, помогите!
Комментарии:
1. Пожалуйста, отредактируйте свой вопрос, чтобы показать, что вы пробовали с группировкой и что произошло, когда вы попробовали это.
Ответ №1:
Это должно подвести вас довольно близко. Сначала нам нужен список доступных идентификаторов, чтобы мы знали, сколько вложенных столбцов местоположения нам нужно.
<cfquery name="locationData">
SELECT location_id FROM gl_codes_locations ORDER BY location_id
</cfquery>
<cfset allLocationIds = ValueList(locationData.location_id)>
Затем внутри таблицы мы можем создать заголовок и тело, используя эту информацию:
<thead>
<tr>
<td>Code ID</td>
<td>Code Account</td>
<td>Code Type</td>
<td>Code Description</td>
<td colspan="#ListLen(allLocationIds)#">Code Location</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<cfloop list="#allLocationIds#" index="id">
<td>#HtmlEditFormat(id)#</td>
</cfloop>
</tr>
</thead>
<tbody>
<cfoutput query="ledgerData" group="code_id">
<cfset currLocationIds = "">
<cfoutput>
<cfset currLocationIds = ListAppend(currLocationIds, location_id)>
</cfoutput>
<tr>
<td>#HtmlEditFormat(code_id)#</td>
<td>#HtmlEditFormat(account_code)#</td>
<td>#HtmlEditFormat(account_type)#</td>
<td>#HtmlEditFormat(account_desc)#</td>
<cfloop list="#allLocationIds#" index="id">
<td>#ListFind(currLocationIds, id) gt 0 ? 'X' : ''#</td>
</cfloop>
</tr>
</cfoutput>
</cfoutput>
Ответ №2:
Благодаря @Tomalac и его ValueList
предложению я смог адаптировать это к своему коду и заставить его работать так, как я хотел. Подсказка по вложенным столбцам отличная, и я могу реализовать ее в будущем, но сейчас мы имеем дело с фиксированным количеством местоположений.
Для справки, соответствующий завершенный код выглядит следующим образом. Я отредактировал имена местоположений по соображениям конфиденциальности.
<table class="table table-striped table-bordered">
<thead class="bg-nav text-white">
<tr>
<th scope="col" rowspan="2" class="align-middle">Code</th>
<th scope="col" rowspan="2" class="align-middle">Type</th>
<th scope="col" rowspan="2" class="align-middle">Description</th>
<th scope="col" colspan="4" class="text-center">Applies To</th>
<th scope="col" rowspan="2" class="text-center align-middle">Edit</th>
<th scope="col" rowspan="2" class="text-center align-middle">Delete</th>
</tr>
<tr>
<th scope="col">Chicago</th>
<th scope="col">Detroit</th>
<th scope="col">LA</th>
<th scope="col">New York</th>
</tr>
</thead>
<tbody>
<cfoutput query="codes" group="code_id">
<tr>
<!--- Use function in cfcomponent to grab the location(s) that pertain to the given code_id --->
<!--- Dump query results into ValueList --->
<cfset codeLocations = ValueList(createObject("component", "com.modules.glcodes").getCodeLocations("query", codes.code_id).location_id)>
<td>#account_code#</td>
<td>#account_type#</td>
<td>#account_desc#</td>
<td><cfif ListLen(codeLocations) GT 0 AND (ListContains(codeLocations, "3") GT 0)>X</cfif></td>
<td><cfif ListLen(codeLocations) GT 0 AND (ListContains(codeLocations, "2") GT 0)>X</cfif></td>
<td><cfif ListLen(codeLocations) GT 0 AND (ListContains(codeLocations, "4") GT 0)>X</cfif></td>
<td><cfif ListLen(codeLocations) GT 0 AND (ListContains(codeLocations, "1") GT 0)>X</cfif></td>
<td>Edit</td>
<td>Delete</td>
</tr>
</cfoutput>
</tbody>
</table>
Комментарии:
1. Если вы вообще можете этого избежать, не нажимайте на сервер базы данных один раз на строку таблицы. Создайте запрос, содержащий все данные для всей таблицы.
2. @Tomalak это действительно хороший момент, о котором я не подумал. Было бы лучше выполнить «главный» запрос, а затем запрос запросов для создания списка значений?
3. Все, что позволяет избежать попадания в базу данных, улучшит производительность страницы. Вы уже группируете
codes
запрос поcode_id
, поэтому с внутренним<cfoutput>
, как я, вы должны получать нужные вам идентификаторы.4.
<cfoutput>
не может быть вложенным, если не сгруппирован. При группировании внутренняя<cfoutput>
выполняется один раз для каждого элемента в группе, а внешняя выполняется один раз для каждой группы. Это работает как механика «группа / заголовок группы / сведения о группе / нижний колонтитул группы» в Crystal Reports, если вы это знаете. Таким образом вы можете настроить несколько уровней группировки, но вам всегда нужно предварительно отсортировать поля вашей группы, т. Е. ColdFusion запустит новую группу при изменении значения поля группы.5. Кроме того, используйте ListFind() / ListFindNoCase() — не ListContains . Последний выполняет поиск подстроки вместо целого значения. trycf.com/gist/27e4d8d276aed791c128986a56ba30c5 /…