問題
我有一些帶有日期和數值的表格;缺少一些數值。我希望用最后一個日期的可用值填充這些缺失值。
我需要這樣做:
- 在 Sybase 資料庫中,我只有讀權限;我可以創建臨時表,但不能創建任何永久表或永久視圖
- 在我擁有完全訪問權限的 Microsoft SQL Server 2019(版本 15)資料庫中
我已經找到了如何在 Microsoft SQL Server 中執行此操作,但在 Sybase 中未找到。
更新:如果我跑select @@version我得到
Adaptive Server Enterprise/16.0 SP02 PL08 Instrumented
例如,我需要從
------- -------
| date | value |
------- -------
| 1-Nov | 100 |
| 2-Nov | |
| 3-Nov | |
| 4-Nov | 110 |
| 5-Nov | |
| 6-Nov | 105 |
------- -------
到(見星號):
------- --------
| date | value |
------- --------
| 1-Nov | 100 |
| 2-Nov | *100 |
| 3-Nov | *100 |
| 4-Nov | 110 |
| 5-Nov | *110 |
| 6-Nov | 105 |
------- --------
嘗試 #1
我在這里找到了一個例子
在 SQL Server 中,它運行時沒有錯誤,但不會更新任何內容。在 Sybase 中,它根本不運行。我得到:
關鍵字 top 附近的語法不正確
這是一個可重現的例子
CREATE TABLE #my_test (my_date datetime, my_value float NULL )
go
INSERT INTO #my_test SELECT '1-Nov-2021',100
INSERT INTO #my_test SELECT '2-Nov-2021',NULL
INSERT INTO #my_test SELECT '3-Nov-2021',NULL
INSERT INTO #my_test SELECT '4-Nov-2021',110
INSERT INTO #my_test SELECT '5-Nov-2021',NULL
INSERT INTO #my_test SELECT '6-Nov-2021',105
go
UPDATE #my_test
set my_value = (
select top 1 b.my_value
from #my_test b
where b.my_date < a.my_date and b.my_date = a.my_date and b.my_value is not null
order by b.my_date desc
)
from #my_test a
where a.my_value is null
go
嘗試#2
Outer apply works with Microsoft SQL but it doesn't seem supported in Sybase: in Sybase I get
Incorrect syntax near 'outer'
update #my_test
set my_value = coalesce(pr.my_value, nx.my_value)
from #my_test m
outer apply --next non-null value
(
select top 1 *
from #my_test x
where x.my_value is not null
and x.my_date > m.my_date
order by my_date
) nx
outer apply -- previous non-null
(select top 1 *
from #my_test x
where x.my_value is not null
and x.my_date < m.my_date
order by my_date desc
) pr
where m.my_value is null
Attempt #3
This was in the same link as before. This code works in SQL Sevrer but Sybase tells me:
You cannot use a derived table in the FROM clause of an UPDATE or DELETE statement
My code:
update #my_test set #my_test.my_value = tt.NewAmount
from #my_test t
inner join (
select my_date, coalesce(min(my_value) over (order by my_date desc ROWS BETWEEN 1 PRECEDING AND CURRENT ROW),
min(my_value) over (order by my_date asc ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)) NewAmount
from #my_test t
) tt on tt.my_date = t.my_date
where t.my_value is null
uj5u.com熱心網友回復:
可以使用一些“基本”子查詢語法來執行此操作...
一種使用 aselect來填補空白的想法(例如,OP 使用 a select into):
select mt1.*,isnull(mt1.my_value,
(select mt2.my_value
from #my_test mt2
where mt2.my_date = (select max(my_date)
from #my_test mt3
where mt3.my_date < mt1.my_date
and mt3.my_value is not NULL))) as new_value
from #my_test mt1
order by mt1.my_date -- for display purposes
go
my_date my_value new_value
------------------------------- ----------- -----------
Nov 1 2021 12:00AM 100 100
Nov 2 2021 12:00AM NULL 100
Nov 3 2021 12:00AM NULL 100
Nov 4 2021 12:00AM 110 110
Nov 5 2021 12:00AM NULL 110
Nov 6 2021 12:00AM 105 105
假設資料已經在#temp 表中并且 OP 想要運行一個update:
update #my_test
set my_value = (select mt2.my_value
from #my_test mt2
where mt2.my_date = (select max(mt3.my_date)
from #my_test mt3
where mt3.my_date < mt1.my_date
and mt3.my_value is not NULL))
from #my_test mt1
where my_value is NULL
go
select * from #my_test
order by my_date
go
my_date my_value
------------------------------- -----------
Nov 1 2021 12:00AM 100
Nov 2 2021 12:00AM 100
Nov 3 2021 12:00AM 100
Nov 4 2021 12:00AM 110
Nov 5 2021 12:00AM 110
Nov 6 2021 12:00AM 105
筆記:
- (對我而言)不清楚如果表中的“前”n 行有
my_value=NULL(即,沒有my_value要復制的“前”行),我們應該做什么;如果這是一個問題 OP 可以將子選擇包裝在一個isnull(<sub-select>,@default_value) - 以上代碼經過測驗
ASE 16.0 SP04 GA(盡管這應該適用于大多數(所有?)版本,因為我們只是使用標準的子查詢語法) - 對于大量資料,查詢將受益于 上的索引
(my_date [,my_value]);雖然 OP 可能無法向永久表添加索引,但他們應該能夠#my_test在執行之前向其添加索引update(所述索引應該在表的初始填充之后創建,以便為 提供可用的統計資料my_date) - 是否在索引
#my_test將被用來將取決于服務器和會話級設定statement_cache,literal_autoparam和deferred_name_resolution以及在資料量#my_test
uj5u.com熱心網友回復:
根據您需要回填的 NULL 數量,您最終將有大約 50% 的行需要更新。
在我遇到的所有資料庫中,這種情況需要一個CREATE TABLE ... AS SELECT,而不是大量更新。并且 - 在我的示例中,我避免使用關鍵字DATEor VALUE。
因此 - 這是一個完整的例子 - 使用LAST_VALUE( ... IGNORE NULLS).
DROP TABLE IF EXISTS indata;
CREATE TABLE
indata(dt,val) AS (
SELECT DATE '1-Nov-2021',100
UNION ALL SELECT DATE '2-Nov-2021',NULL
UNION ALL SELECT DATE '3-Nov-2021',NULL
UNION ALL SELECT DATE '4-Nov-2021',110
UNION ALL SELECT DATE '5-Nov-2021',NULL
UNION ALL SELECT DATE '6-Nov-2021',105
);
DROP TABLE IF EXISTS outdata;
CREATE TABLE outdata AS
SELECT
dt
, LAST_VALUE(val IGNORE NULLS) OVER(ORDER BY dt) AS val
FROM indata
;
ALTER TABLE indata RENAME TO indata_old;
-- sp_rename indata, indata_old;
ALTER TABLE outdata RENAME TO indata;
-- sp_rename indata, indata; -- do you rename tables like this in Sybase?
SELECT * FROM indata;
-- out dt | val
-- out ------------ -----
-- out 2021-11-01 | 100
-- out 2021-11-02 | 100
-- out 2021-11-03 | 100
-- out 2021-11-04 | 110
-- out 2021-11-05 | 110
-- out 2021-11-06 | 105
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/353191.html
標籤:sql tsql null sap-ase sybase-ase15
