我有一张表来跟踪一组设备的各个完成阶段的日期。我需要识别最近更新的设备(即具有最新日期戳的设备),无论哪个阶段更新,并返回设备ID,更新日期和阶段。容易,对吗?嗯,它听起来有点棘手。这是一个问题:每个阶段都表示为表中的一个不同的字段,重新设计表结构不是一个选项(事务表会使这个变得简单。)这是表结构的样子。
equip_id (text)
stage_1_process (date)
stage_2_process (date)
stage_3_process (date)
stage_4_process (date)
stage_5_process (date)
如果该字段包含日期,则认为该阶段已完成;如果该字段为空,则该阶段被视为未完成。
使用Max()函数的联合查询可以获得最新日期:
SELECT Max(dt) AS latest
FROM (
SELECT Max(stage_1_process) AS dt, 'Stage 1' as stage
FROM equip_status
UNION
SELECT Max(stage_2_process) AS dt, 'Stage 2' as stage
FROM equip_status
UNION
SELECT Max(stage_3_process) AS dt, 'Stage 3' as stage
FROM equip_status
UNION
SELECT Max(stage_4_process) AS dt, 'Stage 4' as stage
FROM equip_status
UNION
SELECT Max(stage_5_process) AS dt, 'Stage 5' as stage
FROM equip_status) AS U;
添加“阶段”别名以捕获与最新日期相关联的阶段。但是,我不知道如何在顶级查询中返回它,也不知道如何捕获equip_id,因为它不能从聚合函数派生。
以下是我需要返回的结果集示例:
equip_id | stage | latest
--------------------------------------------
A12345 | Stage 3 | 4/21/2016 3:56:39 PM
感谢您的帮助!
答案 0 :(得分:1)
您可以使用帖子的查询作为派生表加入:
SELECT t1.equip_id,
t2.lastest,
CASE t2.latest
WHEN t1.stage_1_process THEN 'Stage 1'
WHEN t1.stage_2_process THEN 'Stage 2'
WHEN t1.stage_3_process THEN 'Stage 3'
WHEN t1.stage_4_process THEN 'Stage 4'
WHEN t1.stage_5_process THEN 'Stage 5'
END AS stage
FROM equip_status AS t1
JOIN (
SELECT Max(dt) AS latest
FROM (
SELECT Max(stage_1_process) AS dt, 'Stage 1' as stage
FROM equip_status
UNION
SELECT Max(stage_2_process) AS dt, 'Stage 2' as stage
FROM equip_status
UNION
SELECT Max(stage_3_process) AS dt, 'Stage 3' as stage
FROM equip_status
UNION
SELECT Max(stage_4_process) AS dt, 'Stage 4' as stage
FROM equip_status
UNION
SELECT Max(stage_5_process) AS dt, 'Stage 5' as stage
FROM equip_status) AS U
) AS t2 ON t2.latest IN (t1.stage_1_process,
t1.stage_2_process,
t1.stage_3_process,
t1.stage_4_process,
t1.stage_5_process)
这看起来相当丑陋,但这些是未正确规范化表结构的后果。
答案 1 :(得分:1)
一种方法是实现一个函数,该函数返回给定行的5个阶段的最大阶段的值:
来自http://allenbrowne.com/func-09.html
Function MaxOfList(ParamArray varValues()) As Variant Dim i As Integer 'Loop controller. Dim varMax As Variant 'Largest value found so far. varMax = Null 'Initialize to null For i = LBound(varValues) To UBound(varValues) If IsNumeric(varValues(i)) Or IsDate(varValues(i)) Then If varMax >= varValues(i) Then 'do nothing Else varMax = varValues(i) End If End If Next MaxOfList = varMax End Function
现在您可以使用案例陈述和MaxOfList
select top 1
equip_id,
latest,
case when stage_1_process = latest then 'stage 1'
when stage_2_process = latest then 'stage 2'
when stage_3_process = latest then 'stage 3'
when stage_4_process = latest then 'stage 4'
when stage_5_process = latest then 'stage 5'
else 'none' end
from (
select *,
MaxOfList(stage_1_process,stage_2_process,stage_3_process,
stage_4_process,stage_5_process) as latest
from equip_status
) t order by latest desc
答案 2 :(得分:0)
SQL Server具有PIVOT和UNPIVOT,可帮助您分别将行转换为行和列。所以,我尝试了一种UNPIVOT方法来查询你的查询,发现它产生了一个优雅的解决方案(如下所示)。它是否会比明确编写的查询提供更好的性能我不知道,但我一般都相信SQL Server开发人员的智慧,如果他们提供了简洁的手段实现特定结果,它可能已经做得很好(并且可能利用了最终用户/查询编写者无法获得的低级优化)。
这个稍微陈旧的TechNet页面(SQL Server 2008)提供了很好的解释:Using PIVOT and UNPIVOT。
所以,试试这个:
$this->load->model('user_model');
$data => array (
'first_name' => $this->input->post('first_name'),
'last_name' => $this->input->post('last_name'),
'active' => $this->input->post('active'),
'date_registered' => date('Y/m/d h:i:sa')
);