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
не допускается в подпрограмме.запрос или производная таблица.
И хотя в подзапросе (или производной таблице) условие top
допускается , результаты, скорее всего, будут не такими, как ожидалось (и не будут гарантированы).для получения одинаковых результатов при повторных запусках) без предложения order by
.
Таким образом, остается более важный вопрос о том, как update
просто число строк 'top X'.
Теперь Sybase ASE допускает предложение top
в операторе update
, но отсутствие поддержки предложения order by
(в операторе update
) делает top
практически бесполезным, если, так какв этом случае необходимо применить желаемый порядок.
ПосколькуP использует переменную (@CC_N) для определения количества обновляемых строк, я собираюсь предположить, что мы можем использовать другую переменную для определения диапазона 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
, но в запросе OP нам нужноподключите переменную (@CC_N
), которая потребует от нас динамического построения и выполнения запроса.Но в нашем случае это становится немного интереснее, так как для нашего динамического запроса нам также нужно записать результаты запроса в @name
, чтобы мы могли использовать его позже.К счастью для нас, ASE позволяет нам сделать это, включив наш @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 строк,
update
обновит все 100 строк, гдеPP_Decimal >= 47
Некоторые изменения, которые может предпринять пользователь, могут заключаться в ограничении количества обновляемых строк, например:
update top 5 ...
или
set rowcount 5
update ...
set rowcount 0
Но это не гарантирует, что одни и те же строки будут обновляться при повторных запусках.
Еще одно (очевидное) решение - это вытянутьЗначения столбца top @CC_N
первичного ключа (PK) в таблицу #temp, а затем объединение update
с этой таблицей #temp для выполнения требуемых обновлений @CC_N
.Я подожду, чтобы посмотреть, является ли решение таблицы #temp приемлемым для OP, и / или пусть кто-то другой опубликует ответ с подробностями решения на основе таблицы #temp.