замените значения NULL последним ненулевым значением в серии resultset (SQL Server 2008 R2)
для SQL Server 2008 R2
у меня есть resultset, который выглядит так (Примечание [цена] является числовым, NULL ниже представляет собой Значение NULL, результирующий набор упорядочен по product_id и отметке времени)
product timestamp price
------- ---------------- -----
5678 2008-01-01 12:00 12.34
5678 2008-01-01 12:01 NULL
5678 2008-01-01 12:02 NULL
5678 2008-01-01 12:03 23.45
5678 2008-01-01 12:04 NULL
Я хочу преобразовать это в результирующий набор, который (по существу) копирует ненулевое значение из последней предыдущей строки, чтобы создать resultset, который выглядит так:
product timestamp price
------- ---------------- -----
5678 2008-01-01 12:00 12.34
5678 2008-01-01 12:01 12.34
5678 2008-01-01 12:02 12.34
5678 2008-01-01 12:03 23.45
5678 2008-01-01 12:04 23.45
Я не нахожу никакой агрегатной / оконной функции, которая позволит мне сделать это (опять же это необходимо только для SQL Server 2008 R2.)
Я надеялся найти аналитическую агрегатную функцию, которая сделает это для меня, что-то вроде...
LAST_VALUE(price) OVER (PARTITION BY product_id ORDER BY timestamp)
но я, похоже, не нахожу никакого способа сделать "кумулятивное последнее ненулевое значение" в окне (чтобы привязать окно к предыдущим строкам, а не ко всему разделу)
помимо создания табличной функции, определенной пользователем, есть ли какие-либо встроенные, которые выполняли бы это?
обновление:
по-видимому, эта функция доступна в CTP "Denali", но не в SQL Server 2008 R2.
LAST_VALUE http://msdn.microsoft.com/en-us/library/hh231517%28v=SQL.110%29.aspx
Я просто ожидал, что он будет доступен в SQL Server 2008. Он доступен в Oracle (по крайней мере, с 10gR2), и я могу сделать что-то подобное в MySQL 5.1, используя локальный переменная.
http://download.oracle.com/docs/cd/E14072_01/server.112/e10592/functions083.htm
3 ответов
вы можете попробовать следующее:
* Обновлено **
-- Test Data
DECLARE @YourTable TABLE(Product INT, Timestamp DATETIME, Price NUMERIC(16,4))
INSERT INTO @YourTable
SELECT 5678, '20080101 12:00:00', 12.34
UNION ALL
SELECT 5678, '20080101 12:01:00', NULL
UNION ALL
SELECT 5678, '20080101 12:02:00', NULL
UNION ALL
SELECT 5678, '20080101 12:03:00', 23.45
UNION ALL
SELECT 5678, '20080101 12:04:00', NULL
;WITH CTE AS
(
SELECT *
FROM @YourTable
)
-- Query
SELECT A.Product, A.Timestamp, ISNULL(A.Price,B.Price) Price
FROM CTE A
OUTER APPLY ( SELECT TOP 1 *
FROM CTE
WHERE Product = A.Product AND Timestamp < A.Timestamp
AND Price IS NOT NULL
ORDER BY Product, Timestamp DESC) B
--Results
Product Timestamp Price
5678 2008-01-01 12:00:00.000 12.3400
5678 2008-01-01 12:01:00.000 12.3400
5678 2008-01-01 12:02:00.000 12.3400
5678 2008-01-01 12:03:00.000 23.4500
5678 2008-01-01 12:04:00.000 23.4500
попробуйте это:
;WITH SortedData AS
(
SELECT
ProductID, TimeStamp, Price,
ROW_NUMBER() OVER(PARTITION BY ProductID ORDER BY TimeStamp DESC) AS 'RowNum'
FROM dbo.YourTable
)
UPDATE SortedData
SET Price = (SELECT TOP 1 Price
FROM SortedData sd2
WHERE sd2.RowNum > SortedData.RowNum
AND sd2.Price IS NOT NULL)
WHERE
SortedData.Price IS NULL
в основном CTE создает список, отсортированный по метке времени (по убыванию) - самый новый первый. Всякий раз, когда NULL найден, будет найдена следующая строка, содержащая не нулевую цену, и это значение используется для обновления строки с нулевой ценой.
у меня есть таблица, содержащая следующие данные. Я хочу обновить все нули в Столбцах зарплаты с предыдущим значением, не принимая значения null.
стол:
id name salary
1 A 4000
2 B
3 C
4 C
5 D 2000
6 E
7 E
8 F 1000
9 G 2000
10 G 3000
11 G 5000
12 G
вот запрос, который работает для меня.
select a.*,first_value(a.salary)over(partition by a.value order by a.id) as abc from
(
select *,sum(case when salary is null then 0 else 1 end)over(order by id) as value from test)a
выход:
id name salary Value abc
1 A 4000 1 4000
2 B 1 4000
3 C 1 4000
4 C 1 4000
5 D 2000 2 2000
6 E 2 2000
7 E 2 2000
8 F 1000 3 1000
9 G 2000 4 2000
10 G 3000 5 3000
11 G 5000 6 5000
12 G 6 5000