如何使用 ColdFusion 2018/Lucee 创建网格输出以显示来自两个查询的数据 5.x

How do I create grid output to display data from two queries using ColdFusion 2018/Lucee 5.x

我有 table 权限、table 角色和映射 table。我想为网站管理员创建一个 GUI,以便能够添加新角色并为该角色分配权限。目前它是在数据库中完成的,因此可能会出现用户错误。

为了简单起见,假设我们有四个角色,SuperAdmin、Admin、Manager 和 User。权限为创建、读取、更新、删除。在下图中,SuperAdmin 和 Admin 与 Manager 和 User 匹配(用户错误的产物,以及为什么我想创建 GUI 但我离题了)。

目前,我的输出为每个角色显示一行,而理想情况下,角色只会显示一次,并且会为相应的权限勾选相应的复选框,类似于以下内容:

这是我的 CF 代码,但我不知道如何处理它来做我想做的事。

<cfquery name="securityGroups" datasource="#application.support#">
Select
    r.roleLabel,
    r.roleID,
    p.permName,
    p.permID
From
    npermissions p Inner Join
    nrole_npermission_map rp On rp.permissionID = p.permID Inner Join
    nroles r On rp.roleID = r.roleID
</cfquery>

<cfquery name="securityPermissions" datasource="#application.support#">
Select
    p.permName,
    p.permID
From
    npermissions p
</cfquery>

<table id="datatables" class="datatables">
    <thead>
        <tr>
            <th>Role</th>
            <cfoutput query="securityPermissions">
                <th>#securityPermissions.permName#</th>
            </cfoutput>
        </tr>
    </thead>
    <tbody>
        <cfoutput query="securityGroups" group="roleID">
            <tr>
                <td>#securityGroups.roleLabel#</td>
                <cfoutput>
                    <td>
                        <input type="checkbox" name="permID" value="#securityPermissions.permID#" <cfif securityGroups.permID eq securityPermissions.permID>checked</cfif> >#securityPermissions.permname# (#securityGroups.permID# eq #securityPermissions.permID#)
                    </td>
                </cfoutput>
            </tr>
        </cfoutput>
    </tbody>
</table>

使用上面的代码,这会产生以下输出,这是我能够获得的最接近我想要的输出。显示了正确的权限,但未选中复选框并且未显示某些权限。

我想我记得几年前在 easycfm 上读过一些关于教程或论坛的内容。

如果源 table 很小,一个简单的方法是将交叉 + 外连接组合到 return 所有可能的值。然后将查询输出“分组”到行中。交叉连接有利于生成“所有组合”,但 table 大小很重要。连接 2 tables,每行 1000 行,每行产生 100 万行!所以大小是一个重要的考虑因素。

<!--- Returns ALL available roles and permissions --->
<cfquery name="qGridData">
   SELECT r.roleID
        , r.RoleLabel
        , p.permName 
        , p.permID
        , ISNULL(m.permissionID, 0) AS AssignedPermID
   FROM nRoles r 
          CROSS JOIN nPermissions p 
          LEFT JOIN nRole_nPermission_Map m 
          ON m.permissionID = p.permID
          AND m.roleID = r.RoleID
   ORDER BY r.RoleLabel, p.PermName       
</cfquery>

<cfquery name="qGridLabels">
   SELECT p.permName 
   FROM   nPermissions p 
   ORDER BY p.PermName        
</cfquery>
 
<table>
   <cfoutput query="qGridData">
     <th>#permName#</th>
   </cfoutput>
</tr>
<cfoutput query="qGridData" group="roleLabel">
   <tr><td>#roleLabel# (id=#roleID#)</td>
       <input type="hidden" name="roleID" value="#roleID#">
       <cfoutput>
         <td><input type="checkbox" name="roleID_permissions_#roleID#" value="#permID#" <cfif AssignedPermID>checked</cfif>> </td>
       </cfoutput>
    </tr>
</cfoutput>
</table>

另一种选择是使用某种枢轴table。在数据方面,它们比第一个选项更紧凑。虽然动态内容不太灵活。我不熟悉应该适用于大多数数据库的 MariaDB implementation of pivot tables, but

SELECT r.RoleID
        , r.RoleLabel
        , MAX(CASE WHEN p.PermName = 'Read' THEN m.PermissionID ELSE 0 END) AS ReadAllowed 
        , MAX(CASE WHEN p.PermName = 'Read' THEN p.PermID ELSE 0 END) AS ReadID 
        , MAX(CASE WHEN p.PermName = 'Create' THEN m.PermissionID ELSE 0 END) AS CreateAllowed 
        , MAX(CASE WHEN p.PermName = 'Create' THEN p.PermID ELSE 0 END) AS CreateID 
        , MAX(CASE WHEN p.PermName = 'Delete' THEN m.PermissionID ELSE 0 END) AS DeleteAllowed 
        , MAX(CASE WHEN p.PermName = 'Delete' THEN p.PermID ELSE 0 END) AS DeleteID 
        , MAX(CASE WHEN p.PermName = 'Update' THEN m.PermissionID ELSE 0 END) AS UpdateAllowed 
        , MAX(CASE WHEN p.PermName = 'Update' THEN p.PermID ELSE 0 END) AS UpdateID 
FROM nRoles r 
          CROSS JOIN nPermissions p 
          LEFT JOIN nRole_nPermission_Map m 
              ON m.permissionID = p.permID
              AND m.roleID = r.RoleID
GROUP BY 
        r.RoleID
        , r.RoleLabel
ORDER BY r.RoleLabel