【进阶版】MSSQL - 仓位的标识【动态】获取仓位名称

栏目:云星空知识作者:金蝶来源:金蝶云社区发布:2024-09-16浏览:1

【进阶版】MSSQL - 仓位的标识【动态】获取仓位名称

# 简介 我最初想着从 **==函数==** 动态获取仓位名称,但是运行函数提示运算符EXECUTE STRING 无效,在function中不能使用exec和sp_executesql。 所以做了一个获取仓位名称的 **==存储过程==** **传送门:[MSSQL - 仓位的标识【动态】获取仓位名称](https://wenku.my7c.com/article/483211870225238784?productLineId=1)** 但是使用存储过程局限性较大,无法直接在查询中调用,为了解决这个问题决定使用 **CLR 用户定义函数 ** 来实现 # 配置 SQL Server CLR ``` SQL ---开启所有服务器配置选项 EXEC sp_configure N'show advanced options', N'1'; RECONFIGURE WITH OVERRIDE ``` ``` SQL --开启clr enabled 选项 EXEC sp_configure N'clr enabled', N'1' RECONFIGURE WITH OVERRIDE ``` ``` SQL --关闭所有服务器配置选项 EXEC sp_configure N'show advanced options', N'0' RECONFIGURE WITH OVERRIDE ``` ## 假如存在权限异常 **如果存在权限问题,执行下面一段脚本** ``` sql ALTER DATABASE 数据库名 SET TRUSTWORTHY ON EXEC sp_changedbowner 'sa' ``` # 创建CLR函数 VS2022 ## 1. 创建一个数据库项目 ![1693025128701.webp](/download/01007f11ebb26efb49ab82381b5fcc7dd93e.webp) ## 2. 新建一个用户自定义函数 ![image.webp](/download/0100867762b001d64957a220c8d770a75124.webp) ## 3. 根据上一篇文章存储过程改为 C# 代码 ``` C# [Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read)] public static SqlString ScalarFunction(SqlInt32 FSTOCKID, SqlInt32 FSTOCKLOCID) { using (SqlConnection conn = new SqlConnection("context connection=true")) { conn.Open(); DataTable T_BD_STOCKFLEXITEM = new DataTable(); string Str = $"SELECT FSEQ, T31.FFLEXNUMBER FROM T_BD_STOCKFLEXITEM T1 INNER JOIN T_BAS_FLEXVALUES T31 ON T1.FFLEXID = T31.FID WHERE FSTOCKID = {FSTOCKID} "; SqlCommand cmd = new SqlCommand(Str, conn); var edr = cmd.ExecuteReader(); DataTable schemaTable = edr.GetSchemaTable(); try { //动态构建表,添加列 foreach (DataRow dr in schemaTable.Rows) { DataColumn dc = new DataColumn(); //设置列的数据类型 dc.DataType = dr[0].GetType(); //设置列的名称 dc.ColumnName = dr[0].ToString(); //将该列添加进构造的表中 T_BD_STOCKFLEXITEM.Columns.Add(dc); } if (edr.HasRows) { //读取数据添加进表中 while (edr.Read()) { DataRow row = T_BD_STOCKFLEXITEM.NewRow(); //填充一行数据 for (int i = 0; i < schemaTable.Rows.Count; i++) { row[i] = edr[i].ToString(); } T_BD_STOCKFLEXITEM.Rows.Add(row); row = null; } edr.Close(); schemaTable = null; } } catch (Exception ex) { if (!edr.IsClosed) { edr.Close(); }; //抛出异常 throw new Exception(ex.Message); } string ReturnStr = ""; if (T_BD_STOCKFLEXITEM != null&& T_BD_STOCKFLEXITEM.Rows.Count>0) { foreach (DataRow item in T_BD_STOCKFLEXITEM.Rows) { string FFLEXNUMBER_SQL = $"SELECT V{item["FFLEXNUMBER"].ToString()}.FNAME FROM T_BAS_FLEXVALUESDETAIL FVD LEFT JOIN T_BAS_FLEXVALUESENTRY_L AS V{item["FFLEXNUMBER"].ToString()} ON FVD.{item["FFLEXNUMBER"].ToString()}=V{item["FFLEXNUMBER"].ToString()}.FENTRYID AND V{item["FFLEXNUMBER"].ToString()}.FLOCALEID = 2052 WHERE FID={FSTOCKLOCID}"; cmd = new SqlCommand(FFLEXNUMBER_SQL, conn); string OutPutStr = (string) cmd.ExecuteScalar(); if (!string.IsNullOrEmpty(OutPutStr)) { ReturnStr = $"{ReturnStr}.{OutPutStr}"; } } } return ReturnStr.Trim('.'); } return new SqlString("获取失败"); } ``` # 注册 CLR 程序集 ## 注册CLR程序集方式一,指定程序集DLL的路径 ``` sql --注册CLR程序集方式一,指定程序集DLL的路径 CREATE ASSEMBLY UserDefinedClrAssembly --AUTHORIZATION sa --指定数据库所有者,默认为当前用户 FROM 'D:\项目\SQLSERVER.CLR.ScalarFunction\bin\Debug\SQLSERVER.CLR.ScalarFunction.dll' --指定文件路径 WITH PERMISSION_SET = UNSAFE; --指定程序集的权限 --SAFE:无法访问外部系统资源; --EXTERNAL_ACCESS:可以访问某些外部系统资源; --UNSAFE:可以不受限制的访问外部系统资源 GO ``` ## 注册CLR程序集方式二,指定程序集DLL的16进制文件流 **==第二种,这种方式注册程序集稍微复杂一些,但是好处就是注册成功之后,可以移动甚至删除DLL文件,只要不是变更迁移数据库,都不用重新注册。==** ``` sql --注册CLR程序集方式二,指定程序集DLL的16进制文件流 CREATE ASSEMBLY [SQLSERVER.CLR.ScalarFunction] AUTHORIZATION [dbo] FROM 0x4D5A9000030000000400000--.....此处省略数据太长 WITH PERMISSION_SET = UNSAFE ``` ## 从VS获取注册程序集代码【方式二】 ![image.webp](/download/01002940896bd4634c179883353f5eadbe08.webp) # 注册、删除 标值函数/程序集 ``` sql --注册标值函数 CREATE FUNCTION [dbo].Mindee_CLR_GetFStockLOCName (@FSTOCKID [int], @FSTOCKLOCID [int]) RETURNS [nvarchar](MAX) AS EXTERNAL NAME [SQLSERVER.CLR.ScalarFunction].[UserDefinedFunctions].[ScalarFunction]; GO --删除标量函数 Mindee_CLR_GetFStockLOCName DROP FUNCTION dbo.Mindee_CLR_GetFStockLOCName GO --删除程序集 [SQLSERVER.CLR.ScalarFunction] DROP ASSEMBLY [SQLSERVER.CLR.ScalarFunction] GO ``` # 运行测试 ## 测试SQL ``` sql SELECT T1.FBASEQTY AS '库存量(基本单位)', t1.FBASEAVBQTY AS '可用量(基本单位)' ,T3.FNUMBER 物料编码, T3L.FNAME as 物料名称, T4L.FNAME 物料分组名称, T3L.FDESCRIPTION as 物料描述, T3L.FSPECIFICATION AS 规格型号 ,T2L.FNAME as 仓库名称 ,dbo.Mindee_CLR_GetFStockLOCName(T1.FSTOCKID,T1.FSTOCKLOCID) as 仓位名称 --自定义CLR函数 --,T1.FSTOCKID AS 仓库标识 --,T1.FSTOCKLOCID AS 仓位标识 ,T5L.FNAME AS 基本单位 ,T1.FLOT AS 批号基本标识 ,T6L.FNUMBER AS 批号 from T_STK_INVENTORY t1 INNER JOIN t_BD_Stock T2 ON T1.FSTOCKID=T2.FSTOCKID INNER JOIN t_BD_Stock_l T2L ON T1.FSTOCKID=T2L.FSTOCKID and T2L.FLOCALEID=2052 INNER JOIN T_BD_MATERIAL T3 ON T1.FMaterialId = T3.FMasterId AND T1.FSTOCKORGID=T3.FUSEORGID INNER JOIN T_BD_MATERIAL_L T3L ON T3.FMaterialId=T3L.FMaterialId AND T3L.FLOCALEID=2052 LEFT JOIN T_BD_MATERIALGROUP T4 ON T4.FID=T3.FMATERIALGROUP LEFT JOIN T_BD_MATERIALGROUP_L T4L ON T4L.FID=T4.FID AND T4L.FLOCALEID=2052 INNER JOIN T_BD_UNIT_L T5L ON T5L.FUNITID=t1.FBASEUNITID AND T5L.FLOCALEID=2052 LEFT JOIN T_BD_LOTMASTER T6L ON T6L.FLOTID=T1.FLOT WHERE T1.FBASEQTY != 0 ``` ## 效果 ![image.webp](/download/0100c9e236e956224032891e0f48a5ab521c.webp) 完美 ~ # 相关参考连接 [SQL Server CLR 使用 C# 自定义函数](https://www.cnblogs.com/Brambling/p/8000911.html) [CLR 标量值函数](https://learn.microsoft.com/zh-cn/sql/relational-databases/clr-integration-database-objects-user-defined-functions/clr-scalar-valued-functions?view=sql-server-ver16) ___ ==如有错误之处,敬请指正。==

【进阶版】MSSQL - 仓位的标识【动态】获取仓位名称

# 简介我最初想着从 **==函数==** 动态获取仓位名称,但是运行函数提示运算符EXECUTE STRING 无效,在function中不能使用exec和sp_exe...
点击下载文档
确认删除?
回到顶部
客服QQ
  • 客服QQ点击这里给我发消息