如何在 SQL SERVER 2017 SSMS 中用以前保存的行值替换行值

Posted

技术标签:

【中文标题】如何在 SQL SERVER 2017 SSMS 中用以前保存的行值替换行值【英文标题】:How to replace row value with previous saved row value in SQL SERVER 2017 SSMS 【发布时间】:2019-08-13 06:13:43 【问题描述】:

首先我的问题太复杂了,抱歉我的英语不好

所以,我在 SQL 中得到了一些表值函数查询,以便为我在 VB 上选择的每一天自动生成 5 行

这里是这个表值函数如何在 2 天内工作的示例

列数量的默认值为每次 1

默认名称始终为 A , B , C , D , E

它将每天生成新的 5 行,然后上面的所有数据将使用存储过程 (tblProduce) 提交到另一个表中 图片中的所有列都来自VB DataViewGrid,我只制作表值函数来获取ID、名称。其余部分将在VB上填写

主要问题:

我想要的是,如果我在 2019 年 7 月 25 日创建并保存此数据并将 CheckBox 的行值之一更改为 True

然后,第二天,当我想创建另一个数据时,应该是这样的 这是预期的数据应该在第 2 天

绿色背景表示当复选框 = True 时,数据取自上次保存的行

这是针对 SSMS SQL Server 2017 的,我已经尝试在表值函数上使用 UNION / SUB QUERY 但仍然没有弄清楚如何做这件事

QUERY 获取选择了多少天:

CREATE FUNCTION [dbo].[tvfCustomDateRange] (@Increment char(1), @StartDate date, @EndDate date) 
RETURNS @SelectedRange TABLE (cDate date) 
AS
BEGIN 

      ;WITH cteRange (DateRange) AS (
            SELECT @StartDate
            UNION ALL
            SELECT 
                  CASE
                        WHEN @Increment = 'd' THEN DATEADD(dd, 1, DateRange)
                        WHEN @Increment = 'w' THEN DATEADD(ww, 1, DateRange)
                        WHEN @Increment = 'm' THEN DATEADD(mm, 1, DateRange)
                  END
            FROM cteRange
            WHERE DateRange <= 
                  CASE
                        WHEN @Increment = 'd' THEN DATEADD(dd, -1, @EndDate)
                        WHEN @Increment = 'w' THEN DATEADD(ww, -1, @EndDate)
                        WHEN @Increment = 'm' THEN DATEADD(mm, -1, @EndDate)
                  END)

      INSERT INTO @SelectedRange (cDate)
      SELECT DateRange
      FROM cteRange
      OPTION (MAXRECURSION 3660);
      RETURN
END

我在 vb 上选择的每隔多少天生成第 5 行的查询是:

CREATE FUNCTION [dbo].[tvfGenerate5Row] (@BeginDate DateTimeOffset, @EndDate Datetimeoffset)
RETURNS TABLE 
AS
RETURN 
(
    SELECT IsNuLL(tblProduce.Idtbl5Row,tblCustom.Idtbl5Row),
           IsNULL(tblProduce.Name,tblCustom.Name),
           IsNULL(tblProduce.Quantity,1),
           IsNULL(tblProduce.cDate,tblCustom.cDate),
           IsNULL(tblProduce.CheckBox,'')

    FROM  (SELECT Name, cDate, Idtbl5Row
           FROM tvfCustomDateRange('d', @BeginDate, @EndDate) CROSS JOIN tblWith5Row) AS tblCustom LEFT OUTER JOIN tblProduce ON tblCustom.cDate=tblProduce.cDate
)
CREATE TABLE tblProduce
(
    IdtblProduce  BigInt Primary Key,
    Idtbl5Row     BigInt,
    Name          VarChar(25),
    Quantity      Integer,
    cDate         DateTime,
    CheckBox      Bit,
    FOREIGN KEY (Idtbl5Row) REFERENCES tblWith5Row(Idtbl5Row)
)

【问题讨论】:

你的预期输出是什么 第一数据图片和第二数据图片 tableWith5Row 这是什么表。以及其中存在的数据。 它唯一的5行数据只有ID和名称属性gyazo.com/551c9dc60720244c140babd760c0e28a这样 究竟在哪个表中保存了一天的数据,就像你标记了true,然后这个true的条目被保存在特定日期的哪个表中。 【参考方案1】:

因为您的表中已经有这 5 行。现在每次您只想输入相同的新日期,所以最好使用以前的日期数据并使用新的日期数据选择它。

您生成 5 个日期的函数:-

    CREATE FUNCTION [dbo].[tvfCustomDateRange] (@Increment char(1), @StartDate date, @EndDate date) 
    RETURNS @SelectedRange TABLE (cDate date) 
    AS
    BEGIN 

          ;WITH cteRange (DateRange) AS (
                SELECT @StartDate
                UNION ALL
                SELECT 
                      CASE
                            WHEN @Increment = 'd' THEN DATEADD(dd, 1, DateRange)
                            WHEN @Increment = 'w' THEN DATEADD(ww, 1, DateRange)
                            WHEN @Increment = 'm' THEN DATEADD(mm, 1, DateRange)
                      END
                FROM cteRange
                WHERE DateRange <= 
                      CASE
                            WHEN @Increment = 'd' THEN DATEADD(dd, -1, @EndDate)
                            WHEN @Increment = 'w' THEN DATEADD(ww, -1, @EndDate)
                            WHEN @Increment = 'm' THEN DATEADD(mm, -1, @EndDate)
                      END)

          INSERT INTO @SelectedRange (cDate)
          SELECT DateRange
          FROM cteRange
          OPTION (MAXRECURSION 3660);
          RETURN
    END


    CREATE FUNCTION [dbo].[tvfGenerate5Row] (@BeginDate DateTimeOffset, @EndDate Datetimeoffset)
    RETURNS TABLE 
    AS
    RETURN 
    (
        SELECT tblCustom.Name,tblCustom.cDate, tblCustom.ID, 0   AS CHECKBOX
        FROM  (SELECT cDate, Name, ID
               FROM tvfCustomDateRange('d', @BeginDate, @EndDate) CROSS JOIN tableWith5Row) AS tblCustom 
    )

并得到你的输出结果:

    ; WITH CTE AS (
    select ID, MAX(CDATE) AS CDATE from dbo.tvfGenerate5Row( '2019-08-13', '2019-08-15' ) GROUP BY ID 
    )
    SELECT CTE.ID, CTE.CDATE , CASE WHEN D.QUANTITY=1 THEN 1 ELSE 0 END AS CC FROM CTE 
    CROSS APPLY (
           SELECT ID, MAX(QUANTITY) AS QUANTITY 
           FROM tblProduce AS TP 
           WHERE CTE.ID=TP.Idtbl5Row 
           AND QUANTITY = 1
    ) AS D

对于您在评论中提到的情况,认为您已经有回溯的条目。因此,您获得预期结果所需的查询将是:

    ; WITH CTE AS (
    select ID, MAX(CDATE) AS CDATE from dbo.tvfGenerate5Row( '2019-08-13', '2019-08-15' ) GROUP BY ID )
    , CT AS (
    SELECT CTE.ID,  CTE.CDATE  , CASE WHEN D.QUANTITY=1 THEN 1 ELSE 0 END AS CC FROM CTE 
    CROSS APPLY (SELECT ID, MAX(QUANTITY) AS QUANTITY  FROM tblProduce AS TP WHERE CTE.ID=TP.Idtbl5Row and QUANTITY=1  ) AS D
    ) 
    SELECT CT.ID, 
    CASE WHEN tblProduce.CHECKBOX = 1 THEN tblProduce.CDATE ELSE CT.CDATE END AS CDATE, 
    CASE WHEN tblProduce.CHECKBOX = 1 THEN tblProduce.QUANTITY ELSE 1 END AS QUANTITY 
    FROM CT LEFT JOIN ( SELECT * FROM tblProduce WHERE CHECKBOX=1 ) tblProduce ON CT.ID=tblProduce.Idtbl5Row

【讨论】:

感谢您的帮助,但我只想在复选框为 True 时获取以前的数据,如果复选框为 False,它应该生成新行。所以当我将第一行更改为 True 时,下一个数据应该生成 4 Row + 1 Previous Row Data。当我将第一行和第三行更改为 true 时,下一个数据应该生成 3 行 + 2 个上一行数据取决于 PrimaryKey 和 Name 谢谢你的回答,我试试这个 哦,对不起,你的答案绝对有效,但我还没有在我的真实桌子上尝试过,但我认为你的答案会在我的真实桌子上有效,我会试试这个晚上的真实代码,现在是下午 5 点,谢谢顺便说一句......真的对我有很大帮助(我在我的真实代码上测试后检查解决按钮) 而且我还需要更改您的答案并将其放入我的 [dbo].[tvfGenerate5Row] 代码中,因为 [dbo].[tvfGenerate5Row] 是我在 VB 上调用的那个行

以上是关于如何在 SQL SERVER 2017 SSMS 中用以前保存的行值替换行值的主要内容,如果未能解决你的问题,请参考以下文章

在 SSMS (SQL Server) 中创建表

SQL Server:无法通过 SSMS 编辑数据

如何在 SQL Server 2014 中从 SQL Server 2008 R2 恢复备份?

docker快速部署sql server 2017开发版

理解性能的奥秘——应用程序中慢,SSMS中快——SQL Server如何编译动态SQL

如何使数据库转到 SQL Server 而不是 localDB?