只显示一个可能或可能没有孩子的记录

时间:2014-09-03 16:58:48

标签: sql sql-server

我一直坚持这个问题已经有一段时间了。我觉得我很亲密,但是我有些遗漏。

交易可以有零个或多个TransactionErrors。我试图只显示所有交易一次,而且我也试图只显示最新的错误消息(如果有)。

    SELECT [Transaction].[TransactionID]
      ,[FileName]
      ,[DestinationSystem]
      ,[CreatedOn]
      ,LEFT([TransactionError].[ErrorMessage], 300) AS LatestErrorMessage --Gets only the first 300 characters of the error message
FROM [WM01DB].[dbo].[Transaction]
    INNER JOIN SourceSystem ON SourceSystem.SourceSystemId = Transaction.SourceSystemId
    LEFT JOIN TransactionError ON TransactionError.TransactionId = Transaction.TransactionId
WHERE Transaction.CreatedOn >= '2014-08-01 00:00:00.000'
    AND Transaction.CreatedOn < '2014-09-02 00:00:00.000'
    ORDER BY [CreatedOn], [Transaction].[TransactionID]

当我运行此查询时,我得到了我想要的大部分结果,但是我得到了重复的事务,因为这些事务有多个TransactionErrors。它看起来像这样......

TransactionID       FileName                    DestinationSystem   CreatedOn           LatestErrorMessage
18124           201408131541517937_DC_TEST_3339376-4.1.xml  TEST            2014-08-18 18:31:19.993     U_BOL and Tracking Number are blank
18124           201408131541517937_DC_TEST_3339376-4.1.xml  TEST            2014-08-18 18:31:19.993     FRT_CHG_TYPE is blank
18125           201408111521484448_DC_TEST_3339375-2.1.xml  TEST            2014-08-19 16:04:58.467     NULL
18126           201408111521484448_DC_TEST_3339375-2.1.xml  TEST            2014-08-19 16:09:00.467     NULL

呃......看起来不好的代码块...

如您所见,有重复的TransactionIDs,如18124所示。我希望18124只显示一次最新的错误消息。获取最新错误消息的唯一方法是使用特定TransactionID的最新TransactionErrorID ...

请帮忙! :(

4 个答案:

答案 0 :(得分:1)

你可以使用 ROW_NUMBER() PARTITION BY 子句来实现它 -

SELECT [Transaction].[TransactionID]
    ,[FileName]
    ,[DestinationSystem]
    ,[CreatedOn]
    ,LEFT([TransactionError].[ErrorMessage], 300) AS LatestErrorMessage --Gets only the first 300 characters of the error message
    ,ROW_NUMBER() OVER (
        PARTITION BY [Transaction].[TransactionID] ORDER BY [CreatedOn]
            ,[Transaction].[TransactionID] DESC
        ) AS SrNo
FROM [WM01DB].[dbo].[Transaction]
INNER JOIN SourceSystem ON SourceSystem.SourceSystemId = TRANSACTION.SourceSystemId
LEFT JOIN TransactionError ON TransactionError.TransactionId = TRANSACTION.TransactionId
WHERE TRANSACTION.CreatedOn >= '2014-08-01 00:00:00.000'
    AND TRANSACTION.CreatedOn < '2014-09-02 00:00:00.000'
    AND SrNo = 1
ORDER BY [CreatedOn]
    ,[Transaction].[TransactionID]

答案 1 :(得分:1)

SELECT A.[TransactionID]
      ,A.[FileName]
      ,A.[DestinationSystem]
      ,A.[CreatedOn]
      ,A.LatestErrorMessage
FROM (
SELECT [Transaction].[TransactionID]
      ,[FileName]
      ,[DestinationSystem]
      ,[CreatedOn]
      ,LEFT([TransactionError].[ErrorMessage], 300) AS LatestErrorMessage --Gets only the first 300 characters of the error message
      ,ROW_NUMBER() OVER (PARTITION BY [Transaction].[TransactionID] ORDER BY [CreatedOn] DESC) rn
FROM [WM01DB].[dbo].[Transaction]
INNER JOIN SourceSystem    ON SourceSystem.SourceSystemId    = [Transaction].SourceSystemId
                           AND   [Transaction].CreatedOn >= '2014-08-01 00:00:00.000'
                           AND   [Transaction].CreatedOn <  '2014-09-02 00:00:00.000'
LEFT JOIN TransactionError ON TransactionError.TransactionId = [Transaction].TransactionId
  )A 
WHERE A.rn = 1 
ORDER BY A.[CreatedOn], A.[TransactionID]

答案 2 :(得分:1)

我对Krishnraj Rana有类似的解决方案。但是,我认为您需要避免在WHERE子句中使用rowid过滤器,因为如果行为类似于内部联接,那将会产生:

; with Errors as 
(SELECT  [ErrorMessage]
        , Row_Number() over (Partition By TransactionId order by TransactionErrorId Desc) as id
    FROM TransactionError
)

    SELECT [Transaction].[TransactionID]
      ,[FileName]
      ,[DestinationSystem]
      ,[CreatedOn]
      ,LEFT([ErrorMessage], 300) AS LatestErrorMessage --Gets only the first 300 characters of the error message
FROM [WM01DB].[dbo].[Transaction]
    INNER JOIN SourceSystem ON SourceSystem.SourceSystemId = Transaction.SourceSystemId
    LEFT JOIN Errors ON TransactionError.TransactionId = Transaction.TransactionId
        and errors.id = 1
WHERE Transaction.CreatedOn >= '2014-08-01 00:00:00.000'
    AND Transaction.CreatedOn < '2014-09-02 00:00:00.000'
    ORDER BY [CreatedOn], [Transaction].[TransactionID]

答案 3 :(得分:1)

同样使用row_number(),但按要求选择最后TransactionErrorId(至少假设SQL Server 2005):

with x as (
    select
        t.[TransactionId],
        [FileName],
        [DestinationSytem],
        [CreatedOn],
        e.[ErrorMessage],
        row_number() over (
            partition by t.[TransactionId],
            order by e.[TransactionErrorId] desc
        ) rn
    from
        [wm01db].[dbo].[Transaction] t
            inner join
        [dbo].[SourceSystem] s
            on t.SourceSystemId = s.SourceSytemId
            left outer join
        [dbo].[TransactionError] e
            on e.TransactionId = t.TransactionId
    where
        t.CreatedOn >= '2014-08-01 00:00:00.000' and
        t.CreatedOn < '2014-09-02 00:00:00.000'
) select
    [TransactionId],
    [FileName],
    [DestinationSytem],
    [CreatedOn],
    left([ErrorMessage], 300) as LastErrorMessage
from
    x
where
    rn = 1
order by
    [CreatedOn],
    [TransactionId] ;