我有一个存储过程。如果我想获取两个日期时间之间的行,则可以使用类似的内容:
SELECT *
FROM Orders
WHERE OrderDate BETWEEN @dateTimeFrom AND @dateTimeTo;
当数据库中的日期不是日期时间,而是整数时,该怎么办?
我在这样的条件下尝试过:
WHERE
@fromYear <= GS.[Year] AND GS.[Year] <= @toYear
AND @fromMonth <= GS.[Month] AND GS.[Month] <= @toMonth
AND @fromDay <= GS.[Day] AND GS.[Day] <= @toDay
无法正常工作。
我也尝试过:
AND DATEFROMPARTS(GS.[Year], GS.[Month], GS.[Day]) BETWEEN CAST(@from AS date) AND CAST(@to AS date)
编辑:完整过程:
ALTER PROCEDURE [dbo].[Stats]
@from VARCHAR(15) = NULL,
@to VARCHAR(15) = NULL
AS
BEGIN
SET nocount ON;
DECLARE @fromYear INT = NULL;
SET @fromYear = CASE WHEN @from IS NOT NULL THEN Datepart(year, @from) END
SELECT @fromYear
DECLARE @fromMonth INT = NULL;
SET @fromMonth = CASE WHEN @from IS NOT NULL THEN Datepart(month, @from) END
SELECT @fromMonth
DECLARE @fromDay INT = NULL;
SET @fromDay = CASE WHEN @from IS NOT NULL THEN Datepart(day, @from) END
SELECT @fromDay
DECLARE @toYear INT = NULL;
SET @toYear = CASE WHEN @to IS NOT NULL THEN Datepart(year, @to) ELSE @fromYear END
SELECT @toYear
DECLARE @toMonth INT = NULL;
SET @toMonth = CASE WHEN @to IS NOT NULL THEN Datepart(month, @to) ELSE @fromMonth END
SELECT @toMonth
DECLARE @toDay INT = NULL;
SET @toDay = CASE WHEN @to IS NOT NULL THEN Datepart(day, @to) ELSE @fromDay END
SELECT @toDay
SELECT
GS.[name]
FROM
[dbo].[gamestatsdaily] AS GS
WHERE
(@from IS NULL OR (@fromYear <= GS.[Year] AND GS.[Year] <= @toYear
AND @fromMonth <= GS.[Month] AND GS.[Month] <= @toMonth
AND @fromDay <= GS.[Day] AND GS.[Day] <= @toDay))
ORDER BY
GS.[year] ASC, GS.[month] ASC, GS.[day] ASC
END
数据示例:
Name Day Month Year
----------------------------------
Microsoft 24 5 2018
Apple 12 7 2018
Thor 13 8 2018
答案 0 :(得分:0)
正如我在评论中所说,这里的真正答案是修复您的数据定义。答案包括同时使用DATEFROMPARTS
(“简单”答案)和“差”答案;因为查询将是非SARGable的。但是,它还有一个答案,可以将列的数据类型更改为应为int
的列,然后向表中添加一个PERSISTED
计算列,可以查询该列:
USE Sandbox;
GO
CREATE TABLE SomeTable (ID int IDENTITY(1,1),
TheYear varchar(15), --Should be an int
TheMonth varchar(15), --Should be an int
TheDay varchar(15)); --Should be an int
INSERT INTO dbo.SomeTable (TheYear,
TheMonth,
TheDay)
VALUES('2018','06','01'),
('2018','06','05'),
('2018','06','15'),
('2018','06','20'),
('2018','06','22'),
('2018','06','23'),
('2018','07','01'),
('2018','07','03');
GO
DECLARE @StartDate date, @EndDate date;
SET @StartDate = '20180620';
SET @EndDate = '20180630';
--Non SARGable answer:
SELECT *
FROM dbo.SomeTable
--A load of TRY_CONVERT because you've chosen a varchar to store an int. Thus your data can't be trusted to contain an int.
WHERE DATEFROMPARTS(TRY_CONVERT(int,TheYear),TRY_CONVERT(int,TheMonth),TRY_CONVERT(int,TheDay)) BETWEEN @StartDate AND @EndDate;
GO
--The real answer:
--Firstly, let's fix those data types:
ALTER TABLE dbo.SomeTable ADD TheYearI int;
ALTER TABLE dbo.SomeTable ADD TheMonthI int;
ALTER TABLE dbo.SomeTable ADD TheDayI int;
--And update the values
GO
UPDATE dbo.SomeTable
SET TheYearI = TRY_CONVERT(int,TheYear),
TheMonthI = TRY_CONVERT(int,TheMonth),
TheDayI = TRY_CONVERT(int,TheDay);
GO
--Drop the old columns
ALTER TABLE dbo.SomeTable DROP COLUMN TheYear;
ALTER TABLE dbo.SomeTable DROP COLUMN TheMonth;
ALTER TABLE dbo.SomeTable DROP COLUMN TheDay;
GO
--Rename the new columns
EXEC sp_rename 'dbo.SomeTable.TheYearI','TheYear','COLUMN';
EXEC sp_rename 'dbo.SomeTable.TheMonthI','TheMonth','COLUMN';
EXEC sp_rename 'dbo.SomeTable.TheDayI','TheDay','COLUMN';
GO
--Creat the new computed column
ALTER TABLE dbo.SomeTable ADD TheDate AS DATEFROMPARTS(TheYear, TheMonth, TheDay) PERSISTED;
GO
--And now the simple query:
DECLARE @StartDate date, @EndDate date;
SET @StartDate = '20180620';
SET @EndDate = '20180630';
SELECT *
FROM dbo.SomeTable
WHERE TheDate BETWEEN @StartDate AND @EndDate;
GO
DROP TABLE dbo.SomeTable;
GO
答案 1 :(得分:0)
这种方法可能会起作用,但是您确实应该尝试修复该数据。
;WITH Orders (Name, [Day], [Month], [Year]) AS (
SELECT * FROM (
VALUES
('Microsoft', 24, 5, 2018),
('Apple', 12, 7, 2018),
('Thor', 13, 8, 2018)
) AS A (Name, [Day], [Month], [Year])
)
SELECT * FROM Orders
WHERE Cast(STR([Month]) + '/' + STR([Day]) + '/' + STR([Year]) AS DATETIME)
BETWEEN '04/02/2018' AND '07/03/2018'