Как получить предыдущую запись, если в таблице нет текущей записи - PullRequest
1 голос
/ 28 апреля 2019

мой стол вот так

    Id  Date    type    quantity
1   29/04/2019  APPLE   2
2   29/04/2019  Banana  15
3   29/04/2019  Mango   100
4   29/04/2019  Grapes  50
5   29/04/2019  Fish    80
6   30/04/2019  APPLE   4
7   30/04/2019  Grapes  100
8   30/04/2019  Fish    90
9   01/05/2019  APPLE   6
10  01/05/2019  Banana  30
11  01/05/2019  Grapes  150
12  01/05/2019  Fish    100
13  02/05/2019  Mango   200
14  02/05/2019  Grapes  200
15  02/05/2019  Fish    110
16  03/05/2019  APPLE   8
17  03/05/2019  Banana  45
18  03/05/2019  Mango   300
19  04/05/2019  APPLE   10
20  04/05/2019  Grapes  300
21  04/05/2019  Fish    120
22  05/05/2019  APPLE   12
23  05/05/2019  Fish    130

я пропускаю некоторые входные данные каждый день, но мне нужно заполнить пропуски предыдущей строкой того же "Типа" 30/04/2019, я пропустил "Банан и Манго", но мне нужно, как

    Id  Date    type    quantity
1   29/04/2019  APPLE   2
2   29/04/2019  Banana  15
3   29/04/2019  Mango   100
4   29/04/2019  Grapes  50
5   29/04/2019  Fish    80
6   30/04/2019  APPLE   4
7   30/04/2019  Grapes  100
8   30/04/2019  Fish    90
9   30/04/2019  Banana  15
10  30/04/2019  Mango   100

на самом деле последние две строки равны нулю, но должны быть обновлены 29.04.2014

Ответы [ 4 ]

4 голосов
/ 28 апреля 2019

Я думаю, что проще всего было бы так:

DECLARE @PDate DATE = SELECT TOP 1 Date FROM YourTable ORDER BY Date ASC  --Previous Date
DECLARE @NDate DATE = SELECT TOP 1 Date FROM YourTable WHERE DATE>@PDate  --Next Date

WHILE (@NDate IS NOT NULL)
BEGIN

WITH X AS
(
 SELECT T1.Date AS Date1, T1.Type AS Type1, T1.Quantity AS Q1
        T2.Date AS Date2, T2.Type AS Type2, T2.Quantity AS Q2
 FROM YourTable T1
 LEFT JOIN YourTable T2 ON T1.Type = T2.Type
 WHERE T1.Date = @PDate AND T2.Date = @NDate
)
INSERT INTO YourTable (Date,Type,Quantity)
SELECT @NDate,Type1,Q1
WHERE X.Type2 IS NULL

SET @PDate = @NDate
SET @NDate = NULL  -- If next result wasnt found this stays null for while condition
SET @NDate = SELECT TOP 1 Date FROM YourTable WHERE Date>@PDate

END

Я думаю, что это может работать, и я так хочу
(если есть какой-либо синтаксис или ... ошибки его, потому что у меня не было SSMS для тестирования. Извините)

1 голос
/ 28 апреля 2019

Я думаю, что использование курсора является хорошим вариантом для вставки отсутствующих записей в таблицу. Курсором вы сможете проверить недостающие типы по дате и вставить их с предыдущим количеством.

Вы также можете использовать этот следующий скрипт, чтобы найти недостающие записи в вашей таблице. Для создания сценария считаю таблицу name = 'add_missing_records'

SELECT AA.date AS [Date],
AA.type AS [Type],
BB.quantity AS [Original Quantity] ,
CASE 
    WHEN BB.quantity IS NULL THEN 
        ( 
            SELECT quantity 
            FROM add_missing_records C 
            WHERE C.date = (
                SELECT MAX([date]) 
                FROM add_missing_records B 
                WHERE B.date < AA.date 
                AND B.type = AA.type
            )
            AND C.type = AA.type
        ) 
    ELSE BB.quantity 
END AS [New Quantuty]

FROM (
    SELECT date,type
    FROM (
        SELECT DISTINCT 'A' AS common,date 
        FROM add_missing_records
    )A
    FULL JOIN (
        SELECT DISTINCT 'A' as common, type 
        FROM add_missing_records
    )B
    ON a.common = b.common
) AA
LEFT JOIN add_missing_records BB 
    ON AA.date = BB.date 
    AND AA.type = BB.type
WHERE BB.quantity IS NULL
ORDER BY 1,2
1 голос
/ 28 апреля 2019

ОК, после того, как целевые посты улажены, это один из методов.Обратите внимание, что это решение создает наборы данных Types и Dates.Действительно, набор данных Types должен уже существовать где-то в вашей базе данных, и вам следует создать таблицу календаря, если вы собираетесь часто выполнять этот тип работы.

В любом случае,Я оставил комментарии в коде для вас.Я предположил , что вы используете SQL Server 2012+, поскольку в 2008 году буквально заканчивается поддержка.

CREATE TABLE dbo.MyTable (ID int IDENTITY(1,1),
                          [date] date,
                          [type] varchar(10),
                          Quantity int);
INSERT INTO dbo.MyTable
SELECT CONVERT(date,[date],103),
       RTRIM([Type]),
       Quantity
FROM (VALUES('29/04/2019','APPLE ',2),
            ('29/04/2019','Banana',15),
            ('29/04/2019','Mango ',100),
            ('29/04/2019','Grapes',50),
            ('29/04/2019','Fish  ',80),
            ('30/04/2019','APPLE ',4),
            ('30/04/2019','Grapes',100),
            ('30/04/2019','Fish  ',90),
            ('01/05/2019','APPLE ',6),
            ('01/05/2019','Banana',30),
            ('01/05/2019','Grapes',150),
            ('01/05/2019','Fish  ',100),
            ('02/05/2019','Mango ',200),
            ('02/05/2019','Grapes',200),
            ('02/05/2019','Fish  ',110),
            ('03/05/2019','APPLE ',8),
            ('03/05/2019','Banana',45),
            ('03/05/2019','Mango ',300),
            ('04/05/2019','APPLE ',10),
            ('04/05/2019','Grapes',300),
            ('04/05/2019','Fish  ',120),
            ('05/05/2019','APPLE ',12),
            ('05/05/2019','Fish  ',130)) V([date],[Type],Quantity);

GO
--SELECT *
--FROM dbo.MyTable;
GO
--Create a calendar table
WITH N AS (
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) N(N)),
Tally AS(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
    FROM N N1, N N2, N N3), --1000 days shuld be enough
Dates AS(
    SELECT DATEADD(DAY, T.I, MIN(MT.[date])) AS [Date]
    FROM Tally T
         CROSS JOIN dbo.MyTable MT
    GROUP BY T.I
    HAVING DATEADD(DAY, T.I, MIN(MT.[date])) <= MAX([Date])),
--Get Types
Types AS (
    SELECT DISTINCT [Type]
    FROM dbo.MyTable MT),
--Create islands
Grps AS(
    SELECT MT.ID,
           D.[Date],
           T.[Type],
           MT.Quantity,
           COUNT(MT.Quantity) OVER (PARTITION BY T.[Type] ORDER BY D.[date]
                                    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Grp
    FROM Dates D
        CROSS JOIN Types T
        LEFT JOIN dbo.MyTable MT ON D.[Date] = MT.[date]
                                AND T.[type] = MT.[type])
SELECT G.ID AS ID,
       ROW_NUMBER() OVER (ORDER BY G.[Date], G.[Type]) AS RN,
       G.[Date],
       G.[Type],
       MAX(G.Quantity) OVER (PARTITION BY G.[Type], G.Grp) AS Quantity
FROM Grps G
ORDER BY G.[Date],
         G.[Type];

GO
DROP TABLE dbo.MyTable;

db <> fiddle

1 голос
/ 28 апреля 2019

попробуйте это:

declare @date date

и для инициации @date вы можете использовать select @date=max(date) from table1 или передать статическое значение set @date='02/01/2019' а затем найти input

select input,max(date) as MaxDate into #temp 
from table1 
where input not in (select input from table1 where date=@date  ) 
group by input

затем:

select t.* from Table1 t join #temp on  Table1.input=#temp.Input and Table1.date=#temp.MaxDate
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...