【问题标题】:MS SQL - Get Before / After Specific RowsMS SQL - 在特定行之前/之后获取
【发布时间】:2021-12-22 22:30:11
【问题描述】:

我在 SQL 中有这个表。 SQL 中的 F 列和 G 列是空白的,但我已经展示了我希望如何在此表中填写它们。

当“有效”列为真时,我想在第一行开始之前捕获所有行,直到最后一行,例如它是假的。然后在 Pre Units 列中填充 Units 值。然后当它有最后一行时,我希望它填充“发布单位”列。请问您知道如何使用 MS SQL 做到这一点吗?

Table Sample

 CREATE TABLE [dbo].[SODATA](
    [PKID] [bigint] NOT NULL,
    [Date] [date] NULL,
    [ProductCode] [nvarchar](50) NULL,
    [Units] [float] NULL,
    [Valid] [bit] NULL,
    [PreUnits] [decimal](18, 5) NULL,
    [PostUnits] [decimal](18, 5) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (400, N'2019-04-01', N'Product1', 306, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (480, N'2019-04-08', N'Product1', 471, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (561, N'2019-04-15', N'Product1', 248, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (642, N'2019-04-22', N'Product1', 87, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (725, N'2019-04-29', N'Product1', 304, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (804, N'2019-05-06', N'Product1', 234, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (892, N'2019-05-13', N'Product1', 131, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (980, N'2019-05-20', N'Product1', 137, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (1070, N'2019-05-27', N'Product1', 491, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (1158, N'2019-06-03', N'Product1', 474, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (1245, N'2019-06-10', N'Product1', 424, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (1333, N'2019-06-17', N'Product1', 312, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (1420, N'2019-06-24', N'Product1', 483, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (1510, N'2019-07-01', N'Product1', 378, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (1598, N'2019-07-08', N'Product1', 301, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (1684, N'2019-07-15', N'Product1', 67, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (1784, N'2019-07-22', N'Product1', 153, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (1878, N'2019-07-29', N'Product1', 232, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (1974, N'2019-08-05', N'Product1', 145, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (2069, N'2019-08-12', N'Product1', 84, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (2163, N'2019-08-19', N'Product1', 231, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (2257, N'2019-08-26', N'Product1', 454, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (2351, N'2019-09-02', N'Product1', 297, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (2445, N'2019-09-09', N'Product1', 274, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (2539, N'2019-09-16', N'Product1', 331, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (2633, N'2019-09-23', N'Product1', 348, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (2727, N'2019-09-30', N'Product1', 220, NULL, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (2821, N'2019-10-07', N'Product1', 300, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (2915, N'2019-10-14', N'Product1', 132, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (3009, N'2019-10-21', N'Product1', 68, 1, NULL, NULL)
GO
INSERT [dbo].[SODATA] ([PKID], [Date], [ProductCode], [Units], [Valid], [PreUnits], [PostUnits]) VALUES (3102, N'2019-10-28', N'Product1', 450, NULL, NULL, NULL)
GO

【问题讨论】:

  • 数据图像不能帮助我们帮助您。花时间以可消耗的格式发布数据;首选 DDL 和 DML 语句。
  • 要清楚,您是根据Date 列定义之前/之后?还是PKID 专栏?我知道两者似乎在您的图片中定义了相同的顺序,但最好清楚您使用哪些列来定义顺序。
  • @Damien_The_Unbeliever 它将基于产品代码然后日期。
  • @Larnu 我的道歉,我已经用你现在可以导入 SQL 的数据更新了这个问题。
  • [Date] [nvarchar](50) NULL, 不 - 重新开始。您将 DATES 存储在 DATE 数据类型中,而不是作为字符串

标签: sql-server tsql sql-server-2014


【解决方案1】:

您可以使用 CTE (Common Table Expressions)、LAGLEAD 来做到这一点。

插入问题后的代码是:

;WITH mark_changes as (
    select
    PKID,Date,ProductCode,Units,Valid,
    case when ISNULL(Valid,0)<>ISNULL(LAG(Valid,1,2) OVER(order by PKID),0) then 1 else 0 end as Changed
    from SODATA
)
SELECT
PKID,Date,ProductCode,Units,Valid,
case when Valid=1 and Changed=1 then LAG(Units,1,0) OVER(order by PKID) else NULL end as PreUnits,
case when Valid=1 and ISNULL(LEAD(Valid,1) OVER(order by PKID),0)=0 then Units else NULL end as PostUnits
from mark_changes
order by PKID

您可以在 DB Fiddle here 上查看此示例。

【讨论】:

    【解决方案2】:

    https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=3e35b5962e43c1466ee85b6cc08316f9lptr 作为评论发布,非常感谢。

    update x
    set preunits = newpreunits,
    postunits = newpostunits
    from
    (
    select *, 
      max(prvunits) over(partition by productcode, grpid) as newpreunits,
      max(nxtunits) over(partition by productcode, grpid) as newpostunits
    from
    (
    select *, sum(addme) over(partition by productcode order by date) as grpid
    from
    (
    select *, 
      case when valid=1 and lead(valid) over(partition by productcode order by date) is null
      then lead(units) over(partition by productcode order by date) 
      end as nxtunits,
      
      case when valid=1 and lag(valid) over(partition by productcode order by date) is null
      then lag(units) over(partition by productcode order by date) 
      end as prvunits,
      
      case when 
        (valid=1 and lag(valid) over(partition by productcode order by date) is null)
        or
        (valid is null and lag(valid) over(partition by productcode order by date) = 1)
      then 1 else 0 end as addme
    from sodata
    ) as agg
    ) as g
    ) as x
    where newpreunits is not null
    or newpostunits is not null
    

    【讨论】:

      猜你喜欢
      • 2022-01-11
      • 2022-12-24
      • 1970-01-01
      • 1970-01-01
      • 2021-11-04
      • 1970-01-01
      • 1970-01-01
      • 2018-12-16
      • 2020-10-08
      相关资源
      最近更新 更多