读书人

为何查不到想要的结果

发布时间: 2012-12-15 15:16:03 作者: rapoo

高手请进, 为何查不到想要的结果
想查 特定日期之间的数据, 不知这个函数有什么问题, 一直看不出来 。

IF EXISTS(
SELECT *
FROM dbo.sysobjects
WHERE id = OBJECT_ID(N'[dbo].fn_ltDate')
AND (TYPE = 'FN' OR TYPE = 'TF' OR TYPE = 'IF')
)
BEGIN
PRINT '已存在,删除再新建'
DROP FUNCTION fn_ltDate
END
ELSE
BEGIN
PRINT '不存在,新建'
END
GO

--新建函数
CREATE FUNCTION dbo.fn_ltDate
(
@startDate VARCHAR(10),
@endDate VARCHAR(10)
)
RETURNS BIT
AS
BEGIN
DECLARE @result BIT
SET @result = 0
IF (
LTRIM(RTRIM(ISNULL(@startDate, ''))) = ''
OR LTRIM(RTRIM(ISNULL(@endDate, ''))) = ''
OR DATEDIFF(DAY, @startDate, @endDate) >= 0
)
BEGIN
SET @result = 1
END

RETURN @result
END
GO


DECLARE @TempTalbe TABLE (Id INT, CreateTime DATETIME)

INSERT INTO @TempTalbe
SELECT 1,
'2012-1-2' UNION
SELECT 2,
'2012-3-2' UNION
SELECT 3,
'2012-4-2' UNION
SELECT 4,
'2012-5-2' UNION
SELECT 5,
'2012-6-2'

DECLARE @StartDate1 DATETIME
DECLARE @EndDate1 DATETIME
SET @StartDate1 = '2012-3-2'
SET @EndDate1 =''--为NULL就可以, 为''就不行

SELECT *
FROM @TempTalbe t
WHERE dbo.fn_ltDate(@StartDate1, CreateTime)=1
AND
dbo.fn_ltDate(CreateTime, @EndDate1) = 1



[最优解释]
'' datetime是 1900-01-01 00:00:00.000

改成
LTRIM(RTRIM(ISNULL(@startDate, '1900-01-01 00:00:00.000'))) = '1900-01-01 00:00:00.000'
OR LTRIM(RTRIM(ISNULL(@endDate, '1900-01-01 00:00:00.000'))) = '1900-01-01 00:00:00.000'
OR DATEDIFF(DAY, @startDate, @endDate) >= 0

[其他解释]
SELECT CAST('' AS DATETIME)
/*
1900-01-01 00:00:00.000

(1 行受影响)


*/

[其他解释]
也行

LTRIM(RTRIM(ISNULL(@startDate, ''))) = '1900-1-1'
OR LTRIM(RTRIM(ISNULL(@endDate, ''))) = '1900-1-1'
OR DATEDIFF(DAY, @startDate, @endDate) >= 0


[其他解释]
引用:
同志们啊,我定义的只是字符串, 还没有到转换和比较的那一步嘛。
SQL code?12 @startDate VARCHAR(10), @endDate VARCHAR(10)


我看到的是dateitime...

DECLARE @StartDate1 DATETIME
DECLARE @EndDate1 DATETIME
SET @StartDate1 = '2012-3-2'
SET @EndDate1 =''--为NULL就可以, 为''就不行

[其他解释]
CREATE FUNCTION dbo.fn_ltDate
(
@startDate VARCHAR(10),
@endDate VARCHAR(10)
)
RETURNS BIT
AS
BEGIN
DECLARE @result BIT
SET @result = 0
IF (
CONVERT(DATETIME,LTRIM(RTRIM(ISNULL(@startDate, '')))) = '1900-01-01 00:00:00.000'
OR CONVERT(DATETIME,LTRIM(RTRIM(ISNULL(@endDate, '')))) = '1900-01-01 00:00:00.000'
OR DATEDIFF(DAY, CONVERT(DATETIME,@startDate), CONVERT(DATETIME,@endDate)) >= 0
)
BEGIN
SET @result = 1
END

RETURN @result
END
GO


DECLARE @TempTalbe TABLE (Id INT, CreateTime DATETIME)

INSERT INTO @TempTalbe
SELECT 1,
'2012-1-2' UNION
SELECT 2,
'2012-3-2' UNION
SELECT 3,
'2012-4-2' UNION
SELECT 4,
'2012-5-2' UNION
SELECT 5,
'2012-6-2'

DECLARE @StartDate1 DATETIME
DECLARE @EndDate1 DATETIME
SET @StartDate1 = '2012-3-2'
SET @EndDate1 =''--为NULL就可以, 为''就不行

SELECT *
FROM @TempTalbe t
WHERE dbo.fn_ltDate(@StartDate1, CreateTime)=1
AND
dbo.fn_ltDate(CreateTime, @EndDate1) = 1
[其他解释]
请看上面代码中的第 59 行: SET @EndDate1 =''--为NULL就可以, 为''就不行
[其他解释]
同志们啊,我定义的只是字符串, 还没有到转换和比较的那一步嘛。

@startDate VARCHAR(10),
@endDate VARCHAR(10)



[其他解释]
引用:
引用:同志们啊,我定义的只是字符串, 还没有到转换和比较的那一步嘛。
SQL code?12 @startDate VARCHAR(10), @endDate VARCHAR(10)

我看到的是dateitime...
SQL code?1234DECLARE @StartDate1 DATETIME DECL……



楼主的哥们很细心, 发现了我的错误。
当然喽, 也不算什么错误, 只算是我的函数设计的有bug吧——只能传varchar型的实参,不能传datetime型。

#7的写法也很好,只是可读性差了一点点, 下面是本人修改后的。

在很多系统中, 根据日期范围来查询是很常见的操作。表单中输入 2012-05-01 到 2012-10-01
, 很容易漏掉 2012-10-01 这一天的记录, 而且总要判断 is null 或者空串等也比较麻烦, 故写了这段函数。 谢谢诸位, 希望对诸君有用。


IF EXISTS(
SELECT *
FROM dbo.sysobjects
WHERE id = OBJECT_ID(N'[dbo].fn_ltDate')
AND (TYPE = 'FN' OR TYPE = 'TF' OR TYPE = 'IF')
)
BEGIN
PRINT '已存在,删除再新建'
DROP FUNCTION fn_ltDate
END
ELSE
BEGIN
PRINT '不存在,新建'
END
GO

--Create by: yenange
--Description: 前日期是否<=后面的日期(在同一天也算是小于等于)
--Parameters : @startDate 前日期,@endDate 后日期.
-- 两参数传入时的类型可为 varchar 或者 datetime 型
-- 若有一参数为null或者'', 则返回1 (也算是小于等于)
--Return : 是 1 否 0
CREATE FUNCTION dbo.fn_ltDate
(
@startDate VARCHAR(10),
@endDate VARCHAR(10)
)
RETURNS BIT
AS
BEGIN
DECLARE @result BIT
SET @result = 0
IF (
LTRIM(RTRIM(ISNULL(@startDate, ''))) = ''
OR LTRIM(RTRIM(ISNULL(@endDate, ''))) = ''
OR DATEDIFF(DAY, @startDate, '1900-01-01 00:00:00.000') = 0
OR DATEDIFF(DAY, @endDate, '1900-01-01 00:00:00.000') = 0
OR DATEDIFF(DAY, @startDate, @endDate) >= 0
)
BEGIN
SET @result = 1
END

RETURN @result
END
GO

DECLARE @TempTalbe TABLE (Id INT, CreateTime DATETIME)
INSERT INTO @TempTalbe
SELECT 1,'2012-1-2' UNION
SELECT 2,'2012-3-2 00:00:00' UNION
SELECT 3,'2012-4-2' UNION
SELECT 4,'2012-5-2 23:59:59' UNION
SELECT 5,'2012-6-2 23:59:59'

--参数为 datetime 型
DECLARE @StartDate1 DATETIME
DECLARE @EndDate1 DATETIME
SET @StartDate1 = '2012-3-2'
SET @EndDate1 = ''

SELECT *
FROM @TempTalbe t
WHERE dbo.fn_ltDate(@StartDate1, CreateTime) = 1
AND dbo.fn_ltDate(CreateTime, @EndDate1) = 1

--参数为 varchar 型
DECLARE @StartDate2 VARCHAR(10)
DECLARE @EndDate2 VARCHAR(10)
SET @StartDate1 = '2012-3-2'
SET @EndDate1 = '2012-5-2'
SELECT *
FROM @TempTalbe t
WHERE dbo.fn_ltDate(@StartDate1, CreateTime) = 1
AND dbo.fn_ltDate(CreateTime, @EndDate1) = 1





[其他解释]
引用:
引用:
引用:同志们啊,我定义的只是字符串, 还没有到转换和比较的那一步嘛。
SQL code?12 @startDate VARCHAR(10), @endDate VARCHAR(10)

我看到的是dateitime...
SQL code?1234DECLARE @StartDate1 DATE……
其实日期中为''或者‘0’很容易疏忽,没有想到datetime格式的话就是默认的 '1900-01-01 00:00:00.000'

感谢分享。

[其他解释]
为什么函数不能传递datataime类型的参数?既然是日期,那何必要用varchar等字符串类型呢?

[其他解释]
引用:
为什么函数不能传递datataime类型的参数?既然是日期,那何必要用varchar等字符串类型呢?


最前面的不可以, #8可以(无论实际参数是datetime还是varchar)。

一个好的函数, 最好能有良好的兼容性。

即使你用 datetime 作形参, 人家还是可能传个空串进来, 所以形参用什么关系是不大的。

读书人网 >SQL Server

热点推荐