## SQL資料庫使用者屬性異常
- 在 MSSQL 資料庫中,如果使用者的權限顯示如下圖的黑色方塊(而非勾選),表示該使用者透過其他方式獲得了該權限角色,如使用不同結構備份檔進行復原,且資料庫中有同名使用者,但實際與登入的使用者的SID可能是不同的,而導致無法進行異動和刪除。

- 這個狀況無法直接透過 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,如下顯示:

**步驟 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 移除。