似乎此标题之前已被多次使用,遗憾的是我不知道如何描述我的问题。所以,首先,如果你有一个更好的标题建议,这将有助于未来的搜索者,那就开火了!
无论如何,我的问题是尝试编写SQL以根据应用于以下模式的一组规则返回结果集:
TABLE: Tests
COLUMNS: ID (PK), Name
TABLE: TestVersions
COLUMNS: TestID (PK), Version (PK), IsActive
TABLE: TestSessions
COLUMNS: TestID (PK), TestVersion (PK), UserID (PK), Iteration (PK), Completed, CompletionDate
[Tests]上的[Tests]和[TestVersions]之间存在关系。[ID] = [TestVersions]。[TestID]。在[TestSessions]上[TestSessions]和[TestVersions]之间也存在关系。[TestID] = [TestVersions]。[TestID]和[TestSessions]。[TestVersion] = [TestVersions]。[Version]
结果集应返回[Tests]。[ID],[Tests]。[Name]和[TestVersions]。[Version]基于以下规则:
希望这是有道理的。
答案 0 :(得分:0)
这是一个创建临时表的快速脚本,用数据填充它们,并向您展示我如何处理您遇到的问题。让我先说这种东西有时最好留给业务逻辑层。此外,我不确定您的描述是否非常准确,因为似乎存在一些不一致。话虽如此,我希望你能带走如何处理你的问题,把它分解成部分并解决它。不要担心预先优化,只需编写干净和逻辑代码。优化器会告诉您是否犯了任何错误。这假定SQL Server 2008:
declare @Tests table
(
ID int,
Name varchar(100)
)
declare @TestVersions table
(
TestID int,
Version int,
IsActive bit
)
declare @TestSessions table
(
TestID int,
TestVersion int,
UserID varchar(100),
Iteration int,
Completed bit,
CompletionDate date
)
insert into @Tests
select 1, 'one' union all
select 2, 'two' union all
select 3, 'three' union all
select 4, 'four' union all
select 5, 'five'
insert into @TestVersions
select 1, 1, 0 union all
select 2, 1, 1 union all
select 3, 1, 0 union all
select 4, 1, 0 union all
select 5, 1, 1 union all
select 1, 2, 0 union all
select 2, 2, 0 union all
select 3, 2, 1 union all
select 4, 2, 0 union all
select 1, 3, 1 union all
select 2, 3, 1
insert into @TestSessions
select 1, 1, 'a', 1, 1, GETDATE()-101 union all
select 2, 1, 'b', 1, 1, GETDATE()-11 union all
select 3, 1, 'c', 1, 0, null union all
select 4, 1, 'd', 1, 1, GETDATE()-103 union all
select 5, 1, 'e', 1, 1, GETDATE()-101 union all
select 1, 2, 'f', 1, 1, GETDATE()-15 union all
select 2, 2, 'g', 1, 0, null union all
select 3, 2, 'h', 1, 1, GETDATE()-17 union all
select 4, 2, 'i', 1, 0, null union all
select 1, 3, 'j', 2, 1, GETDATE()-109 union all
select 2, 3, 'k', 2, 1, GETDATE()-101 union all
select 2, 1, 'l', 3, 1, GETDATE()-120 union all
select 3, 1, 'm', 1, 1, GETDATE()-11 union all
select 4, 1, 'n', 1, 1, GETDATE()-140 union all
select 5, 1, 'a', 1, 0, null union all
select 1, 2, 'b', 1, 1, GETDATE()-160 union all
select 2, 2, 'c', 2, 0, null union all
select 3, 2, 'd', 1, 1, GETDATE()-17 union all
select 4, 2, 'e', 1, 0, null union all
select 1, 3, 'f', 2, 1, GETDATE()-4 union all
select 2, 3, 'g', 3, 1, GETDATE()-101
select Id
,Name
,Version
from @Tests t
inner join
@TestVersions v on t.ID = v.TestID
-- any test with a session with completed = false
where exists
(select *
from @TestSessions s1
where s1.Completed = 0
and s1.TestID = t.ID
and s1.TestVersion = v.Version
)
or (
-- any max version of a test which has no sessions
not exists
(select *
from @TestSessions s1
where s1.TestID = t.ID
and s1.TestVersion = v.Version
)
and v.Version =
(select MAX(Version)
from @TestVersions v2
where v2.TestID = t.ID
)
)
or (
-- no uncompleted sessions
not exists
(select *
from @TestSessions s1
where s1.Completed = 0
and s1.TestID = t.ID
and s1.TestVersion = v.Version
)
-- we're already inner joining to versions, so we just need to check IsActive
and IsActive = 1
-- the most recent completion date is at least 30 days ago (not quite 30 days ago but i'm lazy)
and GETDATE() - 30 <=
(select MAX(CompletionDate)
from @TestSessions s2
where s2.TestID = t.ID
and s2.TestVersion = v.Version
)
-- not sure what you mean by "return", but I'm sure you can figure out how to project what you need
)
答案 1 :(得分:0)
这是我最终得到的结果(基于Milimetric的建议):
SELECT Tests.ID, Tests.Name, TestVersions.Version
FROM Tests INNER JOIN
TestVersions ON Tests.ID = TestVersions.TestID
WHERE (
EXISTS (SELECT *
FROM TestSessions
WHERE Complete = 0
AND TestID = Test.ID
AND TestVersion = TestVersions.Version)
)
OR
(
NOT EXISTS (SELECT *
FROM TestSessions
WHERE TestID = Tests.ID
AND TestVersion = TestVersions.Version)
AND (TestVersions.Version = (SELECT MAX(Version)
FROM TestVersions
WHERE TestID = Tests.ID))
AND TestVersions.IsActive = 1
AND TestVersions.StartDate <= GetDate()
AND (TestVersions.EndDate IS NULL OR TestVersions.EndDate >= GetDate())
)
OR
(
EXISTS (SELECT *
FROM TestSessions
WHERE Complete = 1
AND TestID = Tests.ID
AND TestVersion = TestVersions.Version)
AND (TestVersions.Version = (SELECT MAX(Version)
FROM TestVersions
WHERE TestID = Tests.ID))
AND (TestVersions.IsActive = 1)
AND (TestVersions.StartDate <= GetDate())
AND (TestVersions.EndDate IS NULL OR TestVersions.EndDate >= GetDate())
AND (GetDate() >= (SELECT DATEADD(day, 30, MAX(TestSessions.CompletionDate))
FROM TestSessions
WHERE TestSessions.TestID = Tests.ID
AND TestSessions.TestVersion = TestVersions.Version))