6

dla SQL Server 2008 R2zastąpić wartości NULL z najnowszej wartości niezerowe w serii wynikowego (SQL Server 2008 R2)

Mam zestaw wyników, który wygląda tak (uwaga [cen] jest numeryczny, NULL poniżej reprezentuje wartość NULL, zestaw wyników jest sortowana według product_id i datownika)

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 

chcę przekształcić że do zestawu wyników, które (w zasadzie) kopiuje niezerowe wartości od najnowszej poprzedniego rzędu, w celu wytworzenia resultset to wygląda tak:

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 

nie znajdę żadnej funkcji agregat/okienkowy, który pozwoli mi na to (znowu to tylko potrzebne dla SQL Server 2008 R2).

Miałem nadzieję znaleźć analityczną łączną funkcję, która zrobi to za mi, coś jak ...

LAST_VALUE(price) OVER (PARTITION BY product_id ORDER BY timestamp) 

Ale nie wydaje się znaleźć jakiś sposób, aby zrobić „skumulowany ostatnią niezerową wartość” w oknie (na związanie się okno do poprzednich wierszach, zamiast cała partycja)

Oprócz tworzenia zdefiniowanej przez użytkownika funkcji o wartości tabelarycznej, Czy jest jakiś wbudowany, który by to wykonał?


UPDATE:

Najwyraźniej ta funkcja jest dostępna w 'Denali' CTP, ale nie w SQL Server 2008 R2.

LAST_VALUE http://msdn.microsoft.com/en-us/library/hh231517%28v=SQL.110%29.aspx

po prostu spodziewałem się, że jest dostępny w SQL Server 2008. Jest ona dostępna w Oracle (od 10gR2 przynajmniej), i mogę zrobić coś podobnego w MySQL 5.1, przy użyciu zmiennej lokalnej.

http://download.oracle.com/docs/cd/E14072_01/server.112/e10592/functions083.htm

+0

Która funkcja to znaczy, że jest dostępny w Denali, ale nie 2008 R2 ?? –

Odpowiedz

8

Można spróbować wykonać następujące czynności:

* Aktualizacja **

-- 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 
+0

To słowo kluczowe APPLY jest dla mnie nowe. Dam ci to. Dzięki! – spencer7593

+0

@ spencer7593 - Daj mi znać, jak to działa. – Lamak

+1

@ spencer7593 - Można również znaleźć dokumentację operatora 'APPLY' na tym łączu: http://technet.microsoft.com/en-us/library/ms175156.aspx – Lamak

2

Spróbuj tego:

;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 

Zasadniczo, CTE tworzy listę posortowaną według znacznika czasu (zstępującego) - nowego Najpierw. Za każdym razem, gdy zostanie znaleziona wartość NULL, zostanie znaleziony następny wiersz zawierający cenę NOT NULL, a ta wartość zostanie użyta do zaktualizowania wiersza o NULL price.

1

Mam tabelę zawierającą następujące dane. Chcę zaktualizować wszystkie wartości null w kolumnach wynagrodzeń z poprzedniej wartości bez pobierania wartości null.

Tabela:

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 

tutaj jest kwerenda, która pracuje dla mnie.

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 

wyjściowa:

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 
Powiązane problemy