我正在尝试开发一个返回序列号列表的SQL查询。设置表格,只要序列号到达某个步骤,就会输入日期和时间。完成该步骤后,将输入另一个日期和时间。我想开发一个查询,它将为我提供已进入该步骤的序列号列表,但不会退出该步骤。它们可能不止一次输入,所以我只查找输入后没有退出的序列号。
例如(为了便于使用,请调用表“Table1”)
1. Serial | Step | Date
2. 1 | enter | 10/1
3. 1 | exit | 10/2
4. 1 | enter | 10/4
5. 2 | enter | 10/4
6. 3 | enter | 10/5
7. 3 | exit | 10/6
对于上表,应检索序列号1和2,但不应检索3。
这可以在带有子查询的签名查询中完成吗?
答案 0 :(得分:4)
select * from Table1
group by Step
having count(*) % 2 = 1
这是当没有两个'enter'但每个enter后跟一个'exit'(如提供的例子中所示)
答案 1 :(得分:4)
我个人认为这是通过改变数据存储方式最好的方法。目前的方法不能有效或有效。是的,你可以乱七八糟地找到一种方法来获取数据。但是,当您有多个输入的步骤而没有退出同一个serialNO时会发生什么?是的,它不应该发生,但迟早它会发生,除非你编写代码来防止它(代码哪个联合很难写)。拥有一个将enter和exit存储在同一记录中的表会更清晰。然后,查询(并且更快)查找输入但未退出的内容变得微不足道。
答案 2 :(得分:3)
这将为您提供没有“退出”结尾的所有“输入”记录。如果您只需要序列号列表,则还应按序列号分组,并仅选择该列。
SELECT t1.*
FROM Table1 t1
LEFT JOIN Table1 t2 ON t2.Serial=t1.Serial
AND t2.Step='Exit' AND t2.[Date] >= t1.[Date]
WHERE t1.Step='Enter' AND t2.Serial IS NULL
答案 3 :(得分:2)
我在MySQL中测试了这个。
SELECT Serial,
COUNT(NULLIF(Step,'enter')) AS exits,
COUNT(NULLIF(Step,'exit')) AS enters
FROM Table1
WHERE Step IN ('enter','exit')
GROUP BY Serial
HAVING enters <> exits
我不确定Date的重要性在这里,但上述内容很容易修改,以纳入日内或跨日要求。
答案 4 :(得分:1)
SELECT DISTINCT Serial
FROM Table t
WHERE (SELECT COUNT(*) FROM Table t2 WHERE t.Serial = t2.Serial AND Step = 'exit') <
(SELECT COUNT(*) FROM Table t2 WHERE t.Serial = t2.Serial AND Step = 'enter')
答案 5 :(得分:1)
SELECT * FROM Table1 T1
WHERE NOT EXISTS (
SELECT * FROM Table1 T2
WHERE T2.Serial = T1.Serial
AND T2.Step = 'exit'
AND T2.Date > T1.Date
)
答案 6 :(得分:0)
如果您确定您有不匹配的输入和退出值,则可以查找“enter”计数不等于计数的所有序列值“退出”。
答案 7 :(得分:0)
如果您使用的是MS SQL 2005或2008,则可以使用CTE获取您正在寻找的结果......
WITH ExitCTE
AS
(SELECT Serial, StepDate
FROM #Table1
WHERE Step = 'exit')
SELECT A.*
FROM #Table1 A LEFT JOIN ExitCTE B ON A.Serial = B.Serial AND B.StepDate > A.StepDate
WHERE A.Step = 'enter'
AND B.Serial IS NULL
如果您不使用这些,我会尝试使用子查询...
SELECT A.*
FROM #Table1 A LEFT JOIN (SELECT Serial, StepDate
FROM #Table1
WHERE Step = 'exit') B
ON A.Serial = B.Serial AND B.StepDate > A.StepDate
WHERE A.Step = 'enter'
AND B.Serial IS NULL
答案 8 :(得分:0)
在Oracle中:
SELECT *
FROM (
SELECT serial,
CASE
WHEN so < 0 THEN "Stack overflow"
WHEN depth > 0 THEN "In"
ELSE "Out"
END AS stack
FROM (
SELECT serial, MIN(SUM(DECODE(step, "enter", 1, "exit", -1) OVER (PARTITION BY serial ORDER BY date)) AS so, SUM(DECODE(step, "enter", 1, "exit", -1)) AS depth
FROM Table 1
GROUP BY serial
)
)
WHERE stack = "Out"
这将选择您想要的内容 AND 过滤exits
没有enters
答案 9 :(得分:0)
有些人建议重新安排您的数据,但我没有看到任何示例,所以我会对此进行修改。这是您描述的同一个表的部分非规范化变体。它应该适用于有限数量的“步骤”(这个例子只考虑“输入”和“退出”,但它可以很容易地扩展),但它最大的弱点是在填充表格后添加额外的步骤(比如说,输入/处理/退出)很昂贵 - 您必须ALTER TABLE
才能这样做。
serial enter_date exit_date
------ ---------- ---------
1 10/1 10/2
1 10/4 NULL
2 10/4 NULL
3 10/5 10/6
您的查询变得非常简单:
SELECT serial,enter_date FROM table1 WHERE exit_date IS NULL;
serial enter_date
------ ----------
1 10/4
2 10/4
答案 10 :(得分:0)
这是一个适用于您的方案的简单查询
SELECT Serial FROM Table1 t1
WHERE Step='enter'
AND (SELECT Max(Date) FROM Table1 t2 WHERE t2.Serial = t1.Serial) = t1.Date
我已经测试了这个,这将为您提供序列号为1&amp;的行。 2