Sql server 2008 在多个表中按优先级顺序检查同一谓词
我需要一个可以接受日期参数和employeeid的查询。这是最简单的部分,对吧?!我遇到的困难是,我需要检查表1中是否存在该日期和员工id,如果它继续存在,如果不存在,请检查表2。如果它存在于表2中,则继续,如果不存在,则检查表3。这个组合将在3个表中的一个表中,但我不确定从语法上设置它的最佳方式是什么 edit一旦发现其中一个表中存在日期,所有处理都应结束。它不应继续到下一个If Exists语句。因此,如果在第一个if Exists语句中找到日期,则所有处理都应结束Sql server 2008 在多个表中按优先级顺序检查同一谓词,sql-server-2008,tsql,Sql Server 2008,Tsql,我需要一个可以接受日期参数和employeeid的查询。这是最简单的部分,对吧?!我遇到的困难是,我需要检查表1中是否存在该日期和员工id,如果它继续存在,如果不存在,请检查表2。如果它存在于表2中,则继续,如果不存在,则检查表3。这个组合将在3个表中的一个表中,但我不确定从语法上设置它的最佳方式是什么 edit一旦发现其中一个表中存在日期,所有处理都应结束。它不应继续到下一个If Exists语句。因此,如果在第一个if Exists语句中找到日期,则所有处理都应结束 Declare @dat
Declare @date datetime, @employeeid varchar(10)
Set @date = '01/01/2012'
Set @employeeid = 'vnm432'
IF EXISTS(Select Top 1 *
FROM firsttable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date)
Begin
'Continue processing here
End
IF EXISTS(Select Top 1 *
FROM secondtable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date)
Begin
'Continue processing here
End
IF EXISTS(Select Top 1 *
FROM thirdtable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date)
Begin
'Continue processing here
End
从我的想法来看,通过子查询和联合,您可以实现以下目标:
declare @foundIn varchar(15)
select @foundIn = foundIn from
(
select top 1 foundIn from
(
Select 'firsttable' as foundIn
FROM firsttable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date
UNION
Select 'secondtable' as foundIn
FROM secondtable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date
UNION
Select 'thirdtable' as foundIn
FROM thirdtable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date
) as q
) as q1
If @foundIn = 'firsttable'
Begin
'Continue processing here'
End
Else If @foundIn = 'secondtable'
Begin
'Continue processing here'
End
Else If @foundIn = 'thirdtable'
Begin
'Continue processing here'
END
更新:
根据首次匹配时停止处理的新要求:
IF EXISTS(Select Top 1 *
FROM firsttable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date)
Begin
--Continue processing here
End
ELSE IF EXISTS(Select Top 1 *
FROM secondtable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date)
BEGIN
--Continue processing here
END
ELSE IF EXISTS(Select Top 1 *
FROM thirdtable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date)
BEGIN
--Continue processing here
END
从我的想法来看,通过子查询和联合,您可以实现以下目标:
declare @foundIn varchar(15)
select @foundIn = foundIn from
(
select top 1 foundIn from
(
Select 'firsttable' as foundIn
FROM firsttable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date
UNION
Select 'secondtable' as foundIn
FROM secondtable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date
UNION
Select 'thirdtable' as foundIn
FROM thirdtable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date
) as q
) as q1
If @foundIn = 'firsttable'
Begin
'Continue processing here'
End
Else If @foundIn = 'secondtable'
Begin
'Continue processing here'
End
Else If @foundIn = 'thirdtable'
Begin
'Continue processing here'
END
更新:
根据首次匹配时停止处理的新要求:
IF EXISTS(Select Top 1 *
FROM firsttable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date)
Begin
--Continue processing here
End
ELSE IF EXISTS(Select Top 1 *
FROM secondtable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date)
BEGIN
--Continue processing here
END
ELSE IF EXISTS(Select Top 1 *
FROM thirdtable
WHERE employeeid = @employeeid
AND CAST(date As Date) = @date)
BEGIN
--Continue processing here
END
这种方法相当干燥,可能会导致执行短路
DECLARE @Flag INT;
WITH CTE1
AS (SELECT 1 AS Priority, employeeid, date
FROM T1
UNION ALL
SELECT 2 AS Priority, employeeid, date
FROM T2
UNION ALL
SELECT 3 AS Priority, employeeid, date
FROM T3),
CTE2
AS (SELECT *
FROM CTE1
WHERE employeeid = @employeeid
AND date >= @date
AND date < DATEADD(DAY, 1, @date))
SELECT @Flag =
CASE WHEN EXISTS (SELECT * FROM CTE2 WHERE Priority = 1) THEN 1
WHEN EXISTS (SELECT * FROM CTE2 WHERE Priority = 2) THEN 2
WHEN EXISTS (SELECT * FROM CTE2 WHERE Priority = 3) THEN 3
END
它还使用if employeeid,date比问题中的查询更容易索引。这种方法相当枯燥,可能会缩短执行时间
DECLARE @Flag INT;
WITH CTE1
AS (SELECT 1 AS Priority, employeeid, date
FROM T1
UNION ALL
SELECT 2 AS Priority, employeeid, date
FROM T2
UNION ALL
SELECT 3 AS Priority, employeeid, date
FROM T3),
CTE2
AS (SELECT *
FROM CTE1
WHERE employeeid = @employeeid
AND date >= @date
AND date < DATEADD(DAY, 1, @date))
SELECT @Flag =
CASE WHEN EXISTS (SELECT * FROM CTE2 WHERE Priority = 1) THEN 1
WHEN EXISTS (SELECT * FROM CTE2 WHERE Priority = 2) THEN 2
WHEN EXISTS (SELECT * FROM CTE2 WHERE Priority = 3) THEN 3
END
它还使用了if employeeid,日期索引比问题中的查询要多。下面的代码是对OP评论的响应。请注意,它在where子句中没有使用日期比较,这是史密斯博士答案的优点之一
-- Sample data.
declare @Employees as Table ( EmployeeId VarChar(10), HireDate DateTime, ShoeSize VarChar(6) );
insert into @Employees ( EmployeeId, HireDate, ShoeSize ) values
( 'vnm123', '2012-01-01T12:00:00', '9' ), ( 'vnm432', '2012-01-01T12:00:00', '12W' ), ( 'xyzzy', '2012-01-01T12:00:00', '6N' );
select * from @Employees;
declare @Victims as Table ( EmployeeId VarChar(10), HireDate DateTime, ShoeSize VarChar(6) );
insert into @Victims ( EmployeeId, HireDate, ShoeSize ) values
( 'vnm123', '2012-01-01T12:00:00', '9' ), ( 'vnm431', '2012-01-01T12:00:00', '12W' ), ( 'xyzzy', '2012-01-01T12:00:00', '6N' );
select * from @Victims;
-- Do something.
declare @TargetDate as Date, @TargetEmployeeId as VarChar(10), @ShoeSize as VarChar(6);
select @TargetDate = '20120101', @TargetEmployeeId = 'vnm432';
select top 1 @ShoeSize = ShoeSize
from @Employees
where EmployeeId = @TargetEmployeeId and Cast( HireDate as Date ) = @TargetDate;
if @@RowCount = 1
begin
-- Process and return.
select 'Employees' as [Table], @ShoeSize as ShowSize;
return
end
select top 1 @ShoeSize = ShoeSize
from @Victims
where EmployeeId = @TargetEmployeeId and Cast( HireDate as Date ) = @TargetDate;
if @@RowCount = 1
begin
-- Process and return.
select 'Victims' as [Table], @ShoeSize as ShowSize;
return
end
下面的代码是对OP评论的回应。请注意,它在where子句中没有使用日期比较,这是史密斯博士回答的优点之一
-- Sample data.
declare @Employees as Table ( EmployeeId VarChar(10), HireDate DateTime, ShoeSize VarChar(6) );
insert into @Employees ( EmployeeId, HireDate, ShoeSize ) values
( 'vnm123', '2012-01-01T12:00:00', '9' ), ( 'vnm432', '2012-01-01T12:00:00', '12W' ), ( 'xyzzy', '2012-01-01T12:00:00', '6N' );
select * from @Employees;
declare @Victims as Table ( EmployeeId VarChar(10), HireDate DateTime, ShoeSize VarChar(6) );
insert into @Victims ( EmployeeId, HireDate, ShoeSize ) values
( 'vnm123', '2012-01-01T12:00:00', '9' ), ( 'vnm431', '2012-01-01T12:00:00', '12W' ), ( 'xyzzy', '2012-01-01T12:00:00', '6N' );
select * from @Victims;
-- Do something.
declare @TargetDate as Date, @TargetEmployeeId as VarChar(10), @ShoeSize as VarChar(6);
select @TargetDate = '20120101', @TargetEmployeeId = 'vnm432';
select top 1 @ShoeSize = ShoeSize
from @Employees
where EmployeeId = @TargetEmployeeId and Cast( HireDate as Date ) = @TargetDate;
if @@RowCount = 1
begin
-- Process and return.
select 'Employees' as [Table], @ShoeSize as ShowSize;
return
end
select top 1 @ShoeSize = ShoeSize
from @Victims
where EmployeeId = @TargetEmployeeId and Cast( HireDate as Date ) = @TargetDate;
if @@RowCount = 1
begin
-- Process and return.
select 'Victims' as [Table], @ShoeSize as ShowSize;
return
end
如果需要,只需在变量和进程中选择行值,并在@RowCount为1时返回即可。或者这不是一个存储过程?@HABO-是的,它是一个存储过程。如何选择行值?我添加了一个包含示例代码的答案。如果需要,只需在变量中选择行值,然后在@RowCount为1时处理并返回。或者这不是一个存储过程?@HABO-是的,它是一个存储过程。我如何选择行值?我添加了一个包含示例代码的答案。如果有多个匹配项,则无法保证将分配给@foundIn的内容,这可能会不必要地访问表。@排名前1的MartinSmith保证只取第一个不,现在我看到了,没有订单,在阅读最新要求之前,我发布了,一旦发现其中一个表中存在日期,所有处理都应end@E-Bat那么,一旦找到相关的日期,这将停止处理,还是将迭代所有表?如果有多个匹配项,则无法保证将分配给@foundIn的内容,并且这可能会不必要地访问表。@排名前1的MartinSmith保证只需要第一个不,不是没有订单,现在我看到了,我在阅读更新的需求之前发布了,一旦发现其中一个表中存在日期,所有处理都应该end@E-Bat那么,一旦找到相关的日期,它会停止处理吗?或者它会迭代所有的表吗?你是什么意思?意思是关闭我的服务器?@RedLightGreenLight-可以在找到结果时避免访问其他表。什么意思可以使执行短路?意思是关闭我的服务器?@RedLightGreenLight-可以在找到结果时避免访问其他表。