SQL-通过先运行命令

SQL-通过先运行命令,sql,sql-server-2005,Sql,Sql Server 2005,请查看此数据库架构: create table Person (id int not null identity, [index] varchar(30), datecreated datetime, groupid int) create table [Group] (id int identity not null, description varchar(30)

请查看此数据库架构:

create table Person (id int not null identity,
                     [index] varchar(30),
                     datecreated datetime, 
                     groupid int)

create table [Group] (id int identity not null, description varchar(30))
样本数据:

insert into Person ([index],datecreated,groupid) values ('4,5,6','2011-01-01',1)
insert into Person ([index],datecreated,groupid) values ('1,2,3','2011-02-02',1)
insert into Person ([index],datecreated,groupid) values ('7,8','2012-02-02',2) 

insert into [Group] (description) values ('TestGroup')
insert into [Group] (description) values ('TestGroup2')
请查看下面的SQL语句:

select  *    
from Person 
inner join [Group] on Person.groupid = [group].id 
where [group].description = 'TestGroup' 
order by 
   left(substring([index], charindex(',', [index]) + 1, 200),  
        charindex(',', substring([index], charindex(',', [index]) + 1, 200)) - 1)
此SQL语句失败,出现以下错误:

传递给子字符串函数的长度参数无效

导致此错误的是
order by
子句,即它试图查找索引列的第三个元素,但第三个元素在第3行中不存在(只有两个元素)

但是,我希望
[group].description='TestGroup'
过滤掉记录三。情况似乎并非如此。这就好像是在
where
子句之前运行了
orderby
子句。如果从查询中排除
order by
子句,则查询将运行


为什么会这样

SQL中的求值顺序有很弱的保证。可能先执行排序,然后执行流聚合。这本身没什么问题


一般来说,您不能依赖执行顺序。除非在case表达式中,如果子字符串的输入无效,您可以使用该表达式按顺序创建一个伪值,如
NULL
案例是执行评估命令的唯一方式。此命令非常残酷。我建议您使用一个临时表或表子表达式将其分成几个查询,这样您就可以先进行筛选,和/或创建一个包含要排序的数据的列。

记住,SQL是一种声明性语言,而不是过程性语言。也就是说,描述所需的结果集。您依赖SQL编译器/优化器来设置执行计划

非常典型的是,SQL引擎将有一个从表中读取数据并执行该数据所需的所有计算的组件。当然,这包括SELECT子句中的计算,也包括“ON”子句、“WHERE”子句和“ORDER BY”子句中的计算

然后,发动机可以在读取数据后进行过滤。这使引擎能够轻松使用计算值进行过滤


我并不是说所有数据库都是这样工作的。我要说的是,不能保证SQL语句中的操作顺序。在这种情况下,按错误的顺序执行操作会导致错误,从而阻止SQL完成。是否需要帮助重写查询以避免出错?

用于测试:为什么在该列中存储逗号分隔的值?这通常是一个非常可疑的DB设计的标志(你的问题就是这个结果)。@a_horse_没有名字,这是我继承的一个系统。它需要重新设计。你知道是什么原因首先考虑GROUP BY子句吗?@marc_s,是的。看看这里,自己看看:sqlfiddle.com/#!3/29802/1 SQL中的执行计划严重依赖于数据和表统计信息。它可以在没有任何警告或明显挑衅的情况下改变。@JNK,有趣的-这个案例似乎很有问题。这一事实改变了我的答案:用CASE试试(因为文档上这么说!),然后测试它。然后希望它稍后会开始崩溃。无论如何,案例是最后的希望。