【问题标题】:SQL ERROR - Explicit conversion from data type int to date is not allowedSQL 错误 - 不允许从数据类型 int 到日期的显式转换
【发布时间】:2018-07-10 08:28:56
【问题描述】:

我有一个包含年份列和月份列的表。年份是 INT,月份是 VARCHAR,如“一月”。我正在创建一个报告,用户应该能够简单地将 To 和 From 日期放入其中。这是我的存储过程。

SQL

ALTER PROCEDURE [Servicing].[ManualAdjustments]

@dateFrom INT,
@dateTo VARCHAR(50)

AS
BEGIN
    SELECT  *
    FROM MyDatabase.dbo.MyTable
    WHERE RefYear BETWEEN CONVERT(DATE,YEAR(@dateFrom)) AND CONVERT(DATE,YEAR(@dateTo))
    AND RefMonth BETWEEN CONVERT(DATE,MONTH(@dateFrom)) AND CONVERT(DATE,MONTH(@dateTo))
END

当我运行它时,它返回“不允许从数据类型 int 到日期的显式转换”。我不确定我在语法上做错了什么。 我查看了关于 SO 的其他示例,但答案完全基于提问者问题,所以我发现很难解决我的问题。

有什么想法吗?

编辑 - 我试过的方法

1

ALTER PROCEDURE [Servicing].[ManualAdjustments]

@dateFrom DATE,
@dateTo DATE

AS
BEGIN
    SELECT  *
    FROM MyDatabase.dbo.MyTable
    WHERE RefYear BETWEEN CONVERT(DATE,YEAR(@dateFrom),0) AND @dateTo
    AND RefMonth BETWEEN CONVERT(DATE,MONTH(@dateFrom),0) AND @dateTo
END
--ERROR -> 'Explicit conversion from data type int to date is not allowed.'

【问题讨论】:

  • 所以您希望日期参数为 int 和 varchar?为什么不是日期数据类型?
  • 我正在使用 Visual Studio 创建报告,因此理想情况下我希望 from 和 to 采用日期格式,以便用户可以使用日历简单地选择日期。我更喜欢转换为日期格式。当我将变量设置为 DATE 时,它不会运行并且我得到这个“操作数类型冲突:日期与 int 不兼容”。
  • 我同意@HoneyBadger @dateFrom@dateTo 应该是数据类型date,毕竟它们日期。跨度>
  • 这个 SQL 没有意义,年/月函数从日期返回年/月作为 int 值 - 您不能将其任意转换为日期。
  • @NikosV 如果用户输入year = 2017 and month = August,您是否希望从01-01-2017 till 31-08-2017 返回结果?

标签: sql sql-server date


【解决方案1】:

此问题的正确解决方案是更改表的结构,创建Date 类型的RefDate 列。假设你不能这样做,你将不得不在你的存储过程中做一些棘手的事情。

但是,在存储过程中,您应该将@dateFrom@dateTo 参数作为Date 类型。

然后您可以使用公用表表达式将月份名称映射到月份编号(因为作为字符串排序时,FebruaryJanuary 之前),然后您可以使用between...and
像这样的东西应该可以解决问题:

ALTER PROCEDURE [Servicing].[ManualAdjustments]

@dateFrom date,
@dateTo date

AS
BEGIN

    With CTEMonths AS
    (
        SELECT Id, Name
        FROM (VALUES 
              (1, 'January'),
              (2, 'February'),
              (3, 'March'),
              (4, 'April'),
              (5, 'May'),
              (6, 'June'),
              (7, 'July'),
              (8, 'August'),
              (9, 'September'),
              (10, 'October'),
              (11, 'November'),
              (12, 'December')
             ) v(Id, Name)
    )

    SELECT  *
    FROM MyDatabase.dbo.MyTable
    JOIN CTEMonths c ON RefMonth = c.Name
    WHERE RefYear BETWEEN YEAR(@dateFrom) AND YEAR(@dateTo)
    AND c.Id BETWEEN MONTH(@dateFrom) AND MONTH(@dateTo)

END

【讨论】:

  • 这样我就明白了。您基本上已经创建了一个包含值和名称的临时表,将临时表连接到公共 RefMonth 列并进行了比较。对吗?
  • A common table expression 不完全是临时表,但您可以这样考虑,所以是的。
  • 好的。我会查查 CTE 看看发生了什么。谢谢。
  • 很高兴为您提供帮助 :-)
【解决方案2】:
DECLARE @Year INT = 2000;
DECLARE @MONTH VARCHAR(50) = 'february';

WITH aDATE
AS (
    SELECT DATEADD(year, @YEAR - 1800,'18000101') X

    UNION ALL

    SELECT DATEADD(month, 1, aDATE.X)
    FROM aDATE
    WHERE YEAR(DATEADD(month, 1, aDATE.X)) % 10 = @YEAr % 10
    )
    ,RANGE
AS (
    SELECT x MonthStart
        ,dateadd(day, - 1, dateadd(month, 1, x)) MonthEnd
    FROM aDATE
    WHERE DATENAME(month, x) = @MONTH
    )
SELECT *
FROM RANGE

【讨论】:

    猜你喜欢
    • 2017-08-27
    • 2012-03-21
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多