带有TOP关键字的变量不能一起使用

时间:2018-12-11 22:36:16

标签: sql sybase sybase-ase

因此,在下面的查询中,我收到以下错误:关键字TOP和ORDER BY旁边的语法不正确。我都没有看到语法问题。经过进一步测试后,看来我的数据库平台不允许在派生表中使用TOP和ORDER BY。有人看到该查询的解决方法吗?我似乎找不到在TOP之后具有整数变量的另一种方法。我正在使用的不幸平台是SqlDbx。

DECLARE @SQL VARCHAR(16384)
DECLARE @CC_N INT

SELECT 
    @CC_N = B.PP - A.CC_PP 
FROM
(
    SELECT 
        Carline, 
        SUM(PP_Floor) AS CC_PP
    FROM PP_Balancing
    WHERE Carline = '01'
    GROUP BY Carline
) AS A
JOIN PP_National AS B ON A.Carline = B.Carline

SET @SQL = 
'
UPDATE PP_Balancing
SET PP_Floor = PP_Floor + 1
WHERE
Sales_Locality IN
    (
        SELECT TOP '+CAST(@CC_N AS VARCHAR(255))+' 
            Sales_Locality
        FROM PP_Balancing
        WHERE Carline = ''01''
        ORDER BY PP_Decimal DESC
    )
AND Carline = ''01''
'

EXEC (@SQL)

1 个答案:

答案 0 :(得分:1)

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 manuals),即,子查询或派生表中不允许order by

虽然子查询(或派生表)中允许top子句 ,但结果可能不会如预期的那样出来(也不能保证产生相同的结果)重复运行)而没有order by子句。

因此,剩下的主要问题是如何update仅行前“ X”行。

现在,Sybase ASE确实允许top语句中的update子句,但是由于缺乏对order by子句(在update语句中)的支持,{ {1}}在这种情况下(如果必须应用所需的排序)几乎没有用。

由于OP使用变量(@CC_N)确定要更新的行数,因此我假设我们可以使用另一个变量来确定要更新的top值的范围。

在进入实际的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 ,但在OPs查询中,我们需要插入变量(5),这将要求我们动态地构建并执行查询。但是在我们的例子中,它变得更加有趣,因为对于动态查询,我们还需要将查询结果捕获到@CC_N中,以便以后使用。对我们来说幸运的是,ASE通过在动态创建的查询中加入@name来做到这一点,例如:

@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

注意:此解决方案假定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中有100行
  • 假设PP_Decimal = 47
  • @CC_N = 5将设置为@PP_Decimal
  • 47不仅会影响@ CC_N = 5行,还会更新所有100行,其中update

用户可能尝试的一些变化是限制要更新的行数,例如:

PP_Decimal >= 47

update top 5 ...

但是这些不能保证相同的行会在重复运行时得到更新。

另一种(显而易见的)解决方案是将set rowcount 5 update ... set rowcount 0 主键(PK)列值拉入#temp表,然后使top @CC_N与该#temp表联接以执行所需的操作update个更新。我将等待看#temp表解决方案是否可以被OP接受,和/或让其他人发布带有#temp表解决方案详细信息的答案。