在两个案例参数(日期范围和行数)之间循环| SQL Server 2012

在两个案例参数(日期范围和行数)之间循环| SQL Server 2012,sql,sql-server,date,case,Sql,Sql Server,Date,Case,我试图理解如何正确地执行这个表中的查询。 输出应仅基于计数表循环,但将显示表行参数内的所有日期 我将数据库分为APPLE、ORANGE和MANGO,因为我需要模拟我的数据库结构。数据应该从不同的数据库中调用,然后处理日期范围和行计数的循环 我从这个问题中得到了想法,并使用一些代码尝试复制它: 这是预期的输出 这就是我试图解决的问题 DECLARE @dbApple TABLE ( FromDate VARCHAR(30)

我试图理解如何正确地执行这个表中的查询。 输出应仅基于计数表循环,但将显示表行参数内的所有日期

我将数据库分为APPLE、ORANGE和MANGO,因为我需要模拟我的数据库结构。数据应该从不同的数据库中调用,然后处理日期范围和行计数的循环

我从这个问题中得到了想法,并使用一些代码尝试复制它:

这是预期的输出

这就是我试图解决的问题

DECLARE @dbApple TABLE
                 (
                     FromDate VARCHAR(30) NOT NULL,
                     ToDate VARCHAR(30) NOT NULL,
                     Name VARCHAR(30) NOT NULL,
                     Count VARCHAR(30) NOT NULL
                 )

INSERT INTO @dbApple (FromDate, ToDate, Name, Count) 
VALUES ('2019-10-05', '2019-10-09', 'APPLE', '3');

DECLARE @dbOrange TABLE
                  (
                      FromDate VARCHAR(30) NOT NULL,
                      ToDate VARCHAR(30) NOT NULL,
                      Name VARCHAR(30) NOT NULL,
                      Count VARCHAR(30) NOT NULL
                  )

INSERT INTO @dbOrange (FromDate, ToDate, Name, Count) 
VALUES ('2019-10-10', '2019-10-14', 'ORANGE', '2'); 

DECLARE @dbMango TABLE
                 (
                      FromDate VARCHAR(30) NOT NULL,
                      ToDate VARCHAR(30) NOT NULL,
                      Name VARCHAR(30) NOT NULL,
                      Count VARCHAR(30) NOT NULL
                  )

INSERT INTO @dbMango (FromDate, ToDate, Name, Count) 
VALUES ('2019-10-15', '2019-10-19', 'MANGO', '4');  

(SELECT
     CONVERT(DATE, CONVERT(DATE, DATEADD(D, v.number, FromDate))) AS Date,
     DB.Name,
     CASE 
        WHEN ROW_NUMBER() OVER(PARTITION BY Count, FromDate, ToDate ORDER BY Count) = Count
           THEN Count
           ELSE NULL 
     END AS Count
 FROM 
     @dbApple DB
 JOIN 
     MASTER..spt_values v ON v.TYPE = 'P'
                          AND v.number BETWEEN 0 AND DATEDIFF(D, FromDate, ToDate))

UNION 

(SELECT
     CONVERT(DATE, DATEADD(D, v.number, FromDate)) AS Date,
     DB.Name,
     CASE 
        WHEN ROW_NUMBER() OVER(PARTITION BY Count, FromDate, ToDate ORDER BY Count) = Count
           THEN Count
           ELSE NULL 
     END AS Count
 FROM 
     @dbOrange DB
 JOIN 
     MASTER..spt_values v ON v.TYPE = 'P'
                          AND v.number BETWEEN 0 AND DATEDIFF(D, FromDate, ToDate))

UNION 

(SELECT
     CONVERT(DATE, DATEADD(D, v.number, FromDate)) AS Date,
     DB.Name,
     CASE 
        WHEN ROW_NUMBER() OVER(PARTITION BY Count, FromDate, ToDate ORDER BY Count) = Count 
           THEN Count
           ELSE NULL 
     END AS Count
 FROM 
     @dbMango DB
 JOIN 
     MASTER..spt_values v ON v.TYPE = 'P'
                          AND v.number BETWEEN 0 AND DATEDIFF(D, FromDate, ToDate))
这是输出:

试着在箱子里用箱子,但运气不好。 在CASE中使用CASE输出


通过理货,您可以非常轻松地实现这一点:

CREATE TABLE dbo.YourTable (Fruit varchar(20),
                            Quantity int);

INSERT INTO dbo.YourTable
VALUES ('Apple',3),
       ('Orange',2),
       ('Mango',4);
GO

DECLARE @StartDate date = '20190101',
        @EndDate date = '20190110';

--Going to us a tally, incase there can be large date ranges
WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT TOP(DATEDIFF(DAY, @StartDate, @EndDate)+1) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))  AS I
    FROM N N1, N N2, N N3) --1000 rows
SELECT DATEADD(DAY, T.I-1, @StartDate) aS [Date],
       YT.Fruit,
       CASE WHEN T.I <= YT.Quantity THEN 1 END AS [Count]
FROM dbo.YourTable YT
     CROSS JOIN Tally T    
ORDER BY Fruit,
         [Date];
GO
DROP TABLE dbo.YourTable

递归地解决这个问题怎么样

首先把水果放在篮子里,然后剥皮

WITH BASKET AS 
(
   SELECT FromDate, ToDate, Name, Count
   FROM @dbApple
   UNION ALL
   SELECT FromDate, ToDate, Name, Count
   FROM @dbOrange
   UNION ALL
   SELECT FromDate, ToDate, Name, Count
   FROM @dbMango
),
PEELED AS
(
    SELECT 
     FromDate as [Date], 1 as Lvl,
     FromDate, ToDate, Name, Count
    FROM BASKET

    UNION ALL

    SELECT 
     DATEADD(day,1,[Date]), Lvl +1, 
     FromDate, ToDate, Name, Count
    FROM PEELED p
    WHERE [Date] < ToDate
)
SELECT [Date], [Name], 
CASE WHEN Lvl <= Count THEN 1 END AS [Count]
FROM PEELED
ORDER BY [Date];

在rextester上的一个测试

为什么将日期存储为VARCHAR30而不是简单地存储为DATETIME?关于中的数字的相同问题以及为什么创建三个相同的表,真的吗??您可以只使用一个表格,并用另一个列来区分存储的水果类型…@Markschultheis抱歉,我这么做是出于匆忙,我只是想实现这个概念,因为我有一个项目需要这个流程才能工作。我试图学习它背后的逻辑。@marc_s我试图在我的主数据库中复制一个场景,我只把这些变量作为例子。我喜欢这个解决方案。这解决了它!非常感谢。我只是将上面的数据库用作我试图在数据库中实现的场景的复制。我喜欢这个解决方案,因为它也可以为一个包含值的表进行重构。抱歉,我在这里稍微重命名了一些内容,其中包括SELECT FromDate、ToDate、FROUTHNAME、FROUTHCOUNT FROM@MyData、True、,但这样你就不需要篮子了。直接在剥离的递归CTE中使用@MyData就可以了。这个方法对这个问题有效,因为这些日期并不重叠。否则它将需要一些调整。是的,但它适用于1-n个表,不是您所说的所有情况下的完全通用解决方案,但对于这个问题,我也喜欢它。我试图从我的主数据库复制这个概念,我只将这些变量分开放置,因为在我的主数据库中,我需要显示的变量来自不同的数据库。
WITH BASKET AS 
(
   SELECT FromDate, ToDate, Name, Count
   FROM @dbApple
   UNION ALL
   SELECT FromDate, ToDate, Name, Count
   FROM @dbOrange
   UNION ALL
   SELECT FromDate, ToDate, Name, Count
   FROM @dbMango
),
PEELED AS
(
    SELECT 
     FromDate as [Date], 1 as Lvl,
     FromDate, ToDate, Name, Count
    FROM BASKET

    UNION ALL

    SELECT 
     DATEADD(day,1,[Date]), Lvl +1, 
     FromDate, ToDate, Name, Count
    FROM PEELED p
    WHERE [Date] < ToDate
)
SELECT [Date], [Name], 
CASE WHEN Lvl <= Count THEN 1 END AS [Count]
FROM PEELED
ORDER BY [Date];