获取没有直接关联的逻辑对应记录

时间:2015-05-11 21:20:26

标签: sql sql-server-2008

我有一个表记录案例的请求和响应,以及每次发生的时间。我的问题是,特定响应与其响应的请求之间没有直接关联。为了使事情变得更加困难,对一个请求可能会有多个响应,并且请求和响应不会始终整理 - 您可能有两个请求后跟两个响应,这意味着第一个响应与第一个请求相关,第二个响应与第二个请求有关。下面简化的表格给出了每种情况的例子:

Case_Id     Subject     Date
123         Request     2014-12-03 15:48:02
123         Response    2014-12-03 16:01:45
123         Response    2014-12-03 17:32:23
123         Request     2015-04-10 12:12:17
123         Request     2015-04-10 12:13:34
123         Response    2015-04-10 13:31:20
123         Response    2014-04-10 13:37:12
234         Request     2014-12-03 12:12:20
234         Response    2014-12-03 12:20:23
234         Request     2015-03-03 15:09:44
234         Response    2015-03-03 16:23:54

我想要做的是找到与案例中每个请求相对应的第一个响应,以便我可以计算响应所花费的时间。所以这个查询的输出应该是:

Case_Id     Request Time            Response Time
123         2014-12-03 15:48:02     2014-12-03 16:01:45
123         2015-04-10 12:12:17     2015-04-10 13:31:20
123         2015-04-10 12:13:34     2015-04-10 13:37:12
234         2014-12-03 12:12:20     2014-12-03 12:20:23
234         2015-03-03 15:09:44     2015-03-03 16:23:54

我遇到的问题是那些非整理的示例,其中有两个(或更多)请求,后跟两个(或更多)响应。到目前为止,我已经得到了这个:

Select N1.Case_id, N1.Date AS Request_Date, N2.Date as Response_Date
FROM Notes N1
  JOIN Notes N2
    ON N1.subject = 'Request'
    AND N2.date = (
      SELECT min(date)
      FROM Notes
      WHERE Case_Id = N1.Case_Id
        AND subject = 'Response'
        AND date > N1.date
    )

几乎可以正常工作,但正如您从SQL Fiddle here中看到的那样,当您有多个请求后跟多个响应时它会失败 - 它会在第一个响应时失败,而不管它是什么&? #34;权利"按先前的要求。我已经四处搜索了,但我无法弄清楚如何排除已经加入之前的回复。

1 个答案:

答案 0 :(得分:0)

这很不愉快,但它似乎适用于您的数据。我必须修复数据中的小故障,因为数据中第7行的值与结果中显示的值不同。

DECLARE @Data TABLE (
    Case_Id INT,
    [Subject] VARCHAR(50),
    [Date] DATETIME);
INSERT INTO @Data SELECT 123, 'Request', '2014-12-03 15:48:02';
INSERT INTO @Data SELECT 123, 'Response', '2014-12-03 16:01:45';
INSERT INTO @Data SELECT 123, 'Response', '2014-12-03 17:32:23';
INSERT INTO @Data SELECT 123, 'Request', '2015-04-10 12:12:17';
INSERT INTO @Data SELECT 123, 'Request', '2015-04-10 12:13:34';
INSERT INTO @Data SELECT 123, 'Response', '2015-04-10 13:31:20';
INSERT INTO @Data SELECT 123, 'Response', '2015-04-10 13:37:12';
INSERT INTO @Data SELECT 234, 'Request', '2014-12-03 12:12:20';
INSERT INTO @Data SELECT 234, 'Response', '2014-12-03 12:20:23';
INSERT INTO @Data SELECT 234, 'Request', '2015-03-03 15:09:44';
INSERT INTO @Data SELECT 234, 'Response', '2015-03-03 16:23:54';
WITH RowIds AS (
    SELECT
        *,
        ROW_NUMBER() OVER (ORDER BY Case_Id, [Date]) AS RowId
    FROM
        @Data),
Requests AS (
    SELECT
        Case_Id,
        [Date]
    FROM
        @Data
    WHERE
        [Subject] = 'Request'),
NextResponse AS (
    SELECT
        r.Case_Id,
        r.[Date] AS Request_Time,
        MIN(d.[Date]) AS Response_Time
    FROM
        Requests r
        INNER JOIN @Data d ON d.Case_id = r.Case_id AND d.[Subject] = 'Response' AND d.[Date] > r.[Date]
    GROUP BY
        r.Case_Id,
        r.[Date]),
AssignIds AS (
    SELECT
        nr.*,
        r.RowId
    FROM
        NextResponse nr
        INNER JOIN RowIds r ON r.Case_Id = nr.Case_Id AND r.[Subject] = 'Response' AND r.[Date] = nr.Response_Time),
FindDuplicates AS (
    SELECT
        RowId
    FROM
        AssignIds
    GROUP BY
        RowId
    HAVING
        COUNT(*) > 1),
ApplyDuplicateOffsets AS (
    SELECT
        a.Case_Id,
        a.Request_Time,
        a.Response_Time,
        a.RowId,
        ROW_NUMBER() OVER (PARTITION BY a.RowId ORDER BY a.Response_Time) AS Offset
    FROM
        FindDuplicates fd
        INNER JOIN AssignIds a ON a.RowId = fd.RowId),
FixDuplicates AS (
    SELECT
        a.Case_Id,
        a.Request_Time,
        MIN(CASE WHEN d.RowId IS NULL THEN a.Response_Time ELSE a2.[Date] END) AS Response_Time
    FROM
        AssignIds a
        LEFT JOIN FindDuplicates d ON d.RowId = a.RowId
        LEFT JOIN ApplyDuplicateOffsets o ON o.RowId = a.RowId AND o.Request_Time = a.Request_Time
        LEFT JOIN RowIds a2 ON a2.Case_Id = a.Case_Id AND a2.RowId >= a.RowId + o.Offset - 1
    GROUP BY
        a.Case_Id,
        a.Request_Time)
SELECT
    *
FROM
    FixDuplicates
ORDER BY
    Case_Id,
    Request_Time;

基本上这可以如下工作:

  • 首先,我列出了每行分配了唯一行ID的数据;
  • 接下来我执行一个简单的匹配,只为每个请求选择下一个响应;
  • 这最终会对多行使用相同的响应,所以我找到了这种情况发生的地方;
  • 接下来我按照日期排序创建重复订单,因此第一个副本分配1,然后分配2,等等;
  • 现在我可以通过选择第一个副本的原始响应,第二个重复的下一个可用响应等来重新分配响应日期(假设每个请求都有自己的响应);
  • 最后我只是吐出了结果。

结果如下:

Case_Id Request_Time    Response_Time
123 2014-12-03 15:48:02.000 2014-12-03 16:01:45.000
123 2015-04-10 12:12:17.000 2015-04-10 13:31:20.000
123 2015-04-10 12:13:34.000 2015-04-10 13:37:12.000
234 2014-12-03 12:12:20.000 2014-12-03 12:20:23.000
234 2015-03-03 15:09:44.000 2015-03-03 16:23:54.000

这是一个很好的解决方案吗?不是真的,我原本以为这需要某种形式的递归,也许这是解决问题的更好方法吗?