两个日期之间的SQL,其中日期用整数表示

时间:2018-07-03 15:23:56

标签: sql-server

我有一个存储过程。如果我想获取两个日期时间之间的行,则可以使用类似的内容:

SELECT * 
FROM Orders
WHERE OrderDate BETWEEN @dateTimeFrom AND @dateTimeTo;

当数据库中的日期不是日期时间,而是整数时,该怎么办?

  • 年份= 2018,月= 6,天= 6

我在这样的条件下尝试过:

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    

2 个答案:

答案 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'