SQL为每个id选择除最新结果之外的所有结果

时间:2016-08-02 17:43:10

标签: sql-server

我需要在我的表中设置一个“放弃”标志,除了每个id的最新结果。我以为我有一个可以在这里工作的查询,但是当我在查询上运行select时,我得到的结果不正确 - 我看到一个案例,它选择了两个特定id的结果。我也使用相同的确切数据获得多个结果。 我在这里做错了什么?

这是我的选择声明:

<asp:DropDownList ID="ddlType" runat="server" DataSourceID="sdsType"
                  DataValueField="ID" DataTextField="Name" AppendDataBoundItems="true">
    <asp:ListItem Value="0" Text="--Please Select--" Selected="True"></asp:ListItem>
</asp:DropDownList>
<asp:RequiredFieldValidator ID="rfvType" runat="server" ControlToValidate="ddlType" 
                            InitialValue="0" ErrorMessage="Type required"></asp:RequiredFieldValidator>
<asp:SqlDataSource ID="sdsType" runat="server" 
                   ConnectionString='<%$ ConnectionStrings:TESTConnectionString %>'
                   SelectCommand="SELECT ID, Name FROM Type"></asp:SqlDataSource>

这是我想要运行的实际查询:

select t.test_row_id, t.test_result_id, t.waived, t.pass, t.comment
from EV.Test_Result
join EV.Test_Result as t on EV.Test_Result.test_row_id = t.test_row_id and EV.Test_Result.start_time < t.start_time and t.device_id = 1219 and t.waived = 0
order by t.test_row_id

2 个答案:

答案 0 :(得分:1)

如果我理解正确,你就会遇到问题,因为ON谓词的基数会返回所有匹配的行。

       EV.Test_Result.test_row_id = t.test_row_id 
   and EV.Test_Result.start_time < t.start_time

ON将比较具有相同ID的所有start_time值,并返回结果集的每个组合,其中start_time小于t.start_time。显然,这不是你想要的。

                    and t.device_id = 1219 
                    and t.waived = 0

这实际上是一个谓词(ON技术上是一个),但我更喜欢在subquery / CTE中使用它有几个原因:限制行数{ {1}}必须检索并比较。

以下内容可能是您所需要的:

SQL

此查询会在SELECT A.test_row_id , A.test_result_id , A.waived , A.pass , A.comment FROM EV.Test_Result A INNER JOIN (SELECT MAX(start_time) AS start_time , test_row_id FROM EV.Test_Result WHERE device_id = 1219 AND waived = 0 GROUP BY test_row_id ) AS T ON A.test_row_id = T.test_row_id AND A.start_time < T.start_time ORDER BY A.test_row_id 谓词中的值之间返回1:M关系,与您运行的ON查询不同。

<强>更新 由于我怯懦地试图改变M:M上的查询,我将通过解释基本SO查询运算符的物理和逻辑顺序来赎回自己:

如您所知,您编写了一个简单的SQL语句,如下所示:

SELECT

请注意,如果使用聚合函数,则所有其他列必须出现在GROUP BY或其他函数中。

现在,SQL Server要求它们以该顺序编写,尽管它实际上按照以下顺序处理它,值得记忆:

  • FROM,WHERE,GROUP BY,HAVING,SELECT,ORDER BY

SELECT - MSDN上找到了更多详细信息,但这就是为什么SELECT <aggregate column>, SUM(<non-aggregate column>) AS Cost FROM <table_name> WHERE <column> = 'some_value' GROUP BY <aggregate column> HAVING SUM(<non-aggregate column>) > some_value ORDER BY <column> 运算符中的任何列都必须位于聚合函数组中(SELECT,{{1} }},SUM等)...以及为什么我的懒惰代码在您第一次尝试时失败了。 :/ 另请注意,MIN是最后一个(技术上MAX运算符发生在此之后),没有它,结果不是确定性的,除非ORDER BY之类的函数强制执行它(认为这发生在TOP声明。)

希望这有助于解决问题,更好地解决SQL的工作原理。干杯

答案 1 :(得分:0)

您可以按时间戳降序尝试ROW_NUMBER()函数顺序并过滤出具有ROW_NUMBER 1的值;

以下查询应该获取除最新的

之外的每个ID的所有记录

我在Oracle下面尝试了一个包含字段的表:id,user_id,record_order和timestamp并且它有效:

   select 
          <table_name_alias>.* 
        from 
        (
     select 
    id,
    user_id, 
        row_number() over (partition by id order by record_order desc) as record_number 
    from 
    <your_table_name>
 ) <table_name_alias> 
        where 
    record_number <>1; 

如果您使用的是Teradata DB,还可以尝试QUALIFY语句。我不确定是否所有数据库都支持此功能。

Select 
     table_name.* 
    from table_name 
    QUALIFY row_number() over (partition by id order by record_order desc) <>1;