SQL查询过滤

时间:2009-02-18 12:17:39

标签: sql filter

使用SQL Server 2005,我有一个表,其中记录了某些事件,我需要创建一个只返回非常具体结果的查询。下面有一个例子:

Log:
Log_ID | FB_ID |   Date    | Log_Name | Log_Type

   7   |   4   | 2007/11/8 |   Nina   |  Critical
   6   |   4   | 2007/11/6 |   John   |  Critical
   5   |   4   | 2007/11/6 |   Mike   |  Critical
   4   |   4   | 2007/11/6 |   Mike   |  Critical
   3   |   3   | 2007/11/3 |   Ben    |  Critical
   2   |   3   | 2007/11/1 |   Ben    |  Critical

查询应该执行以下操作:每个FB_ID只返回一行,但这必须是第一次更改Log_Name的行,或者如果名称永远不会更改,那么第一个日期行。

在外行人的条款中,我需要这个来浏览数据库以检查案例(FB_ID)的责任移动到另一个人的每个实例,如果它从未有过,那么只需获取原始记录器的名称。

在上面的示例中,我应该获得行(Log_ID)2和6。

这甚至可能吗?现在正在讨论DB是否只是错误的方式。 :)

我想我需要能够以某种方式将第一个产生的Log_Name存储到变量中,然后将其与IF条件等进行比较。我不知道如何用SQL做这样的事情。

编辑:更新了日期。为了澄清这一点,正确的结果将如下所示:

Log_ID | FB_ID |   Date    | Log_Name | Log_Type

   6   |   4   | 2007/11/6 |   John   |  Critical
   2   |   3   | 2007/11/1 |   Ben    |  Critical

这不是我之后每个FB_ID的第一个日期,而是Log_Name从原始文件更改的行。

最初FB_ID 4属于Mike,但查询应返回它移动到John的行。但是,它不应该返回进一步移动到Nina的行,因为当John得到它时,第一个责任改变已经发生。

对于具有FB_ID 3的Ben,记录器永远不会更改,因此应该返回Ben的第一行。

3 个答案:

答案 0 :(得分:3)

我想有更好,更高效的方式,但这个似乎有用:

SELECT *
  FROM log
 WHERE log_id IN
   ( SELECT MIN(log_id)
       FROM log
      WHERE
         ( SELECT COUNT(DISTINCT log_name)
                FROM log log2
               WHERE log2.fb_id = log.fb_id ) = 1
         OR log.log_name <> ( SELECT log_name
                                FROM log log_3
                               WHERE log_3.log_id =
                                 ( SELECT MIN(log_id)
                                     FROM log log4
                                    WHERE log4.fb_id = log.fb_id ) )
      GROUP BY fb_id )

答案 1 :(得分:2)

这将有效地使用(fb_id, cdate, id)上的索引:

SELECT  lo4.*
FROM
    (
    SELECT  CASE WHEN ln.log_id IS NULL THEN lo2.log_id ELSE ln.log_id END AS log_id,
            ROW_NUMBER() OVER (PARTITION BY lo2.fb_id ORDER BY lo2.cdate) AS rn
    FROM    (
        SELECT
            lo.*,
            (
            SELECT  TOP 1 log_id
            FROM    t_log li
            WHERE   li.fb_id = lo.fb_id
                    AND li.cdate >= lo.cdate
                    AND li.log_id <> lo.log_id
                    AND li.log_name <> lo.log_name
            ORDER BY
                cdate, log_id
            ) AS next_id
        FROM t_log lo
        ) lo2
    LEFT OUTER JOIN
        t_log ln
    ON ln.log_id = lo2.next_id
    ) lo3, t_log lo4
WHERE lo3.rn = 1
    AND lo4.log_id = lo3.log_id

答案 2 :(得分:0)

如果我已正确理解问题,则以下SQL应该可以解决问题:

SELECT Log_ID, FB_ID, min(Date), Log_Name, Log_Type  
FROM Log  
GROUP BY Date

SQL将为每个FP_ID选择具有最早日期的行。