## SQL資料庫使用者屬性異常 - 在 MSSQL 資料庫中,如果使用者的權限顯示如下圖的黑色方塊(而非勾選),表示該使用者透過其他方式獲得了該權限角色,如使用不同結構備份檔進行復原,且資料庫中有同名使用者,但實際與登入的使用者的SID可能是不同的,而導致無法進行異動和刪除。 ![image](https://hackmd.io/_uploads/ryveCT-qke.png) - 這個狀況無法直接透過 GUI 取消,此時若是直接刪除使用者,可能會發生錯誤代碼 15138 或15150 並提示「資料庫主體在資料庫中擁有結構描述且無法卸除」,若為 15150 請直接參考第四種方法的第二部分。 - 以下是可能的原因與解決方法: ## 🔎 可能的原因 1. **使用者是資料庫擁有者(DB Owner)** 如果該使用者是資料庫的擁有者(DB Owner),他會自動擁有該權限,且無法在 GUI 取消。 2. **使用者透過 AD 群組或角色獲得權限** 如果該使用者是某個 Windows 群組(Active Directory 群組)的成員,而該群組被指派該權限,那麼這個權限會繼承下來,導致 GUI 中無法取消。 3. **使用者透過其他角色繼承了權限** 例如使用不同結構資料庫進行還原,且擁有同名使用者。若該使用者被手動加入該角色,則 GUI 可能不允許直接取消,需透過 T-SQL 指令來移除。 4. **Schema擁有者異常,且透過其他方式獲得權限** 此種情況為,使用者是資料庫的擁有者(DB Owner),且使用者透過其他方始取得該權限,可能會導致使用者的擁有權無法被轉移,也無法被刪除,為上述1和2情境混合。 --- ## 解決方法 ### 方法 1:檢查該使用者是否是DB Owner 執行以下 T-SQL,檢查該使用者是否是資料庫的擁有者: ``` SQL SELECT name, owner_sid FROM sys.databases WHERE name = DB_NAME(); ``` 如果 owner_sid 對應到該使用者,則代表該使用者是 dbo,需手動變更擁有者: 解決方式:變更資料庫擁有者 ``` SQL ALTER AUTHORIZATION ON DATABASE::[你的資料庫名稱] TO [新擁有者]; --例如: ALTER AUTHORIZATION ON DATABASE::MyDatabase TO sa; ``` 這樣原本的使用者就不再是 dbo,db_owner 權限也能被移除。 ### 方法 2:檢查該使用者是否透過群組繼承權限 使用以下 SQL 指令檢查該使用者的角色: ``` SQL EXEC sp_helprolemember 'db_owner'; ``` 如果發現該使用者的帳號來自某個群組(例如 DOMAIN\SomeGroup),則需到 Active Directory 或 SQL Server 內移除該群組的 db_owner 權限: ``` SQL ALTER ROLE db_owner DROP MEMBER [DOMAIN\SomeGroup]; ``` ### 方法 3:手動移除 db_owner 權限 如果確定該使用者不應該擁有 db_owner 權限,可以使用以下 SQL 指令: ``` SQL ALTER ROLE db_owner DROP MEMBER [使用者帳號]; ``` 例如: ``` SQL ALTER ROLE db_owner DROP MEMBER [test_user]; ``` ### 方法 4:轉移 Schema 擁有者 通常該狀況資料庫顯示錯誤代碼可能會是 15138,如下顯示: ![image](https://hackmd.io/_uploads/B1WH6T-5Je.png) **步驟 1. 找出該使用者所擁有的 Schema** 執行以下 SQL 語句來查找該使用者擁有的所有結構描述: ``` SQL SELECT s.name AS SchemaName, u.name AS Owner FROM sys.schemas s JOIN sys.database_principals u ON s.principal_id = u.principal_id WHERE u.name = 'test_admin'; ``` **步驟 2. 將 Schema 的擁有者轉移給其他使用者** 執行以下命令,將該 Schema 的擁有者改為其他使用者(例如 dbo): ``` SQL --將db_owner歸還給dbo ALTER AUTHORIZATION ON SCHEMA::[SchemaName] TO [dbo]; ``` 將 [SchemaName] 替換為第 1 步中查到的 Schema 名稱。 如果 test_admin 擁有多個 Schema,則需要對每個 Schema 執行此命令。 **步驟 3. 確保 test_admin 不再擁有其他物件** 執行以下查詢,確認該使用者是否擁有其他資料庫物件: ``` SQL SELECT o.name AS ObjectName, o.type_desc, u.name AS Owner FROM sys.objects o JOIN sys.database_principals u ON o.principal_id = u.principal_id WHERE u.name = 'test_admin'; ``` 如果該使用者仍擁有物件,請將物件的擁有者改為其他使用者(例如 dbo),使用以下命令: ``` SQL ALTER AUTHORIZATION ON OBJECT::[ObjectName] TO [dbo]; 將 [ObjectName] 替換為物件名稱。 ``` **步驟 4. 刪除使用者** 確認使用者不再擁有任何結構描述或物件後,可以安全地刪除該使用者: ``` SQL DROP USER [test_admin]; ``` - 注意事項 - 請謹慎處理資料庫中的擁有者轉移,確保不會影響其他使用者或應用程式的正常運作。 - 如果使用者擁有的結構描述或物件較多,建議先備份資料庫。 --- **⚠️ 如問題仍法解決,請繼續往下:** 當刪除 MSSQL 中的使用者 test_op 時,可能出現錯誤代碼 15150 並提示「無法卸除使用者 dbo」,原因是該使用者與資料庫所有者 (dbo) 關聯,SQL Server 無法刪除資料庫的擁有者。 以下是解決問題的步驟: 1.驗證 test_op 是否為資料庫擁有者 執行以下 SQL 查詢,確認 test_op 是否為該資料庫的擁有者: ``` SQL USE [YourDatabaseName]; GO SELECT name AS DatabaseUserName, suser_sname(owner_sid) AS DatabaseOwner FROM sys.databases WHERE name = db_name(); ``` 檢查 DatabaseOwner 列是否顯示 test_op。 2.將資料庫擁有者改為其他使用者 如果 test_op 是資料庫的擁有者,必須先將資料庫的擁有者更改為其他使用者,例如 sa: ``` SQL USE [master]; GO ALTER AUTHORIZATION ON DATABASE::[YourDatabaseName] TO [sa]; ``` 將 [YourDatabaseName] 替換為目標資料庫的名稱。 執行此命令後,資料庫的擁有者將更改為 sa。 3.確認 test_op 不再是任何物件的擁有者 執行以下查詢,檢查 test_op 是否仍擁有該資料庫中的任何物件: ``` SQL USE [YourDatabaseName]; GO SELECT o.name AS ObjectName, o.type_desc, u.name AS Owner FROM sys.objects o JOIN sys.database_principals u ON o.principal_id = u.principal_id WHERE u.name = 'test_op'; ``` 如果有結果,則需要將這些物件的擁有者更改為其他使用者(例如 dbo): ``` SQL ALTER AUTHORIZATION ON OBJECT::[ObjectName] TO [dbo]; ``` 將 [ObjectName] 替換為物件名稱,並對查詢結果中的每個物件執行此命令。 4.刪除 test_op 使用者 確認 test_op 不再是資料庫的擁有者或任何物件的擁有者後,刪除使用者: ``` SQL USE [YourDatabaseName]; GO DROP USER [test_op]; ``` - 注意事項 - 不可直接刪除 dbo 使用者:dbo 是 SQL Server 的內建帳戶,無法刪除。 - 確認資料庫擁有者正確性:將資料庫擁有者更改為適當的使用者,例如 sa,以確保未來的管理方便。 - 先行備份資料庫:執行重要變更前,建議對資料庫進行備份。 --- ## 總結 若 DB Owner 身分導致問題,需變更資料庫擁有者 (ALTER AUTHORIZATION)。 若使用者是 某個群組的成員,需檢查該群組是否被指派 db_owner,並在 SQL Server 內移除該群組的 db_owner 權限。 若只是單純的 db_owner 角色成員,可以透過 ALTER ROLE db_owner DROP MEMBER 移除。