SQL: Как заполнить строки между двумя конкретными строками одним и тем же значением?
Мне нужно заполнить / заменить строки "-" между двумя "AL" ИЛИ двумя "MX" со значением "AL" или "MX" в зависимости от того, где появляется "-". Для целей этого примера я использую только 2 uid (на самом деле у меня больше uid). Кроме того, таблица упорядочена по столбцам uid и code_date в ASC
Для простоты понимания у меня есть эта таблица:
но я хотел бы иметь что-то вроде этого:
Я использую SQL Server 2008. Любое предложение о том, как я могу добиться этого???
Я создал таблицу со следующим кодом:
DECLARE @Customers TABLE
(uid bigint,
code_date date,
Value nchar(10)
)
INSERT INTO @Customers
VALUES (1591, '2016-08-01', ''),
(1591, '2016-08-02', ''),
(1591, '2016-08-03', 'AL'),
(1591, '2016-08-04', '-'),
(1591, '2016-08-05', '-'),
(1591, '2016-08-06', '-'),
(1591, '2016-08-07', '-'),
(1591, '2016-08-08', '-'),
(1591, '2016-08-09', 'AL'),
(1591, '2016-08-10', ''),
(1591, '2016-08-11', 'AL'),
(1591, '2016-08-12', ''),
(1082, '2016-02-01', ''),
(1082, '2016-02-02', ''),
(1082, '2016-02-03', ''),
(1082, '2016-02-04', ''),
(1082, '2016-02-05', 'MX'),
(1082, '2016-02-06', '-'),
(1082, '2016-02-07', '-'),
(1082, '2016-02-08', '-'),
(1082, '2016-02-09', '-'),
(1082, '2016-02-10', '-'),
(1082, '2016-02-11', '-'),
(1082, '2016-02-12', 'MX');
SELECT * FROM @Customers ORDER BY uid, code_date ASC
3 ответа
Решение
declare @x varchar(1000) = ''
update @Customers
set @x = value = (case when @x <> '' and value not in ('-',@x) then '' else @x end) + (case when value = '-' then '' when value = @x then '' else value end)
where value <> ''
/* Test Data & Table */
DECLARE @Customers TABLE
(Dates datetime,
Customer integer,
Value integer)
INSERT INTO @Customers
VALUES ('20100101', 1, 12),
('20100101', 2, NULL),
('20100101', 3, 32),
('20100101', 4, 42),
('20100101', 5, 15),
('20100102', 1, NULL),
('20100102', 2, NULL),
('20100102', 3, 39),
('20100102', 4, NULL),
('20100102', 5, 16),
('20100103', 1, 13),
('20100103', 2, 24),
('20100103', 3, NULL),
('20100103', 4, NULL),
('20100103', 5, 21),
('20100104', 1, 14),
('20100104', 2, NULL),
('20100104', 3, NULL),
('20100104', 4, 65),
('20100104', 5, 23) ;
/* CustCTE - This gives us a RowNum to allow us to build the recursive CTE CleanCust */
WITH CustCTE
AS (SELECT Customer,
Value,
Dates,
ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY Dates) RowNum
FROM @Customers),
/* CleanCust - A recursive CTE. This runs down the list of values for each customer, checking the Value column, if it is null it gets the previous non NULL value.*/
CleanCust
AS (SELECT Customer,
ISNULL(Value, 0) Value, /* Ensure we start with no NULL values for each customer */
Dates,
RowNum
FROM CustCte cur
WHERE RowNum = 1
UNION ALL
SELECT Curr.Customer,
ISNULL(Curr.Value, prev.Value) Value,
Curr.Dates,
Curr.RowNum
FROM CustCte curr
INNER JOIN CleanCust prev ON curr.Customer = prev.Customer
AND curr.RowNum = prev.RowNum + 1)
/* Update the base table using the result set from the recursive CTE */
UPDATE trg
SET Value = src.Value
FROM @Customers trg
INNER JOIN CleanCust src ON trg.Customer = src.Customer
AND trg.Dates = src.Dates
/* Display the results */
SELECT * FROM @Customers
Для select
запрос, просто используйте outer apply
:
select t.*, coalesce(t.value, t2.value) as new_value
from t outer apply
(select top 1 t2.*
from t t2
where t2.uid = t.uid and t2.code_date < t.code_date and t2.value is not null
order by t2.code_date desc
) t2;
Вы можете использовать аналогичную логику в update
,
Как update
, это было бы:
update t
set value = t2.new_value
from t outer apply
(select top 1 t2.*
from t t2
where t2.uid = t.uid and t2.code_date < t.code_date and t2.value is not null
order by t2.code_date desc
) t2
where t.value is null;