提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
翻译|使用教程|编辑:鲍佳佳|2020-09-01 14:16:14.100|阅读 207 次
概述:在本文中,我们将主要集中于对数据库中的存储过程进行单元测试,并举例说明使用dbForge单元测试工具进行单元测试有多么简单。
# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>
相关链接:
dbForge Studio for SQL Server为有效的探索、分析SQL Server数据库中的大型数据集提供全面的解决方案,并设计各种报表以帮助作出合理的决策。(为庆祝双节来袭现dbForge Studio for SQL Server正版授权低至 1710元!包含多种授权方式供你选择。)
点击下载dbForge Studio for SQL Server最新试用版
单元测试是数据库DevOps流程的重要组成部分。其主要目标是测试数据库对象的组成部分,以便在项目早期发现任何故障或缺陷。这种方法使数据库开发人员可以确保验证他们所做的更改,并且项目将正常运行。在本文中,我们将主要集中于对数据库中的存储过程进行单元测试,并举例说明使用dbForge单元测试工具进行单元测试有多么简单。
之前,我们讨论了为招聘服务创建SQL Server数据库的过程。
图1。招聘服务的数据库架构
如上所示,数据库包含以下实体:
但是,在系列文章中,我们以某种方式忽略了单元测试的关键方面。因此,现在,我建议我们仔细研究此方法,并通过为基于某些技能的员工搜索实现SearchEmployee存储过程来举例说明。为了确保数据完整性,我们应该在Skill表上添加唯一约束,如下所示:
ALTER TABLE [dbo].[Skill] ADD CONSTRAINT UniqueSkillName UNIQUE (SkillName);
但是,在执行此操作之前,请使用以下查询确保SkillName字段中的数据不包含任何重复的条目:
SELECT [SkillName] FROM [JobEmpl].[dbo].[Skill] GROUP BY [SkillName] HAVING COUNT(*) > 1;
假设您有重复的条目,则需要将所有记录标准化为SkillName字段相对于彼此的唯一值。
这一步骤中我们在技能名称中创建了唯一性约束。现在,是时候实现SearchEmployee存储过程了,如下所示:
CREATE PROCEDURE [dbo].[SearchEmployee] @SkillList NVARCHAR(MAX), @CountNotSkill INT = 1 AS BEGIN SET NOCOUNT ON; DECLARE @count_skills INT; SELECT [value] INTO #tbl_skill_tmp FROM STRING_SPLIT(@SkillList, N';'); SELECT s.[SkillID] ,s.[SkillName] INTO #tbl_skill FROM #tbl_skill_tmp AS tt INNER JOIN [dbo].[Skill] AS s ON s.[SkillName] = tt.[value]; SET @count_skills = (SELECT COUNT(*) FROM #tbl_skill); SELECT jh.* ,p.[ProjectName] ,p.[Description] AS [ProjectDescription] ,ts.* INTO #tbl_res0 FROM [dbo].[JobHistory] AS jh INNER JOIN [dbo].[Project] AS p ON p.[ProjectID] = jh.[ProjectID] INNER JOIN [dbo].[ProjectSkill] AS ps ON ps.[ProjectID] = p.[ProjectID] INNER JOIN #tbl_skill AS ts ON ps.[SkillID] = ts.[SkillID]; SELECT [EmployeeID] ,[SkillID] ,MIN([SkillName]) AS [SkillName] ,SUM(DATEDIFF(DAY, [StartDate], COALESCE([FinishDate], GETDATE()))) AS [Days] ,MIN([StartDate]) AS [StartDate] ,MAX(COALESCE([FinishDate], GETDATE())) AS [FinishDate] INTO #tbl_res FROM #tbl_res0 GROUP BY [SkillID] ,[EmployeeID]; SELECT emp.[EmployeeID] ,emp.[LastName] ,emp.[FirstName] ,r.[SkillID] ,r.[SkillName] ,r.[StartDate] ,r.[FinishDate] ,r.[Days] / 365 AS [Years] ,(r.[Days] - (r.[Days] / 365) * 365) / 30 AS [Months] ,r.[Days] - (r.[Days] / 365) * 365 - ((r.[Days] - (r.[Days] / 365) * 365) / 30) * 30 AS [Days] INTO #tbl_res2 FROM #tbl_res AS r INNER JOIN [dbo].[Employee] AS emp ON emp.[EmployeeID] = r.[EmployeeID]; SELECT [EmployeeID] ,[LastName] ,[FirstName] INTO #tbl_empl FROM #tbl_res2; SELECT ts.[SkillID] ,te.[EmployeeID] ,ts.[SkillName] ,te.[LastName] ,te.[FirstName] INTO #tbl_skill_empl FROM #tbl_skill AS ts CROSS JOIN #tbl_empl AS te; SELECT tse.[EmployeeID] ,tse.[LastName] ,tse.[FirstName] ,tse.[SkillID] ,tse.[SkillName] ,tr2.[StartDate] ,tr2.[FinishDate] ,tr2.[Years] ,tr2.[Months] ,tr2.[Days] INTO #tbl_res3 FROM #tbl_skill_empl AS tse LEFT OUTER JOIN #tbl_res2 AS tr2 ON tse.[SkillID] = tr2.[SkillID] AND tse.[EmployeeID] = tr2.[EmployeeID]; SELECT [EmployeeID] INTO #tbl_empl_res FROM (SELECT [EmployeeID] ,[SkillID] FROM #tbl_res3 WHERE [Months] >= 6 OR [Years]>=1 GROUP BY [EmployeeID] ,[SkillID]) AS t GROUP BY [EmployeeID] HAVING COUNT(*) >= @count_skills - @CountNotSkill; SELECT tr2.[EmployeeID], tr2.[LastName], tr2.[FirstName], tr2.[SkillID], tr2.[SkillName], tr2.[StartDate], tr2.[FinishDate], tr2.[Years], tr2.[Months], tr2.[Days] FROM #tbl_empl_res AS ter INNER JOIN #tbl_res2 AS tr2 ON ter.[EmployeeID] = tr2.[EmployeeID]; SELECT tr2.[EmployeeID], tr2.[LastName], tr2.[FirstName], tr0.[CompanyID], (SELECT TOP(1) com.[CompanyName] FROM [dbo].[Company] AS com WHERE com.[CompanyID]=tr0.[CompanyID]) AS [CompanyName], tr0.[PositionID], (SELECT TOP(1) p.[PositionName] FROM [dbo].[Position] AS p WHERE p.[PositionID]=tr0.[PositionID]) AS [PositionName], tr0.[ProjectID], tr0.[StartDate], tr0.[FinishDate], tr0.[Description], tr0.[ProjectName], tr0.[ProjectDescription], tr0.[SkillID], tr0.[SkillName], tr0.[Achievements], tr0.[ReasonsForLeavingTheProject], tr0.[ReasonsForLeavingTheCompany] FROM #tbl_res2 AS tr2 INNER JOIN #tbl_res0 AS tr0 ON tr0.[EmployeeID] = tr2.[EmployeeID] INNER JOIN #tbl_skill AS ts ON ts.[SkillID] = tr0.[SkillID]; DROP TABLE #tbl_skill_tmp; DROP TABLE #tbl_skill; DROP TABLE #tbl_res; DROP TABLE #tbl_res2; DROP TABLE #tbl_empl; DROP TABLE #tbl_skill_empl; DROP TABLE #tbl_res3; DROP TABLE #tbl_empl_res; DROP TABLE #tbl_res0; END GO
为什么不更详细地检查SearchEmployee存储过程的工作?
对于初学者,它具有两个输入参数:
现在,让我们转到SearchEmployee存储过程的主体:
完成上述步骤后,我们可以提取出能够使用C#和T-SQL语言以及ASP.NET技术胜任的员工的姓名,但前提是最多只能缺少一种技能,如下所示:
EXEC [dbo].[SearchEmployee] @SkillList = N'C#;T-SQL;ASP.NET' ,@CountNotSkill = 1;
您可以在单元测试的帮助下涵盖所创建解决方案的大部分甚至全部功能。最重要的是,单元测试是DevOps基本原理的一部分,因为它们在此自动化过程中扮演着关键角色之一。本次讲解就这些,下一篇文章我们将讲解如何创建并运行存储过程 。立即下载体验吧!点击获取正版授权!
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn
文章转载自:本文探讨 SQL Server 中 NULL 和空值之间的区别,并讨论如何有效地处理它们。
Unity 是一款功能极其丰富的游戏引擎,允许开发人员将各种媒体集成到他们的项目中。但是,它缺少最令人兴奋的功能之一 - 将 Web 内容(例如 HTML、CSS 和 JavaScript)直接渲染到 3D 场景中的纹理上的能力。在本文中,我们将介绍如何使用 DotNetBrowser 在 Unity3D 中将 Web 内容渲染为纹理。
DevExpress v24.2帮助文档正式发布上线了,请按版本按需下载~
本教程将向您展示如何用MyEclipse构建一个Web项目,欢迎下载最新版IDE体验!
dbForge Studio for MySQL是与专业化MySQL数据库紧密相连的先进开发环境。
dbForge Studio for SQL ServerdbForge Studio for SQL Server是用于SQL Server的终极管理工具。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@pclwef.cn
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢