>我正在尝试实现一个非常简单的路由系统,该系统允许项目根据相关表中的路由信息从一个步骤转到另一个步骤。我的 ASP.NET 方法应该根据数据库结果进行下一步,以避免任何愚蠢的硬编码值。
有一个表包含活动步骤(所有步骤"要做"或不做,位:1 或 0),另一个包含已完成步骤的表。根据这些信息,我相信我应该能够从包含所有活动步骤的表中选择前 1 个(下一步),其中 stepID 不在已完成的步骤 ID 列表中。
我已经在纸上尝试过这个,这是有道理的,我也尝试从详细查询到大查询,这应该返回下一步(前 1 名)。底层查询有效,但是,我的大查询应该返回前 1 个项目(下一步)时遇到问题。我总是收到以下错误:
"Msg 156,级别 15,状态 1。关键字附近的语法不正确 "哪里"。消息 156,级别 15,状态 1。关键字附近的语法不正确 "不是"。(第 4 行)">
表概述如下。
表路由包含要完成的所有步骤(或非 -> 0)
itemID |routeID |stepID |stepScheduled |
-------|--------|-------|--------------|
1 |1 |10 |1 |
2 |1 |20 |1 |
3 |1 |30 |1 |
4 |1 |40 |1 |
5 |1 |50 |1 |
6 |1 |60 |1 |
7 |1 |70 |1 |
8 |1 |80 |1 |
9 |1 |90 |1 |
10 |1 |100 |1 |
----------------------------------------
表Steps_Completed包含已完成的步骤(如果此项尚未完成任何步骤,则可能为空)。
completionID |sampleID |stepID |userName |completionDT |stationID |
-------------|---------|-------|---------|--------------------|--------------|
1 |1 |10 |Me |2017-12-28 10:04:41 |workstation 1 |
------------------------------------------------------------------------------
我目前正在尝试的查询返回上述错误消息:
SELECT TOP 1 stepID FROM
(SELECT [stepID] **Routes** WHERE [routeID] = 1 AND [stepScheduled] = 1)
WHERE stepID NOT IN (SELECT stepID FROM **Steps_Completed** WHERE sampleID =
1);
() 中的子查询在单独执行时工作并返回预期值:
(从路由中选择 [步骤ID],其中 [路由ID] = 1 和 [步骤计划] = 1) 返回第一个表中所示的所有行(所有"待办事项")
(从Steps_Completed中选择步骤ID 其中 SAMPLEID = 1) 返回已完成的所有行,如果尚未记录任何内容,则返回空结果。
这个想法是对"路由"列表进行基本的"减法","减去"已完成的步骤,然后选择剩余列表的前 1 项。由于步骤ID列表可以按ASC排序,因此前1项应该是我的结果。
问题似乎出在"WHERE STEPID 不在">部分。
以下是当前查询的直接修复方法:
SELECT TOP 1 [stepID]
FROM Routes
WHERE
[routeID] = 1 AND
[stepScheduled] = 1 AND
[stepID] NOT IN (SELECT stepID FROM Steps_Completed WHERE sampleID = 1)
ORDER BY
[stepID];
另一种表达方式是使用左连接:
SELECT TOP 1 r.stepID
FROM Routes r
LEFT JOIN Steps_Completed s
ON r.routeID = s.sampleID AND
r.stepID = s.stepID
WHERE
r.routeID = 1 AND
r.stepScheduled = 1 AND
s.sampleID IS NULL
ORDER BY
r.stepID;
这里要注意的一个关键点是,我们通常必须ORDER BY
一起使用TOP
. 否则,"top"没有很好的定义,因为SQL表没有内部顺序。 另外,我认为您不必在此处使用子查询,因此我将其删除。
使用别名:
SELECT TOP 1 stepID FROM
(SELECT [stepID] from Routes WHERE [routeID] = 1 AND [stepScheduled] = 1) as a
WHERE stepID NOT IN (SELECT stepID FROM Steps_Completed WHERE sampleID =
1);
SELECT stepID
FROM Routes
WHERE stepID = (SELECT MIN(stepId)
FROM Routes r
LEFT JOIN Steps_Completed sc
ON r.stepID = sc.stepID
WHERE [routeID] = 1
AND [stepScheduled] = 1
AND sc.stepID is null)