我想解决这个问题,避免使用游标(FETCH)。
问题出现了......
1st Table/quantity
------------------
periodid periodstart periodend quantity
1 2010/10/01 2010/10/15 5
2st Table/sold items
-----------------------
periodid periodstart periodend solditems
14343 2010/10/05 2010/10/06 2
现在我想获得以下视图或仅查询结果
Table Table/stock
-----------------------
periodstart periodend itemsinstock
2010/10/01 2010/10/04 5
2010/10/05 2010/10/06 3
2010/10/07 2010/10/15 5
如果不使用游标,或者不使用单个日期而不使用句点,似乎无法解决此问题。
我将不胜感激。
由于
答案 0 :(得分:2)
DECLARE @t1 TABLE (periodid INT,periodstart DATE,periodend DATE,quantity INT)
DECLARE @t2 TABLE (periodid INT,periodstart DATE,periodend DATE,solditems INT)
INSERT INTO @t1 VALUES(1,'2010-10-01T00:00:00.000','2010-10-15T00:00:00.000',5)
INSERT INTO @t2 VALUES(14343,'2010-10-05T00:00:00.000','2010-10-06T00:00:00.000',2)
DECLARE @D1 DATE
SELECT @D1 = MIN(P) FROM (SELECT MIN(periodstart) P FROM @t1
UNION ALL
SELECT MIN(periodstart) FROM @t2) D
DECLARE @D2 DATE
SELECT @D2 = MAX(P) FROM (SELECT MAX(periodend) P FROM @t1
UNION ALL
SELECT MAX(periodend) FROM @t2) D
;WITH
L0 AS (SELECT 1 AS c UNION ALL SELECT 1),
L1 AS (SELECT 1 AS c FROM L0 A CROSS JOIN L0 B),
L2 AS (SELECT 1 AS c FROM L1 A CROSS JOIN L1 B),
L3 AS (SELECT 1 AS c FROM L2 A CROSS JOIN L2 B),
L4 AS (SELECT 1 AS c FROM L3 A CROSS JOIN L3 B),
Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS i FROM L4),
Dates AS(SELECT DATEADD(DAY,i-1,@D1) AS D FROM Nums where i <= 1+DATEDIFF(DAY,@D1,@D2)) ,
Stock As (
SELECT D ,t1.quantity - ISNULL(t2.solditems,0) AS itemsinstock
FROM Dates
LEFT OUTER JOIN @t1 t1 ON t1.periodend >= D and t1.periodstart <= D
LEFT OUTER JOIN @t2 t2 ON t2.periodend >= D and t2.periodstart <= D ),
NStock As (
select D,itemsinstock, ROW_NUMBER() over (order by D) - ROW_NUMBER() over (partition by itemsinstock order by D) AS G
from Stock)
SELECT MIN(D) AS periodstart, MAX(D) AS periodend, itemsinstock
FROM NStock
GROUP BY G, itemsinstock
ORDER BY periodstart
答案 1 :(得分:1)
希望比马丁更容易阅读。我使用了不同的表格和样本数据,希望能够推断出正确的信息:
CREATE TABLE [dbo].[Quantity](
[PeriodStart] [date] NOT NULL,
[PeriodEnd] [date] NOT NULL,
[Quantity] [int] NOT NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[SoldItems](
[PeriodStart] [date] NOT NULL,
[PeriodEnd] [date] NOT NULL,
[SoldItems] [int] NOT NULL
) ON [PRIMARY]
INSERT INTO Quantity (PeriodStart,PeriodEnd,Quantity)
SELECT '20100101','20100115',5
INSERT INTO SoldItems (PeriodStart,PeriodEnd,SoldItems)
SELECT '20100105','20100107',2 union all
SELECT '20100106','20100108',1
现在的实际查询是:
;WITH Dates as (
select PeriodStart as DateVal from SoldItems union select PeriodEnd from SoldItems union select PeriodStart from Quantity union select PeriodEnd from Quantity
), Periods as (
select d1.DateVal as StartDate, d2.DateVal as EndDate
from Dates d1 inner join Dates d2 on d1.DateVal < d2.DateVal left join Dates d3 on d1.DateVal < d3.DateVal and d3.DateVal < d2.DateVal where d3.DateVal is null
), QuantitiesSold as (
select StartDate,EndDate,COALESCE(SUM(si.SoldItems),0) as Quantity
from Periods p left join SoldItems si on p.StartDate < si.PeriodEnd and si.PeriodStart < p.EndDate
group by StartDate,EndDate
)
select StartDate,EndDate,q.Quantity - qs.Quantity
from QuantitiesSold qs inner join Quantity q on qs.StartDate < q.PeriodEnd and q.PeriodStart < qs.EndDate
结果是:
StartDate EndDate (No column name)
2010-01-01 2010-01-05 5
2010-01-05 2010-01-06 3
2010-01-06 2010-01-07 2
2010-01-07 2010-01-08 4
2010-01-08 2010-01-15 5
说明:我使用了三种公用表表达式。第一个(日期)收集了我们正在谈论的所有日期,从所涉及的两个表中。第二个(期间)从日期CTE中选择连续值。然后第三个(QuantitiesSold)在SoldItems表中找到与这些时段重叠的项目,并将它们的总数相加。保留在外部选择中的所有内容都是从数量表
中存储的总数量中减去这些数量答案 2 :(得分:0)
约翰,你能做的是一个WHILE循环。在循环之前声明并初始化2个变量,一个是开始日期,另一个是结束日期。你的循环看起来像这样:
WHILE(@StartEnd <= @EndDate)
BEGIN
--processing goes here
SET @StartEnd = @StartEnd + 1
END
您需要将期间定义存储在另一个表中,以便在需要临时表时检索这些并输出行。
如果您需要更详细的示例,或者我的错误结束,请告诉我们!
答案 3 :(得分:0)
达明,
我正在尝试完全理解您的解决方案并对大量数据进行测试,但我收到了以下错误代码。
Msg 102,Level 15,State 1,Line 20
“日期”附近的语法不正确。
Msg 102,Level 15,State 1,Line 22
','附近的语法不正确。
Msg 102,Level 15,State 1,Line 25
','附近的语法不正确。
答案 4 :(得分:0)
达明,
根据您的解决方案,我还希望为StockItems提供一个整洁的显示,而不会重叠日期。这个解决方案怎么样?
CREATE TABLE [dbo].[SoldItems](
[PeriodStart] [datetime] NOT NULL,
[PeriodEnd] [datetime] NOT NULL,
[SoldItems] [int] NOT NULL
) ON [PRIMARY]
INSERT INTO SoldItems (PeriodStart,PeriodEnd,SoldItems)
SELECT '20100105','20100106',2 union all
SELECT '20100105','20100108',3 union all
SELECT '20100115','20100116',1 union all
SELECT '20100101','20100120',10
;WITH Dates as (
select PeriodStart as DateVal from SoldItems
union
select PeriodEnd from SoldItems
union
select PeriodStart from Quantity
union
select PeriodEnd from Quantity
), Periods as (
select d1.DateVal as StartDate, d2.DateVal as EndDate
from Dates d1
inner join Dates d2 on d1.DateVal < d2.DateVal
left join Dates d3 on d1.DateVal < d3.DateVal and
d3.DateVal < d2.DateVal where d3.DateVal is null
), QuantitiesSold as (
select StartDate,EndDate,SUM(si.SoldItems) as Quantity
from Periods p left join SoldItems si on p.StartDate < si.PeriodEnd and si.PeriodStart < p.EndDate
group by StartDate,EndDate
)
select StartDate,EndDate, qs.Quantity
from QuantitiesSold qs
where qs.quantity is not null