[英]MySQL query which has multiple subqueries, each with different join types
首先,讓我給出一個我的mysql查詢中使用的表之間的關系圖:
(來源: r717.net )
我有一個看起來像這樣的查詢:
SELECT *
FROM `permissions`
WHERE `id` IN (
SELECT pr.perm_id
FROM `user_roles` as ur
LEFT JOIN `permissions_role` as pr
ON ur.role_id = pr.role_id
WHERE ur.user_id = '$userid'
)
OR `id` IN (
SELECT `perm_id`
FROM `permissions_user`
WHERE `user_id` = '$userid'
)
$userid
是當前用戶的用戶表中的id。 我將結果中的權限名稱存儲到一個數組中,該數組表示根據用戶的角色和他/她的ID分配給用戶的所有權限:
<?php
$user_perms = array();
if(mysql_num_rows($query) > 0):
while($result = mysql_fetch_array($query):
$user_perms[] = $result('name');
endwhile;
endif;
?>
print_r($user_perms);
生成一個看起來像這樣的輸出:
Array (
[0] => ACCESS_TELEPHONELIST_PAGE
[1] => ACCESS_VACATIONSCHED_PAGE
[2] => ACCESS_TOURSCHED_PAGE
[3] => ACCESS_WORKSCHED_PAGE
[4] => ACCESS_RESOURCES_LINKS
[5] => ACCESS_PMTOOL_PAGE
[6] => ACCESS_TOOLSTOOL_PAGE
[7] => ACCESS_SHOPTOOLLIST_PAGE
[8] => ACCESS_TOOLINVENTORY_PAGE
[9] => ACCESS_MANAGETOOLLIST_PAGE
[10] => ACCESS_TOOLREPORTS_PAGE
[11] => ACCESS_JOBSLIST_LINKS
[12] => MAIN_TAB_TOOLSTOOL
[13] => ADMIN_TAB_PODMANAGEMENT
[14] => TOOL_TAB_SHOPTOOLLIST
)
我想要做的是也將所有用戶的角色存儲到另一個數組中而不進行第二次查詢。 我以為我需要為子查詢使用別名,所以我嘗試了這個查詢:
SELECT permissions.*, usersroles.role_id
FROM `permissions`
INNER JOIN (
SELECT ur.user_id, pr.perm_id, ur.role_id
FROM `user_roles` as ur
LEFT JOIN `permissions_role` as pr
ON ur.role_id = pr.role_id
WHERE ur.user_id = '$userid'
) AS usersroles ON usersroles.perm_id = permissions.id
INNER JOIN (
SELECT `perm_id`, `user_id`
FROM `permissions_user`
WHERE `user_id` = '$userid'
) AS userperms ON userperms.user_id = usersroles.user_id
AND userperms.perm_id = permissions.id
並使用類似於上面代碼的代碼...
<?php
$user_perms = array();
$user_roles = array();
if(mysql_num_rows($query) > 0):
while($result = mysql_fetch_array($query):
$user_perms = $result('name');
$user_roles = $result('role_id');
endwhile;
endif;
?>
......我收到這個警告:
Warning: mysql_num_rows() expects parameter 1 to be resource, boolean given
但是,我想print_r($user_roles);
並生成如下所示的輸出:
Array (
[0] => administrator
[1] => humanresources
[2] => podmanager
)
任何人都可以告訴我我做錯了什么,或者建議一種更好的方法將我需要的數據從一個查詢轉換為2個數組?
編輯:仔細考慮后,我改變了我的代碼,使用ImreL建議的2個查詢。 生成的代碼可以很好地運行並快速執行。 我編輯了我的答案,以顯示我使用的最終代碼,並添加了支持代碼來演示我如何使用2個查詢。 非常感謝ImreL!
該查詢將需要在用戶加載的每個頁面上運行,並且我們擁有超過30,000個權限和3,000個角色。 我只是非常努力地將我的查詢數量保持在最低限度。 我們還在辦公室的服務器上托管我們的7個站點,服務器似乎無法處理我們生成的流量(遺憾的是我無法控制)
我看到你的意圖是好的,但讓我告訴你:
“查詢數量”不是衡量網站效果的正確方法。
很多時候,2個簡單查詢比1個復雜使用更少的資源。
還有其他方法可以加快您的網站:
最后,我試圖提出查詢以滿足所要求的內容:
select * from (
select ur.role_id, p.*
from user_roles ur
left join permissions_role pr on ur.role_id = pr.role_id
left join permissions p on p.id = pr.perm_id
where ur.user_id = '$userid'
union all
select null as role_id, p.*
from permissions_user pu
join permissions p on p.id = pu.perm_id
where pu.user_id = '$userid'
) sub
group by ifnull(name,role_id) -- group by to eliminate duplicates
但這對性能不利。 使用2個查詢會更好:第1個獲取用戶的所有權限
select p.* from permissions p
join permissions_role pr on pr.perm_id = p.id
join user_roles ur on ur.role_id = pr.role_id and ur.user_id = '$userid'
union
select p.* from permissions p
join permissions_user pu on pu.perm_id = p.id and pu.user_id = '$userid';
和第二個獲得所有角色。
編輯:這是最后的工作查詢。 此外,我認為查看查詢的使用方式可能對其他人有用,因此包含了完整的解釋。
//build the array(s)
$userperms = array();
$userroles = array();
if(isset($_SESSION['userid'])):
//get the userid
$thisuserid = $_SESSION['userid'];
//get the permissions for each of the user's roles
$Cpermissions_role = mysql_query("
SELECT r.type, ur.user_id, pr.perm_id, ur.role_id, p.name
FROM user_roles ur
LEFT JOIN permissions_role pr ON ur.role_id = pr.role_id
LEFT JOIN roles r ON ur.role_id = r.id
LEFT JOIN permissions p ON p.id = pr.perm_id
WHERE ur.user_id = '$userid'") or die(mysql_error());
//get the extra permissions for the user
$Cpermissions_user = mysql_query("
SELECT pu.user_id, pu.perm_id, p.name
FROM permissions_user pu
LEFT JOIN permissions p ON p.id = pu.perm_id
WHERE pu.user_id = '$userid'") or die(mysql_error());
//build an array of the user's roles & an array of the user's permissions
if(mysql_num_rows($Cpermissions_role) > 0):
while($Rpermissions_role = mysql_fetch_array($Cpermissions_role)):
if(empty($userperms)):
$userperms[] = $Rpermissions_role['name'];
elseif(!in_array($Rpermissions_role['name'],$userperms)):
$userperms[] = $Rpermissions_role['name'];
endif;
if(empty($userroles)):
$userroles[] = $Rpermissions_role['type'];
elseif(!in_array($Rpermissions_role['type'],$userroles)):
$userroles[] = $Rpermissions_role['type'];
endif;
endwhile;
endif;
if(mysql_num_rows($Cpermissions_user) > 0):
while($Rpermissions_user = mysql_fetch_array($Cpermissions_user)):
if(empty($userperms)):
$userperms[] = $Rpermissions_user['name'];
elseif(!in_array($Rpermissions_user['name'],$userperms)):
$userperms[] = $Rpermissions_user['name'];
endif;
endwhile;
endif;
endif;
/**
* Determines if the user has permission for the page or parts of page
* @param string $perm the permission constant
* @return boolean true if user has access, false if not
*/
function hasPermission($perm){
global $userperms;
if(empty($userperms)):
return false;
else:
if(is_array($userperms)):
if(in_array($perm,$userperms)):
return true;
else:
return false;
endif;
else:
if($perm == $userperms):
return true;
else:
return false;
endif;
endif;
endif;
}
然后,我使用以下決策聲明:
if(hasPermission("ACCESS_HOME_PAGE")):
//perform circus tricks here
endif;
那么,現在print_r($userperms);
輸出:
Array (
[0] => ACCESS_TELEPHONELIST_PAGE
[1] => ACCESS_VACATIONSCHED_PAGE
[2] => ACCESS_TOURSCHED_PAGE
[3] => ACCESS_WORKSCHED_PAGE
[4] => ACCESS_RESOURCES_LINKS
[5] => ACCESS_PMTOOL_PAGE
[6] => ACCESS_TOOLSTOOL_PAGE
[7] => ACCESS_SHOPTOOLLIST_PAGE
[8] => ACCESS_TOOLINVENTORY_PAGE
[9] => ACCESS_MANAGETOOLLIST_PAGE
[10] => ACCESS_TOOLREPORTS_PAGE
[11] => ACCESS_JOBSLIST_LINKS
[12] => MAIN_TAB_TOOLSTOOL
[13] => ADMIN_TAB_PODMANAGEMENT
[14] => TOOL_TAB_SHOPTOOLLIST
[15] => ACCESS_HOME_PAGE
)
並且, print_r($userroles);
輸出:
Array (
[0] => administrator
[1] => humanresourcees
[2] => podmanager
)
而且,為了徹底,這是我用來訪問php數組的JavaScript:
var js_userperms = new Array();
js_userperms = ["<?php echo join("\", \"", $userperms); ?>"];
並且,jQuery決策聲明:
if(jQuery.inArray("ACCESS_HOME_PAGE", js_userperms) != -1){
//perform circus tricks here
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.