问题
I want to populate a datetime column on the fly within a stored procedure. below is the query that I currently have that does same but slows down query performance.
CREATE TABLE #TaxVal
(
ID INT
, PaidDate DATETIME
, CustID INT
, CompID INT
)
INSERT INTO #TaxVal(ID, PaidDate, CustID, CompID)
VALUES(01, '20150201',12, 100)
, (03,'20150301', 18,101)
, (10,'20150401',19,22)
, (17,'20150401',02,11)
, (11,'20150411',18,201)
, (78,'20150421',18,299)
, (133,'20150407',18,101)
-- SELECT * FROM #TaxVal
DECLARE @StartDate DATETIME = '20150101'
, @EndDate DATETIME = '20150501'
DECLARE @Tab TABLE
(
CompID INT
, DateField DATETIME
)
DECLARE @T INT
SET @T = 0
WHILE @EndDate >= @StartDate + @T
BEGIN
INSERT INTO @Tab
SELECT CompID
, @StartDate + @T AS DateField
FROM #TaxVal
WHERE CustID = 18
AND CompID = 101
ORDER BY DateField DESC
SET @T = @T + 1
END
SELECT DISTINCT * FROM @Tab
DROP TABLE #TaxVal
Which is the best way to write this query for better performance?
回答1:
Change this:
DECLARE @T INT
SET @T = 0
WHILE @EndDate >= @StartDate + @T
BEGIN
INSERT INTO @Tab
SELECT CompID
, @StartDate + @T AS DateField
FROM #TaxVal
WHERE CustID = 18
AND CompID = 101
ORDER BY DateField DESC
SET @T = @T + 1
END
to this:
;with cte as(
select cast('20150101' as date) as d
union all
select dateadd(dd, 1, d) as d from cte where d < '20150501'
)
INSERT INTO @Tab
SELECT CompID, d
FROM #TaxVal
cross join cte
WHERE CustID = 18 AND CompID = 101
Option(maxrecursion 0)
Here is recursive common table expression
to get all dates in range. Then you do a cross join
and insert. Notice that there is no sense to order set while inserting.
回答2:
Giorgi's answer of
;with cte as(
select cast('20150101' as date) as d
union all
select dateadd(dd, 1, d) as d from cte where d < '20150501'
)
INSERT INTO @Tab
SELECT CompID, d
FROM #TaxVal
cross join cte
WHERE CustID = 18 AND CompID = 101
will work, but be careful with recursive CTE's. If the date range is large, you'll quickly hit your maximum recursion level. Often, a numbers table is used much like HABO mentioned. This is simply a table with a single column that only a integer so the rows would be 1, 2, 3, 4, 5, etc. You can then join the Numbers table (outer apply works well for this) and use the numbers with dateadd to get your incremental dates. Also note that you can run into an issue where the Numbers table doesn't contain enough rows for you date range.
来源:https://stackoverflow.com/questions/29945952/populating-a-datetime-column