---
# System prepended metadata

title: MS SQL資料庫使用者屬性 - 結構描述異常問題排除
tags: [SQL, MSSQL]

---

## 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 移除。
