C# AP 端拋出 SQL Excpetion
該 case 在 Profile 內開啟 Exception 和 User Error Message 就行
Profile 側錄結果
namespace ToLookupSample
{
internal class Program
{
static void Main(string[] args)
{
var books = new List<Book>
{
new Book { Title = "C# 實戰", Category = "CSharp", PublishYear = 2025 },
new Book { Title = "設計模式", Category = "CSharp", PublishYear = 2023 },
new Book { Title = "MS SQL TSQL 學習手冊", Category = "SQL", PublishYear = 2020 },
new Book { Title = "MS SQL 效能調校", Category = "SQL", PublishYear = 2025 },
new Book { Title = "MS SQL 索引深入淺出", Category = "SQL", PublishYear = 2025 },
new Book { Title = "世界歷史", Category = "History", PublishYear = 1981 }
};
// 1. 建立 ILookup:以 Category 為 Key
ILookup<string, Book> bookLookup = books.ToLookup(b => b.Category);
// 2. 透過索引子 [Key] 查詢存在的書籍分類
IEnumerable<Book> sql = bookLookup["SQL"];
Console.WriteLine($"SQL 書籍:{sql.Count()}");
foreach (Book book in sql)
Console.WriteLine($" ----- {book.Title}");
// 3. 查詢不存在的書籍分類:回傳空集合,不會拋出 Exception
IEnumerable<Book> ai = bookLookup["AI"];
Console.WriteLine($"是否有 AI 分類書籍:{ai.Any()}");
// 4. 檢查某個 Key 是否存在
bool hasHistory = bookLookup.Contains("History");
Console.WriteLine($"是否有 History 分類書籍:{hasHistory}");
// 5. 忽略大小寫
ILookup<string, string> books4OrdinalIgnoreCase = books.ToLookup(
keySelector: b => b.Category,
elementSelector: b => b.Title,
comparer: StringComparer.OrdinalIgnoreCase // 忽略大小寫
);
IEnumerable<string> csharp = books4OrdinalIgnoreCase["csharp"];
Console.WriteLine($"C# 書籍 - 不區分大小寫");
foreach (string title in csharp)
Console.WriteLine($" ----- {title}");
// 6. Key 使用 ValueTuple (Category, PublishYear) 作為複合 Key
var booksValueTuple = books.ToLookup(b => (
Category: b.Category,
Year: b.PublishYear
));
var targetKey = ("SQL", 2025);
var matchedBooks = booksValueTuple[targetKey].ToList();
Console.WriteLine($"2005 出版 SQL 書籍 - 複合 Key");
foreach (Book book in matchedBooks)
Console.WriteLine($" ----- {book.Title}");
}
}
public class Book
{
public string Title { get; set; }
public string Category { get; set; }
public int PublishYear { get; set; }
}
}
SELECT
soh.SalesOrderNumber,
soh.OrderDate,
sod.OrderQty,
sod.UnitPrice,
sod.LineTotal,
p.ProductNumber,
p.[Name] AS ProductName
FROM Sales.SalesOrderHeader AS soh
INNER JOIN Sales.SalesOrderDetail AS sod ON soh.SalesOrderID = sod.SalesOrderID
INNER JOIN Production.[Product] AS p ON sod.ProductID = p.ProductID
WHERE soh.SalesOrderID IN (43659 , 75123)
把 List Detail Row 轉為 Group Row
{
"id": "v1_ChdPU0F4YWFtNkFwS2kxZThQZ05lbXdROBIXT1NBeGFhbTZBcEtpMWU4UGdOZW13UTg",
"model": "gemini-3-flash-preview",
"status": "completed",
"object": "interaction",
"created": "2025-11-26T12:25:15Z",
"updated": "2025-11-26T12:25:15Z",
"steps": [
{
"type": "model_output",
"content": [
{
"type": "text",
"text": "I'm doing great, thank you for asking! How can I help you today?"
}
]
}
]
}
code.gs
const GEMINI_MODEL = "gemini-3.8-flash";
/**
* 呼叫 Gemini API
*
* @param {string} prompt 使用者輸入的問題
* @return {string} Gemini 回覆
*/
function askGemini(prompt) {
// 1. 取得 API Key
const apiKey = PropertiesService
.getScriptProperties()
.getProperty("GEMINI_API_KEY");
if (!apiKey) {
throw new Error("找不到 GEMINI_API_KEY,請先設定 Script Properties。");
}
// 2. Gemini API URL
const url = "https://generativelanguage.googleapis.com/v1beta/interactions";
// 3. 要傳給 Gemini 的資料
const payload = {
model: GEMINI_MODEL,
input: prompt
};
// 4. HTTP Request 設定
const options = {
method: "post",
contentType: "application/json",
headers: {
"x-goog-api-key": apiKey
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
// 5. 呼叫 Gemini
const response = UrlFetchApp.fetch(url, options);
// 6. 取得 HTTP Status Code
const statusCode = response.getResponseCode();
// 7. 取得 JSON 字串
const responseText = response.getContentText();
// 8. API 發生錯誤
if (statusCode < 200 || statusCode >= 300) {
throw new Error(
"Gemini API 呼叫失敗\n" +
"HTTP Status: " + statusCode + "\n" +
responseText
);
}
// 9. JSON → JavaScript Object
const data = JSON.parse(responseText);
// 10. 取得 Gemini 回覆文字
const result = getGeminiText(data);
return result;
}
/**
* 從 Gemini Interaction Response 取得文字
*/
function getGeminiText(data) {
if (!data.steps) {
throw new Error("Gemini Response 沒有 steps 資料。");
}
let result = [];
data.steps.forEach(step => {
if (step.type !== "model_output") {
return;
}
if (!step.content) {
return;
}
step.content.forEach(content => {
if (content.type === "text" && content.text) {
result.push(content.text);
}
});
});
if (result.length === 0) {
throw new Error("Gemini 沒有回傳文字內容。");
}
return result.join("\n");
}
測試
/**
* 測試 Gemini API
*/
function testGemini() {
const prompt = "請用 100 個字介紹高雄。";
const result = askGemini(prompt);
console.log(result);
}