- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我遇到了一个问题,复杂的 SQL 查询总是出错。从本质上讲,这会导致向错误的客户发送邮件以及其他类似的“问题”。
每个人对于创建这样的 SQL 查询都有什么经验?我们每隔一周就会创建新的数据群。
以下是我的一些想法及其局限性:
创建测试数据虽然这可以证明我们拥有所有正确的数据,但它并不能强制排除生产中的异常情况。这些数据在今天被认为是错误的,但在 10 年前可能是正确的;它没有记录在案,因此我们只有在提取数据后才知道它。
创建维恩图和数据映射 这似乎是测试查询设计的可靠方法,但它并不能保证实现是正确的。它让开发人员提前计划并在编写时思考正在发生的事情。
感谢您对我的问题提供的任何意见。
最佳答案
您不会编写具有 200 行长函数的应用程序。您可以将这些长函数分解为较小的函数,每个函数都有一个明确定义的职责。
为什么要这样编写 SQL?
分解您的查询,就像分解您的函数一样。这使得它们更短、更简单、更容易理解、更容易测试、更容易重构。它允许您在它们之间添加“垫片”,并在它们周围添加“包装器”,就像在过程代码中一样。
你是如何做到这一点的?通过将查询所做的每件重要事情都放入 View 中。然后,您可以从这些更简单的 View 中组合出更复杂的查询,就像您从更原始的函数中组合出更复杂的函数一样。
最棒的是,对于大多数 View 组合,您将从 RDBMS 中获得完全相同的性能。 (对于某些人来说,您不会;那又怎样?过早的优化是万恶之源。首先正确编写代码,然后在需要时进行优化。)
Here's an example of using several view to decompose a complicated query.
在示例中,由于每个 View 只添加一个转换,因此每个 View 都可以独立测试以发现错误,并且测试很简单。
以下是示例中的基表:
create table month_value(
eid int not null, month int, year int, value int );
这个表是有缺陷的,因为它使用两列,月份和年份,来表示一个数据,一个绝对月份。以下是我们对新计算列的规范:
We'll do that as a linear transform, such that it sorts the same as (year, month), and such that for any (year, month) tuple there is one and only value, and all values are consecutive:
create view cm_absolute_month as
select *, year * 12 + month as absolute_month from month_value;
现在我们必须测试的是我们规范中固有的,即对于任何元组(年、月),都有且只有一个(absolute_month),并且(absolute_month)是连续的。让我们编写一些测试。
我们的测试将是一个 SQL select
查询,具有以下结构:测试名称和连接在一起的 case 语句。测试名称只是一个任意字符串。 case 语句只是 case when
测试语句 then 'passed' else 'failed' end
。
测试语句只是 SQL 选择(子查询),测试必须为 true 才能通过。
这是我们的第一个测试:
--a select statement that catenates the test name and the case statement
select concat(
-- the test name
'For every (year, month) there is one and only one (absolute_month): ',
-- the case statement
case when
-- one or more subqueries
-- in this case, an expected value and an actual value
-- that must be equal for the test to pass
( select count(distinct year, month) from month_value)
--expected value,
= ( select count(distinct absolute_month) from cm_absolute_month)
-- actual value
-- the then and else branches of the case statement
then 'passed' else 'failed' end
-- close the concat function and terminate the query
);
-- test result.
运行该查询会产生以下结果:对于每个(年,月)都有一个且只有一个(absolute_month):通过
只要month_value中有足够的测试数据,该测试就有效。
我们也可以添加一个测试以获得足够的测试数据:
select concat( 'Sufficient and sufficiently varied month_value test data: ',
case when
( select count(distinct year, month) from month_value) > 10
and ( select count(distinct year) from month_value) > 3
and ... more tests
then 'passed' else 'failed' end );
现在让我们测试一下它的连续性:
select concat( '(absolute_month)s are consecutive: ',
case when ( select count(*) from cm_absolute_month a join cm_absolute_month b
on ( (a.month + 1 = b.month and a.year = b.year)
or (a.month = 12 and b.month = 1 and a.year + 1 = b.year) )
where a.absolute_month + 1 <> b.absolute_month ) = 0
then 'passed' else 'failed' end );
现在,让我们将测试(只是查询)放入一个文件中,然后针对数据库运行该脚本。事实上,如果我们将 View 定义存储在一个脚本(或多个脚本,我建议每个相关 View 一个文件)中以针对数据库运行,我们可以将每个 View 的测试添加到相同的脚本中,这样(重新)创建 View 的行为也会运行 View 的测试。这样,当我们重新创建 View 时,我们都会得到回归测试,并且当 View 创建针对生产环境运行时, View 也将在生产环境中进行测试。
关于sql - 测试 SQL 查询的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/754527/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!