将开始日期和结束日期之间的所有日期插入表中

时间:2020-11-12 15:02:02

标签: c# sql sql-server

假设我有2张桌子

第一个是“订单”

Select * from Orders

给我这个结果。

 Order_ID   Date_Start          Date_End                                   Order_Name
2059    2020-11-13 00:00:00.000 2020-11-14 00:00:00.000             order1
2060    2020-12-12 00:00:00.000 2020-12-22 00:00:00.000             order2

第二张桌子说它是“日期”

这是“日期”表的理想结果。我需要为每个订单ID在该表的两个日期之间插入日期。

Date                    Type1   Type2   Type3   Type4   Type5   Order_ID
2020-11-13 00:00:00.000 NULL    NULL    NULL    NULL    NULL    2059
2020-11-14 00:00:00.000 NULL    NULL    NULL    NULL    NULL    2059

我希望现在可以更清楚了。

2 个答案:

答案 0 :(得分:2)

使用OVER / PARTITION,然后使用dateadd(),实际上非常简单。

首先,我们需要在最终记录列表中获取任意数量的记录。为此,请选择至少具有所需行数的任何表。可以是员工表,客户,订单等。对于您的示例,只要有14天。由此,只要创建一个临时结果集,只要表格中有这么多记录,就可以简单地将数字1遍历任何数字... 10、14、127,任何数字。

现在,按顺序进行分区是技巧的一部分。您不能按常量进行分区,但是可以基于方程式进行分区。因此,选择任何表的“ ID”列并乘以0总是得到0。因此,您的分区将对等值等于0的所有值进行分组...棘手的...所以现在,所有记录都归入这一组,并​​在该组内分配一个行号。通过“ TOP 14”结束这一工作,您将获得14条记录以开始您的列表基础。

SELECT top 10
        ROW_NUMBER() OVER(PARTITION BY SomeTableID * 0 order by SomeTableID * 0) AS "MyRow"
    FROM 
        SomeTable

所以现在,我有一个结果集,其中包含10行,其值从1到10。

现在,让我们建立日期。只要您是连续构建的(例如每天,每月,每年或任何模式),就以一个日期作为基准并继续添加。在下面的示例中,我使用的是当前日期,并且继续添加1个月,但是同样,您可以执行数天,数周的操作。

select
      dateadd( month, Counter.MyRow, convert( date, getdate() )) ListOfDates
   from
      ( SELECT top 10 ROW_NUMBER() 
              OVER(PARTITION BY SomeTableID * 0 order by SomeTableID * 0) AS "MyRow"
           FROM SomeTable ) Counter

因此,在上面的示例中,它将从今天开始返回10行并生成

2020-11-20
2020-12-20
2021-01-20
...
2021-08-20

跟进。

您的查询失败,因为您正在显式连接字符串以构建命令...错误技术。您应该参数化您的查询。构建一个SQL Command对象,添加参数,然后调用您的填充。

var sqlcmd = new SqlCommand("", con);
sqlcmd.CommandText = 
@"WITH theDates AS 
(
   SELECT @parmStartDate as theDate
   UNION ALL
   SELECT DATEADD(day, 1, theDate)
      FROM theDates
      WHERE DATEADD(day, 1, theDate) <= @parmEndDate
)

SELECT theDate
   FROM theDates
   OPTION(MAXRECURSION 0)";


sqlcmd.Parameters.AddWithValue("parmStartDate", dataGridView.CurrentRow.Cells[2] );
sqlcmd.Parameters.AddWithValue("parmEndDate", dataGridView.CurrentRow.Cells[3] );

var ds = new DataSet();
var dtbl2 = new DataTable();
// pass the pre-formatted and parameterized query command to the SQL Data Adapter
var sda2 = new SqlDataAdapter(sqlcmd);

答案 1 :(得分:1)

以下是一些用于构建动态日期范围表的sql。在联接 /和/ 联接表节* /

之后,您需要根据需要在/ *列中自定义它。

/*
script to build table with dynamic columns
*/
DROP TABLE IF EXISTS #tempDateRange
DROP TABLE IF EXISTS #dateRangeTable

DECLARE @StartDate datetime = DATEADD(DAY, -14, GETDATE()), 
@EndDate datetime = GETDATE()

/*
Generate date range table
*/
SELECT  DATEADD(DAY, nbr - 1, @StartDate) AS [Date],
UPPER(LEFT(DATENAME(mm, DATEADD(DAY, nbr - 1, @StartDate)), 3)) AS [MonthShort],
MONTH( DATEADD(DAY, nbr - 1, @StartDate)) AS [Month],
YEAR(DATEADD(DAY, nbr - 1, @StartDate)) AS [Year],
CONCAT(UPPER(LEFT(DATENAME(mm, DATEADD(DAY, nbr - 1, @StartDate)), 3)), '-', YEAR(DATEADD(DAY, nbr - 1, @StartDate))) AS MonthYear
INTO #tempDateRange
FROM    ( SELECT TOP(DATEDIFF(DAY, @StartDate, @EndDate)) ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n AS Nbr
            FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) ones(n),
                 (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) tens(n),
                 (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) hundreds(n),
                 (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) thousands(n)
            WHERE ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n BETWEEN 1 AND DATEDIFF(DAY, @StartDate, @EndDate)
            ORDER BY 1
        ) nbrs
WHERE   nbr - 1 <= DATEDIFF(DAY, @StartDate, @EndDate)

/*
Generate columns for date range
*/
DECLARE 
    @columns NVARCHAR(MAX) = ''
SELECT @columns+=QUOTENAME(convert(nvarchar(10), Date, 120)) + ' NVARCHAR(10),' 
FROM (
    SELECT DISTINCT Date, [Month], [Year] FROM #tempDateRange
) x
ORDER BY x.[Year], x.[Month]
SET @columns = LEFT(@columns, LEN(@columns) - 1);

DECLARE @sql NVARCHAR(MAX) = ''
SET @sql = '

INSERT #dateRangeTable
SELECT *
FROM (
    SELECT a.TestData AS Data, /* replace with your column after join */
    convert(nvarchar(10), Date, 120) AS [Date]
    FROM #tempDateRange [date]
    /* Join your table */
    LEFT JOIN (
        SELECT ''start test'' AS TestData,  CAST('''+CONVERT(NVARCHAR, @StartDate)+''' AS DATE) AS TargetDate
        UNION 
        SELECT ''end test'' AS TestData,  CAST('''+CONVERT(NVARCHAR, DATEADD(DAY, -1, @EndDate))+''' AS DATE) AS TargetDate
    ) AS a ON CAST(a.TargetDate AS DATE) = CAST(date.[date] AS DATE)
    WHERE [date].[Date] BETWEEN CAST('''+CONVERT(NVARCHAR, @StartDate)+''' AS DATE) AND CAST('''+CONVERT(NVARCHAR, @EndDate)+''' AS DATE)
) o
PIVOT(
    MAX(Data)
    FOR [Date] IN ('+ REPLACE(@columns, 'NVARCHAR(10)', '') +')
) AS pivot_table;
'


SET @sql = N'
DROP TABLE IF EXISTS #dateRangeTable
CREATE TABLE #dateRangeTable('+@columns+')
' + 
@sql 
+ N'
SELECT * FROM #dateRangeTable
DROP TABLE IF EXISTS #dateRangeTable
'
PRINT (@sql)
--EXECUTE sp_executesql @sql

相关问题