我有一个查询,我需要从表中获取结果,具体取决于用户在vb.net页面上指定的参数。
声明一个变量将是理想的解决方案,但由于它是一个内联表值函数,我无法做到这一点,我已经读过其他问题,这在多元表函数中是可行的但是使用了这样的不推荐使用功能。
以下查询将是理想的解决方案或我想要实现的目标。
USE [AUDIT]
GO
ALTER FUNCTION [dbo].[GetCreated_LPA_Audits]
(
@fechaInicio nvarchar (max),
@fechaFin nvarchar (max)
@Period int,
@Fecha int
)
RETURNS TABLE
AS
RETURN
(
SELECT T1.Plant,T1.Area,T1.Location,T1.IDAudit,T1.Auditor,T1.AuditDate,T1.DueDate,T1.CreationDate
FROM Header AS T1 inner join Audits AS T2 ON T1.IDChecklist = T2.IDChecklist
inner join AuditGroups AS T3 ON T2.IDGroup = T3.IDGroup
WHERE T3.IDGroup = '2' and CreationDate is not null AND
CASE WHEN @Periodo = '0' THEN CreationDate>= @fechaInicio
WHEN @Periodo = '1' THEN DATEPART(MONTH,CreationDate)>= @Fecha
WHEN @Periodo = '2' THEN
CASE WHEN @Fecha = 13 THEN
DATEPART(MONTH,CreationDate)>= 1
END
WHEN @Periodo = '2' THEN
CASE WHEN @Fecha = 14 THEN
DATEPART(MONTH,CreationDate)>= 7
END
WHEN @Periodo = '3' THEN
CASE WHEN @Fecha = 15 THEN
DATEPART(Year,CreationDate)>= 2015
END
END
AND
CASE WHEN @Periodo = '0' THEN @fechaInicio<=CreationDate
WHEN @Periodo = '1' THEN @Fecha<=DATEPART(MONTH,CreationDate)
WHEN @Periodo = '2' THEN
CASE WHEN @Fecha = 13 THEN
6<=DATEPART(MONTH,CreationDate)
END
WHEN @Periodo = '2' THEN
CASE WHEN @Fecha = 14 THEN
12<=DATEPART(MONTH,CreationDate)
END
WHEN @Periodo = '3' THEN
CASE WHEN @Fecha = 15 THEN
DATEPART(Year,CreationDate)>= 2015
END
END
和 在上一个查询@fechaInicio中,@ fefFin,@ Periodo和@Fecha是用户提供的参数。
基本上如果@Periodo = 0
我需要将结果放在哪里
CreationDate>= @fechaInicio and CreationDate<=@fechaFin
如果@Periodo = 1
我需要将结果放在哪里
DATEPART(MONTH,CreationDate)>= @Fecha and DATEPART(MONTH,CreationDate)<= @Fecha
等等。 希望我提前做好准备,谢谢!
编辑使用来自@MatBailie的伪代码,并对其问题进行了一些修改和回答
IF @periodo = '0' THEN
WHERE CreationDate >= @fechaInicio -- Copied from 1st CASE
AND @fechaFin <= CreationDate -- Copied from 2nd CASE
-- gets results from @fechaInicio to @fechaFin
-- i.e. results from 04/05/2016 to 04/16/2016
IF @periodo = '1' THEN
WHERE DATEPART(MONTH,CreationDate) >= @Fecha -- Copied from 1st CASE
AND @Fecha <= DATEPART(MONTH,CreationDate) -- Copied from 2nd CASE
-- In these case both conditions are the same 'cause
-- @Fecha is the number of a month (1 - 12)
-- i.e. @Fecha = 3 will get all the results of March
-- regardless of what it is on @fechaInicio and @fechaFin
IF @periodo = '2' THEN
IF @fetcha = 13 THEN
WHERE DATEPART(MONTH,CreationDate)>= 1 -- Copied from 1st CASE
AND 6<=DATEPART(MONTH,CreationDate) -- Copied from 2nd CASE
IF @fetcha = 14 THEN
WHERE DATEPART(MONTH,CreationDate)>= 7 -- Copied from 1st CASE
AND 12<=DATEPART(MONTH,CreationDate) -- Copied from 2nd CASE
-- You never use @fetchaInicio?
-- You want everything in the first 6 months or last 6 months
-- For every year
-- Regardless of what is in @fetchaInicio?
-- Exactly!!--
IF @periodo = '3' THEN
IF @fetcha = 15 THEN
WHERE DATEPART(Year,CreationDate)>= 2015 -- Copied from 1st CASE
AND 2015 <= DATEPART(Year,CreationDate) -- Copied from 2nd CASE
--
那个案例@periodo = '2' AND @fetcha NOT IN (13,14)
怎么样?
那个案例@periodo = '3' AND @fetcha NOT IN (15)
?
此案例不存在,仅限于客户端。
如果他们选择@Periodo = '2'
,那么@Fecha
的值将为1 - 12,而不是其他任何内容。
与@Periodo = '3'
相同,则@Fecha
的值为15或16,均指2015年或2016年。
答案 0 :(得分:1)
重新组织WHERE子句要好得多,这样过滤后的字段位于左边,而不是任何函数内部。
例如......
WHERE
CreationDate >= @VPeriodo
AND CreationDate < CASE
WHEN @Periodo = '0' THEN DATEADD(DAY, 1, @VPeriodo)
WHEN @Periodo = '1' THEN DATEADD(MONTH, 1, @VPeriodo)
WHEN @Periodo = '2' THEN DATEADD(MONTH, 1, @VPeriodo)
WHEN @Periodo = '3' THEN DATEADD(YEAR, 1, @VPeriodo)
END
在此示例中,右侧是所有标量常量。这意味着您可以在CreationDate字段上进行范围扫描。
另外,@ VPeriodo应该是DATE
或DATETIME
而不是VARCHAR(MAX)
。
编辑: 包括使用VARCHAR跳转的箍
使用VARCHAR时,所有日期都需要采用YYYYMMDD
格式。这是因为搅拌的自然顺序与日期的自然顺序相同......
- '20161101'
&gt; '20161002'
使用其他格式时,例如YYYYDDMM
,它会失败...
- '20160111'
&lt; '20160210'
问题,此格式于10月2日到11月1日之后
WHERE
CreationDate >= @VPeriodo
AND CreationDate < CONVERT(
NVARCHAR(8),
CASE
WHEN @Periodo = '0' THEN DATEADD(DAY, 1, CAST(@VPeriodo AS DATE))
WHEN @Periodo = '1' THEN DATEADD(MONTH, 1, CAST(@VPeriodo AS DATE))
WHEN @Periodo = '2' THEN DATEADD(MONTH, 1, CAST(@VPeriodo AS DATE))
WHEN @Periodo = '3' THEN DATEADD(YEAR, 1, CAST(@VPeriodo AS DATE))
END,
112 -- Format code for ISO dates, YYYYMMDD
)
编辑: OP发出评论并改变问题后向OP提出的问题
我所做的就是重新安排你的代码,为你所写的内容制作伪代码......
IF @periodo = '0' THEN
WHERE CreationDate >= @fetchaInicio -- Copied from 1st CASE
AND @fetchaInicio <= CreationDate -- Copied from 2nd CASE
-- These two conditions are direct from your code
-- But they're the same as each other
-- What do you REALLY want to happen when @Periodo = '0'?
IF @periodo = '1' THEN
WHERE DATEPART(MONTH,CreationDate) >= @Fecha -- Copied from 1st CASE
AND @Fecha <= DATEPART(MONTH,CreationDate) -- Copied from 2nd CASE
-- These two conditions are direct from your code
-- But they're the same as each other
-- What do you REALLY want to happen when @Periodo = '1'?
IF @periodo = '2' THEN
IF @fetcha = 13 THEN
WHERE DATEPART(MONTH,CreationDate)>= 1 -- Copied from 1st CASE
AND 6<=DATEPART(MONTH,CreationDate) -- Copied from 2nd CASE
IF @fetcha = 14 THEN
WHERE DATEPART(MONTH,CreationDate)>= 7 -- Copied from 1st CASE
AND 12<=DATEPART(MONTH,CreationDate) -- Copied from 2nd CASE
-- You never use @fetchaInicio?
-- You want everything in the first 6 months or last 6 months
-- For every year
-- Regardless of what is in @fetchaInicio?
IF @periodo = '3' THEN
IF @fetcha = 15 THEN
WHERE DATEPART(Year,CreationDate)>= 2015 -- Copied from 1st CASE
AND DATEPART(Year,CreationDate)>= 2015 -- Copied from 2nd CASE
-- Both conditions are the same again, why?
-- You want everything from 2015 onwards, forever?
-- You never use @fetchaInicio?
-- It's always 2015?
那个案例@periodo = '2' AND @fetcha NOT IN (13,14)
怎么样?
那个案例@periodo = '3' AND @fetcha NOT IN (15)
怎么样?
请你带上我的伪代码,并给出一些你在每种情况下真正想要做的实例吗?
答案 1 :(得分:0)
每当您想在where子句中使用参数作为条件时,您可以遵循以下格式:
WHERE
((@Periodo = '0' AND CreationDate
OR (@Periodo = '1' AND @VPeriodo = CAST(DATEPART(MONTH,CreationDate) as Nvarchar(10))
OR (@Periodo = '2' AND @VPeriodo = CAST(DATEPART(MONTH,CreationDate) as Nvarchar(10))
OR (@Periodo = '3' AND @VPeriodo = CAST(DATEPART(Year,CreationDate) as Nvarchar(10)))
确保参数评估是第一个,因为它会很快而且为false将阻止查询继续处理条件中处理更加密集的部分。
答案 2 :(得分:0)
首先,你是对的,内联TFV真的更快。如果不是过于复杂。 我最好为SQL Server端的每个@Periodo参数值设置一些iTFV,并在客户端的代码中选择正确的一个。
或者你可以在一个iTVF
中完成WHERE
@Periodo = '0' AND CreationDate>= @fechaInicio and CreationDate<=@fechaFin
OR @Periodo = '1' and DATEPART(MONTH,CreationDate)>= @Fecha and DATEPART(MONTH,CreationDate)<= @Fecha
...
但是,众所周知,MS SQL会为OR运营商构建一个非常糟糕的计划,这可能会让你努力坚持使用iTVF。