Sql 即使使用MAX函数,子查询也会返回多行
我已经搜索过了,在这个案件中找不到任何对我有帮助的东西。数据库是MS SQL Server 2008 R2 我有一个复杂的查询,实际上我正在使用CTE,其中一个子查询应该为每列返回一行。然而,我不知道该怎么做 这是密码Sql 即使使用MAX函数,子查询也会返回多行,sql,sql-server,tsql,Sql,Sql Server,Tsql,我已经搜索过了,在这个案件中找不到任何对我有帮助的东西。数据库是MS SQL Server 2008 R2 我有一个复杂的查询,实际上我正在使用CTE,其中一个子查询应该为每列返回一行。然而,我不知道该怎么做 这是密码 select MemberFK as LMFK, ContractNr, Contractbegin as LC, ContractEnd as LCE from Contracts as V WHERE MainContract=1 AND Description not
select MemberFK as LMFK, ContractNr, Contractbegin as LC, ContractEnd as LCE from Contracts as V
WHERE
MainContract=1
AND Description not like '%Mitarbeiter%'
AND Description not like '%Kind%'
AND Description not like '%Teen%'
AND Description not like '%Kid%'
AND Contractbegin =
(select TOP 1 MAX(V1.Contractbegin) from Contracts as V1 WHERE
(V1.Description like '%Gold%'
OR V1.Description like '%Silber%'
OR V1.Description like '%Bronze%'
OR V1.Description like '%Executive%' )
AND V1.ContractEnd>V1.Contractbegin --to flush out some erroneous rows
AND V1.MemberFK =V.MemberFK)
有问题的行示例:
LMFK ContractNr LC LCE
649 644 2002-10-01 00:00:00 2008-04-30 00:00:00
755 646 2002-11-01 00:00:00 2002-11-01 00:00:00
755 647 2002-11-01 00:00:00 2008-07-31 00:00:00
754 648 2002-11-01 00:00:00 2008-07-31 00:00:00
我想做的是,每个LMFK只得到一行,得到满足其他条件的最大ContractNr。如您所见,ContractNr 646无效,而647无效。看起来V1.ContractEnd>V1.Contractbegin
条件工作不正常
感谢您的帮助 您应该在where cluse中使用ContractNr。您的查询将返回与max Contractbegin匹配的所有记录
select MemberFK as LMFK, ContractNr, Contractbegin as LC, ContractEnd as LCE from Contracts as V
WHERE
MainContract=1
AND Description not like '%Mitarbeiter%'
AND Description not like '%Kind%'
AND Description not like '%Teen%'
AND Description not like '%Kid%'
AND ContractNr =
(select TOP 1 MAX(V1.ContractNr) from Contracts as V1 WHERE
(V1.Description like '%Gold%'
OR V1.Description like '%Silber%'
OR V1.Description like '%Bronze%'
OR V1.Description like '%Executive%' )
AND V1.ContractEnd>V1.Contractbegin --to flush out some erroneous rows
AND V1.MemberFK =V.MemberFK)
我总是喜欢创建一个玩具桌和/或数据库来展示我的想法。下面就是这样一个片段 这里有一些关于你的解决方案和我的解决方案的评论 1-在开始时使用通配符将列与模式进行比较时,查询优化器无法使用任何索引。因此,这将导致全表扫描 2-我总是喜欢测试空值。合并是一种将空字符串默认为空字符串的好方法 3-如果对where逻辑使用持久化计算列,则在插入或更新记录时,该列将存储在数据库中 4-一个持久化的计算列可以有一个索引,因此,消除了对较大表的表扫描 我不得不使用查询索引提示,因为对于小表,表扫描速度更快 此外,您可能需要添加成员和/或开始日期。IE-更多的工作/测试用于实际示例 5-最后但并非最不重要的一点,使用窗口分区和row_number()函数查找最新的行 我将其捆绑到一个CTE中,因为您不能在WHERE子句中引用语句的SELECT部分中的计算 这里有一些好的概念:
- 通配符模式搜索等于全表扫描
- 始终为空的ST/帐户
- 将计算列持久化为索引
对于速度
- 使用分组功能选择顶部结果
——删除旧表
如果对象id('tempdb.dbo.contracts')>0
删除tempdb.dbo.contracts表;
去
--创建新表
创建表tempdb.dbo.contracts
(
id_num int identity(1,1),
国际货币基金组织成员,
主标志位,
开始日期日期时间,
结束日期日期时间,
说明\u txt varchar(512),
不要将标志用作
(
--一定有这些话
(
案例
当较低的值(合并(description_txt,')如“%gold%”时,则为0
当较低的值(合并(description_txt,')如“%silver%”时,则为0
当较低的值(合并(description_txt,')如“%brown%”时,则为0
当较低(合并(description_txt,'')时,如“%executive%”,则为0
其他1
结束
)
+
--千万不要有这些话
(
案例
当较低时(合并(description_txt.),如“%mitarbeiter%”,则为1
当较低(合并(description_txt,“”)时,如“%kind%”,则为1
当像“%teen%”这样的值较低时(合并(description_txt,”),则为1
当较低(合并(description_txt,')时,如“%kid%”,则为1
其他0
结束
)
+
--必须有开始日期选择V1.ContractBeginFromContracts作为V1,其中(V1.Description(如“%Gold%”或V1.Description(如“%Silber%”)或V1.Description(如“%brown%”)或V1.Description(如“%Executive%”)按V1.Contractbegin DESC排序…。如果运行此命令,您可能会看到多行共享最高的V1.Contractbegin。此外,您还有一个打字错误,它会显示“Silber”而不是“Silver.selecting top n而不使用order by子句似乎是寻找麻烦的好方法。但是V1.ContractEnd>V1.Contractbegin是一个条件Contractbegin=().V1.ContractEnd>V1.Contractbegin不是主查询的条件。谢谢,我正在尝试。选择最大ContractNr似乎效果更好。但是,Contractbegin不再有任何条件。ContractNr条款不需要它吗?我想为每个成员获得系统中的最新合同,我应该获得maxim嗯,开始日期。
-- Drop old table
if object_id('tempdb.dbo.contracts') > 0
drop table tempdb.dbo.contracts;
go
-- Create new table
create table tempdb.dbo.contracts
(
id_num int identity(1,1),
member_fk int,
main_flag bit,
begin_date smalldatetime,
end_date smalldatetime,
description_txt varchar(512),
do_not_use_flag as
(
-- must have these words
(
case
when lower(coalesce(description_txt, '')) like '%gold%' then 0
when lower(coalesce(description_txt, '')) like '%silver%' then 0
when lower(coalesce(description_txt, '')) like '%bronze%' then 0
when lower(coalesce(description_txt, '')) like '%executive%' then 0
else 1
end
)
+
-- must not have these words
(
case
when lower(coalesce(description_txt, '')) like '%mitarbeiter%' then 1
when lower(coalesce(description_txt, '')) like '%kind%' then 1
when lower(coalesce(description_txt, '')) like '%teen%' then 1
when lower(coalesce(description_txt, '')) like '%kid%' then 1
else 0
end
)
+
-- must have begin_date <= end_date
(
case
when begin_date is null then 1
when end_date is null then 0
when begin_date <= end_date then 0
else 1
end
)
+
(
-- toss out non-main records
case
when main_flag = 1 then 0
else 1
end
)
) persisted
);
go
-- add index on id include flag
create nonclustered index ix_contracts
on tempdb.dbo.contracts (do_not_use_flag);
go
-- add data to table
insert into tempdb.dbo.contracts (member_fk, main_flag, begin_date, end_date, description_txt)
values
-- shows up
(1, 1, getdate() - 5, getdate(), 'Silver - good contract for DBA'),
-- main contract <> 1
(1, 0, getdate() - 5, getdate(), 'Gold - good contract for DBA'),
-- no flag = true
(1, 1, getdate() - 5, getdate(), 'Bronze - good contract for Teen'),
-- end < begin
(1, 1, getdate(), getdate()-5, 'Bronze - good contract for DBA'),
(2, 1, getdate() - 5, getdate(), 'Executive - good contract for DBA');
go
-- wait 5 seconds
WAITFOR DELAY '00:00:02';
go
insert into tempdb.dbo.contracts (member_fk, main_flag, begin_date, end_date, description_txt)
values
(2, 1, getdate() - 4, getdate(), 'Executive - good contract for DBA');
go
-- show the raw data
select * from tempdb.dbo.contracts as c
go
-- show the data
;
with cte_contract_by_recent_begin_dte
as
(
select
ROW_NUMBER() OVER (PARTITION BY member_fk ORDER BY begin_date desc) as top_id,
*
from
tempdb.dbo.contracts as c with(index(ix_contracts))
where
c.do_not_use_flag = 0
)
select * from cte_contract_by_recent_begin_dte as cte where cte.top_id = 1