PCB MS SQL 標量函式(CLR) 實現轉Json方法
阿新 • • 發佈:2018-12-15
一.準備需轉為json的資料
在資料庫中執行一段SQL返回的資料
需轉換後的JSON字串的效果
[{"TechName":"開料","ItemName":"綜合利用率是否為最高","ItemPara":"/"},{"TechName":"開料","ItemName":"綜合利用率","ItemPara":"68.36"},{"TechName":"開料","ItemName":"緯向餘料","ItemPara":"0"},{"TechName":"開料","ItemName":"經向餘料","ItemPara":"0"},{"TechName":"開料","ItemName":"是否為小交貨面積拼板","ItemPara":"n"},{"TechName":"開料","ItemName":"緯向尺寸","ItemPara":"24"},{"TechName":"開料","ItemName":"是否為陰陽銅結構","ItemPara":"N"},{"TechName":"開料","ItemName":"是否橫豎開料","ItemPara":"N"},{"TechName":"開料","ItemName":"生產尺寸長","ItemPara":"24"},{"TechName":"開料","ItemName":"生產尺寸寬","ItemPara":"18"},{"TechName":"開料","ItemName":"拼板利用率","ItemPara":"68.36"},{"TechName":"開料","ItemName":"開料圖紙","ItemPara":"/"},{"TechName":"開料","ItemName":"是否顧客指定板材","ItemPara":"N"},{"TechName":"開料","ItemName":"開料數","ItemPara":"4"},{"TechName":"開料","ItemName":"大料經向尺寸","ItemPara":"36"},{"TechName":"開料","ItemName":"大料緯向尺寸","ItemPara":"48"},{"TechName":"開料","ItemName":"成品尺寸長","ItemPara":"12"},{"TechName":"開料","ItemName":"成品尺寸寬","ItemPara":"13.5"},{"TechName":"開料","ItemName":"是否為PTFE板材","ItemPara":"N"},{"TechName":"開料","ItemName":"交貨拼板個數","ItemPara":"1"},{"TechName":"開料","ItemName":"生產拼板個數","ItemPara":"1176"},{"TechName":"開料","ItemName":"交貨單位","ItemPara":"U"},{"TechName":"開料","ItemName":"是否為凹蝕板材","ItemPara":"N"}]
二.C#寫SQL SERVER(CLR)轉JSON函式
先執行SQL返回DataTable,接著再將DataTable轉為Json, 這裡轉為Json有2種方法,程式碼都貼在下方了
/// <summary> /// 執行SQL語句 返回的DataTable 轉為 Json /// </summary> /// <param name="StrSQL"></param> /// <returns></returns>View Code[Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read)] public static string ExecSQL2Json(string StrSQL) { DataTable dt = getDataTable(StrSQL); //return DataTable2Json(dt); //方法1 轉為 Json if (dt is null) returnnull; List<Dictionary<string, object>> list = new List<Dictionary<string, object>>(); foreach (DataRow dr in dt.Rows) { Dictionary<string, object> result = new Dictionary<string, object>(); foreach (DataColumn dc in dt.Columns) { result.Add(dc.ColumnName, dr[dc].ToString()); } list.Add(result); } return Json.Serialize(list);//方法2 轉為 Json } /// <summary> /// 執行SQL獲取DataTable /// </summary> /// <param name="StrSQL"></param> /// <returns></returns> private static DataTable getDataTable(string StrSQL) { DataTable dt = new DataTable(); try { using (SqlConnection cn = new SqlConnection("context connection=true")) { using (SqlDataAdapter da = new SqlDataAdapter(StrSQL, cn)) { DataSet ds = new DataSet(); da.Fill(ds, "tab"); dt = ds.Tables["tab"]; } } } catch (Exception ex) { throw; } return dt; }
方法一:DataTable轉Json
/// <summary> /// DataTable轉Json /// </summary> /// <param name="table"></param> /// <returns></returns> public static string DataTable2Json(DataTable table) { var JsonString = new StringBuilder(); if (table.Rows.Count > 0) { JsonString.Append("["); for (int i = 0; i < table.Rows.Count; i++) { JsonString.Append("{"); for (int j = 0; j < table.Columns.Count; j++) { object ValueNull = table.Rows[i][j]; if (ValueNull == DBNull.Value) { JsonString.Append("\"" + table.Columns[j].ColumnName.ToString() + "\":null" + ((j < table.Columns.Count - 1) ? "," : "")); } else { string Value = table.Rows[i][j].ToString(); if (table.Columns[j].DataType == typeof(string) || table.Columns[j].DataType == typeof(DateTime) || table.Columns[j].DataType == typeof(Guid)) { JsonString.Append("\"" + table.Columns[j].ColumnName.ToString() + "\":" + "\"" + Value + "\"" + ((j < table.Columns.Count - 1) ? "," : "")); } else { if (table.Columns[j].DataType == typeof(bool)) Value = Value.ToLower(); JsonString.Append("\"" + table.Columns[j].ColumnName.ToString() + "\":" + Value + ((j < table.Columns.Count - 1) ? "," : "")); } } } JsonString.Append("}" + ((i < table.Rows.Count - 1) ? "," : "")); } JsonString.Append("]"); } return JsonString.ToString(); }View Code
方法二: 開源MiniJSON類解析Json字串
using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace SQLClr { /// <summary> /// This class encodes and decodes JSON strings. /// Spec. details, see http://www.json.org/ /// /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary. /// All numbers are parsed to doubles. /// </summary> public static class Json { /// <summary> /// Parses the string json into a value /// </summary> /// <param name="json">A JSON string.</param> /// <returns>An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false</returns> //反序列化 public static object Deserialize(string json) { // save the string for debug information if (json == null) { return null; } return Parser.Parse(json); } //阻止其他類從該類繼承 sealed class Parser : IDisposable { const string WORD_BREAK = "{}[],:\""; public static bool IsWordBreak(char c) { // 如果 c 是空白,則為 true;否則,為 false;報告指定 Unicode 字元在此字串中的第一個匹配項的索引。 return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1; } enum TOKEN { NONE, CURLY_OPEN, CURLY_CLOSE, SQUARED_OPEN, SQUARED_CLOSE, COLON, COMMA, STRING, NUMBER, TRUE, FALSE, NULL }; // 實現從字串進行讀取的 System.IO.TextReader。 StringReader json; Parser(string jsonString) { json = new StringReader(jsonString); } public static object Parse(string jsonString) { using (var instance = new Parser(jsonString)) { return instance.ParseValue(); } } //釋放 public void Dispose() { json.Dispose(); json = null; } Dictionary<string, object> ParseObject() { Dictionary<string, object> table = new Dictionary<string, object>(); // ditch opening brace json.Read(); // { while (true) { switch (NextToken) { case TOKEN.NONE: return null; case TOKEN.COMMA: continue; case TOKEN.CURLY_CLOSE: return table; default: // name string name = ParseString(); if (name == null) { return null; } // : if (NextToken != TOKEN.COLON) { return null; } // ditch the colon json.Read(); // value table[name] = ParseValue(); break; } } } List<object> ParseArray() { List<object> array = new List<object>(); // ditch opening bracket json.Read(); // [ bool parsing = true; while (parsing) { TOKEN nextToken = NextToken; switch (nextToken) { case TOKEN.NONE: return null; case TOKEN.COMMA: continue; case TOKEN.SQUARED_CLOSE: parsing = false; break; default: object value = ParseByToken(nextToken); array.Add(value); break; } } return array; } object ParseValue() { TOKEN nextToken = NextToken; return ParseByToken(nextToken); } object ParseByToken(TOKEN token) { switch (token) { case TOKEN.STRING: return ParseString(); case TOKEN.NUMBER: return ParseNumber(); case TOKEN.CURLY_OPEN: return ParseObject(); case TOKEN.SQUARED_OPEN: return ParseArray(); case TOKEN.TRUE: return true; case TOKEN.FALSE: return false; case TOKEN.NULL: return null; default: return null; } } string ParseString() { StringBuilder s = new StringBuilder(); char c; // ditch opening quote json.Read(); bool parsing = true; while (parsing) { if (json.Peek() == -1) { parsing = false; break; } c = NextChar; switch (c) { case '"': parsing = false; break; case '\\': if (json.Peek() == -1) { parsing = false; break; } c = NextChar; switch (c) { case '"': case '\\': case '/': s.Append(c); break; case 'b': s.Append('\b'); break; case 'f': s.Append('\f'); break; case 'n': s.Append('\n'); break; case 'r': s.Append('\r'); break; case 't': s.Append('\t'); break; case 'u': var hex = new char[4]; for (int i = 0; i < 4; i++) { hex[i] = NextChar; } s.Append((char)Convert.ToInt32(new string(hex), 16)); break; } break; default: s.Append(c); break; } } return s.ToString(); } object ParseNumber() { string number = NextWord; // 摘要: // 報告指定 Unicode 字元在此字串中的第一個匹配項的索引。 // // 引數: // value: // 要查詢的 Unicode 字元。 // // 返回結果: // 如果找到該字元,則為 value 的從零開始的索引位置;如果未找到,則為 -1。 if (number.IndexOf('.') == -1) { long parsedInt; // 將數字的字串表示形式轉換為它的等效 64 位有符號整數。一個指示轉換是否成功的返回值。 Int64.TryParse(number, out parsedInt); return parsedInt; } double parsedDouble; Double.TryParse(number, out parsedDouble); return parsedDouble; } // void EatWhitespace() { //指示指定字串中位於指定位置處的字元是否屬於空白類別。 while (Char.IsWhiteSpace(PeekChar)) { json.Read(); //摘要: // 返回下一個可用的字元,但不使用它。 // // 返回結果: // 表示下一個要讀取的字元的整數,或者,如果沒有更多的可用字元或該流不支援查詢,則為 -1。 if (json.Peek() == -1) { break; } } } char PeekChar { get { // 讀取輸入字串中的下一個字元並將該字元的位置提升一個字元。 // // 返回結果: // 基礎字串中的下一個字元,或者如果沒有更多的可用字元,則為 -1。 return Convert.ToChar(json.Peek()); } } char NextChar { get { return Convert.ToChar(json.Read()); } } string NextWord { get { // 表示可變字元字串。無法繼承此類。 StringBuilder word = new StringBuilder(); while (!IsWordBreak(PeekChar)) { // 摘要: // 在此例項的結尾追加指定 Unicode 字元的字串表示形式。 // // 引數: // value: // 要追加的 Unicode 字元。 // // 返回結果: // 完成追加操作後對此例項的引用。 word.Append(NextChar); //下一個字元為空 if (json.Peek() == -1) { break; } } // return word.ToString(); } } TOKEN NextToken { get { EatWhitespace(); if (json.Peek() == -1) { return TOKEN.NONE; } switch (PeekChar) { case '{': return TOKEN.CURLY_OPEN; case '}': json.Read(); return TOKEN.CURLY_CLOSE; case '[': return TOKEN.SQUARED_OPEN; case ']': json.Read(); return TOKEN.SQUARED_CLOSE; case ',': json.Read(); return TOKEN.COMMA; case '"': return TOKEN.STRING; case ':': return TOKEN.COLON; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': return TOKEN.NUMBER; } switch (NextWord) { case "false": return TOKEN.FALSE; case "true": return TOKEN.TRUE; case "null": return TOKEN.NULL; } return TOKEN.NONE; } } } /// <summary> /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string /// </summary> /// <param name="json">A Dictionary<string, object> / List<object></param> /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns> public static string Serialize(object obj) { return Serializer.Serialize(obj); } sealed class Serializer { StringBuilder builder; Serializer() { //建立生成器 builder = new StringBuilder(); } //序列化 public static string Serialize(object obj) { var instance = new Serializer(); instance.SerializeValue(obj); return instance.builder.ToString(); } //型別 void SerializeValue(object value) { IList asList; IDictionary asDict; string asStr; if (value == null) { builder.Append("null"); } else if ((asStr = value as string) != null) { SerializeString(asStr); } else if (value is bool) { builder.Append((bool)value ? "true" : "false"); } else if ((asList = value as IList) != null) { SerializeArray(asList); } else if ((asDict = value as IDictionary) != null) { SerializeObject(asDict); } else if (value is char) { SerializeString(new string((char)value, 1)); } else { SerializeOther(value); } } //序列化物件 void SerializeObject(IDictionary obj) { bool first = true; builder.Append('{'); foreach (object e in obj.Keys) { if (!first) { builder.Append(','); } SerializeString(e.ToString()); builder.Append(':'); SerializeValue(obj[e]); first = false; } builder.Append('}'); } // 序列化陣列 void SerializeArray(IList anArray) { builder.Append('['); bool first = true; foreach (object obj in anArray) { if (!first) { builder.Append(','); } SerializeValue(obj); first = false; } builder.Append(']'); } //string void SerializeString(string str) { builder.Append('\"'); char[] charArray = str.ToCharArray(); foreach (var c in charArray) { switch (c) { case '"': builder.Append("\\\""); break; case '\\': builder.Append("\\\\"); break; case '\b': builder.Append("\\b"); break; case '\f': builder.Append("\\f"); break; case '\n': builder.Append("\\n"); break; case '\r': builder.Append("\\r"); break; case '\t': builder.Append("\\t"); break; default: int codepoint = Convert.ToInt32(c); if ((codepoint >= 32) && (codepoint <= 126)) { builder.Append(c); } else { //builder.Append("\\u"); //builder.Append(codepoint.ToString("x4")); builder.Append(c); } break; } } builder.Append('\"'); } //其他 void SerializeOther(object value) { // NOTE: decimals lose precision during serialization. // They always have, I'm just letting you know. // Previously floats and doubles lost precision too. //注意:小數在序列化過程中丟失精度。 //他們總是有,我只是讓你知道。 //以前失去精度和雙精度浮點數。 if (value is float) { builder.Append(((float)value).ToString("R")); } else if (value is int || value is uint || value is long || value is sbyte || value is byte || value is short || value is ushort || value is ulong) { builder.Append(value); } else if (value is double || value is decimal) { builder.Append(Convert.ToDouble(value).ToString("R")); } else { SerializeString(value.ToString()); } } } } }View Code
三.SQL伺服器CLR配置(允許SQL呼叫.net程式)
sp_configure 'show advanced options', 1; RECONFIGURE WITH override GO sp_configure 'clr enabled', 1; RECONFIGURE WITH override GO Sp_changedbowner 'sa',true --sa改為當前登入使用者名稱 alter database [dbname] set trustworthy on --bbname 改為自己的庫名
四.註冊 CLR 程式集
create ASSEMBLY SQLfunctionAssembly FROM 'D:\SQLClr.dll' --改為自己C#寫的dll路徑填寫 WITH PERMISSION_SET = UNSAFE;
建立的.net程式集資料會寫入下表:
select * from sys.assemblies select * from sys.assembly_files
五.建立標量函式
create FUNCTION [dbo].[ExecSQL2Json](@StrSQL [nvarchar](max)) RETURNS [nvarchar](max) WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLfunctionAssembly].[SQLClr.SQLfunction].[ExecSQL2Json]
六.測試轉Json函式
DECLARE @SQL VARCHAR(MAX) SET @SQL = 'SELECT TechName,ItemName,ItemPara FROM FP_EMS_DB.dbo.V_ppegeneral WHERE pdctno = ''2V011Z30A4'' AND TechNo = ''CC_01'' ORDER BY ItemNo ' SELECT dbo.ExecSQL2Json(@SQL)
執行後結果
七.小結
採用CLR方式寫SQL SERVER函式轉為json字串,那麼只要傳入一段SQL語句就可以轉為Json字串,是不是很方便,但這種作法在實際應用中作用不太大,因為業務系統現在基本採用ORM 物件關係對映模型開發,資料庫表對映成物件,直接操作的物件,然而物件轉為json放在應用程式端轉換是及為方便的,在這裡只開拓一種新思路在資料庫中實現轉json的方法。