1

我想解决这个问题,避免使用游标(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

如果不使用游标,或者不使用单个日期而不是句点,似乎不可能解决这个问题。

我将不胜感激任何帮助。

谢谢

4

5 回答 5

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
于 2010-10-22T12:57:47.563 回答
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

说明:我正在使用三个公用表表达式。第一个(日期)是从所涉及的两个表中收集我们正在谈论的所有日期。第二个 (Periods) 从 Dates CTE 中选择连续值。然后第三个 (QuantitiesSold) 在 SoldItems 表中查找与这些期间重叠的项目,并将它们的总数加在一起。外部选择中剩下的就是从存储在数量表中的总量中减去这些数量

于 2010-10-22T13:19:44.337 回答
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
于 2010-10-28T10:31:52.163 回答
0

约翰,你可以做的是一个 WHILE 循环。在循环之前声明并初始化 2 个变量,一个是开始日期,另一个是结束日期。您的循环将如下所示:

WHILE(@StartEnd <= @EndDate)
BEGIN
  --processing goes here
  SET @StartEnd = @StartEnd + 1
END

您需要将周期定义存储在另一个表中,以便在需要时检索这些行并将行输出到临时表。

让我知道您是否需要更详细的示例,或者我的方法有误!

于 2010-10-22T12:51:08.240 回答
0

达米安,

我正在尝试完全理解您的解决方案并在大量数据上对其进行测试,但我收到您的代码的以下错误。

消息 102,第 15 级,状态 1,第 20 行

“日期”附近的语法不正确。

消息 102,第 15 级,状态 1,第 22 行

',' 附近的语法不正确。

消息 102,第 15 级,状态 1,第 25 行

',' 附近的语法不正确。

于 2010-10-26T07:16:51.283 回答