OP在评论中提到这是一个Sybase ASE 12.5.4实例,所以我们将看一些ASE特定的细节......
OP还没有(还)提供实际的错误消息,但我猜它看起来像:
select * from (select top 4 id from sysobjects order by name ) dt go Msg 154, Level 15, State 53: Server 'ASE200', Line 2: An ORDER BY clause is not allowed in a derived table. select * from (select id from sysobjects order by name ) dt go Msg 154, Level 15, State 53: Server 'ASE200', Line 3: An ORDER BY clause is not allowed in a derived table.
这是预期的行为(按照 Sybase ASE手册 ),即 order by 子查询或派生表中不允许使用。
order by
而且 top 条款 的 是 强> 允许在子查询(或派生表)中,结果可能不会按预期出现(也不保证在重复运行时生成相同的结果) order by 条款。
top
因此,叶子使用更重要的问题如何 update 只是'前X'行数。
update
现在,Sybase ASE确实允许了 top 条款 update 声明,但缺乏支持 order by 条款(在 update 声明)使 top 如果在这种情况下必须应用所需的顺序,则几乎没用。
由于OP使用变量(@CC_N)来确定要更新的行数,我将假设我们可以使用另一个变量来确定 PP_Decimal 我们想要更新的值。
PP_Decimal
在我到达实际之前 update 声明我们需要看几个中间步骤......
-- use variable (@name) to capture the Nth name from sysobjects (order by name) select top 5 name from sysobjects order by name go name ------------------------------ sysalternates sysattributes syscolumns syscomments sysconstraints <<<=== we want to capture this value in @name (5 rows affected) declare @name varchar(255) -- @name will be assigned each value as it's returned by the query, with -- the last value (sysconstraints) being the last value assigned to @name select top 5 @name = name from sysobjects order by name print @name go (5 rows affected) sysconstraints <<<=== the contents of @name
在这个例子中,我插入了一个静态 5 ,但在OPs查询中我们需要插入一个变量( @CC_N ),这将要求我们动态构建和执行查询。但在我们的情况下,它更有趣的是,对于我们的动态查询,我们还需要捕获查询的结果 @name 所以我们以后可以使用它。对我们来说幸运的是,ASE允许我们通过包括我们来做到这一点 @name 在动态创建的查询中,例如:
5
@CC_N
@name
declare @name varchar(30), @SQL varchar(100), @CC_N int select @CC_N = 5 select @SQL = 'select top ' + convert(varchar(30),@CC_N) + ' @name = name from sysobjects order by name' select @SQL as 'my query' exec(@SQL) select @name as '@name' go @SQL ------------------------------------------------------- select top 5 @name = name from sysobjects order by name @name ------------------------------ sysconstraints <<<=== the contents of @name
在这一点上,我们应该拥有实现所需的一切 update 。
注意:为了这个答案,我将假设 PP_Decimal column是一个整数。
DECLARE @SQL varchar(1000), @CC_N int, @PP_Decimal int -- OPs original code to find the Nth value; -- removed the superfluous 'group by' from the derived table SELECT @CC_N = B.PP - A.CC_PP FROM (SELECT SUM(PP_Floor) AS CC_PP FROM PP_Balancing WHERE Carline = '01' ) AS A JOIN PP_National AS B ON A.Carline = B.Carline -- ??? should OP check for @CC_N >= 1 ??? -- find the Nth PP_Decimal value where 'N' == @CC_N select @SQL = "select top " + convert(varchar(30), @CC_N) + " @PP_Decimal = PP_Decimal from PP_Balancing where Carline = '01' order by PP_Decimal desc" -- comment-out/remove the following 'select'; -- only placed here for debugging purposes select @SQL as '@SQL' exec(@SQL) -- at this point @PP_Decimal should contain the last/Nth PP_Decimal value when ordered by PP_Decimal desc; -- again, following 'select' is for debugging purposes select @PP_Decimal as '@PP_Decimal' -- now update our table where PP_Decimal >= @PP_Decimal update PP_Balancing set PP_Floor = PP_Floor + 1 where PP_Decimal >= @PP_Decimal and Carline = '01' go @SQL --------------------------------------- select top 5 @PP_Decimal = PP_Decimal <<<=== for sake of example I plugged in @CC_N=5 from PP_Balancing where Carline = '01' order by PP_Decimal desc @PP_Decimal ----------- 538 <<<=== made up number for the sake of this example (since I don't have any actual data) (N rows affected) <<<=== assuming update statement finds @CC_N rows to update
注意:此解决方案假定 PP_Decimal 值是唯一的,否则是最终的 update 可以更新超过 @CC_N 值,例如,
max(PP_Decimal) = 47
PP_Decimal = 47
@CC_N = 5
@PP_Decimal
47
PP_Decimal >= 47
用户可能尝试的一些变化是限制要更新的行数,例如:
update top 5 ...
要么
set rowcount 5 update ... set rowcount 0
但是这些并不能保证在重复运行时会更新相同的行。
另一个(显而易见的)解决方案是拉动 top @CC_N 将主键(PK)列值转换为#temp表然后具有 update 加入此#temp表来执行所需的操作 @CC_N 更新。我等着看OP是否可以接受#temp表解决方案和/或让其他人发布一个基于#temp表的解决方案的详细信息。
top @CC_N