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