Соединения SQL Server с одинаковыми строками с использованием rownum не возвращают значений - PullRequest
0 голосов
/ 04 мая 2018

Я пытаюсь вернуть несколько значений записей в одной строке, поэтому я хотел использовать несколько объединений в одной таблице. Мне нужно, чтобы две верхние записи отображались бок о бок. Эти объединения становятся 'LatestNote' и 'SecondLatestNote', используя RowNumber для их разделения.

Ниже приведен очень простой пример, но я не получаю результатов. Что я тут испортил?

SQL с объединениями, который не возвращает значений:

DECLARE @DateFrom AS DATETIME = CONVERT(DateTime, '2017-01-01 00:00:00.000', 120)
DECLARE @DateTo AS DATETIME = CONVERT(DateTime, '2018-01-01 00:00:00.000', 120)

SELECT
    LatestNote.NoteCode,
    LatestNote.NoteDate,           
    SecondLatestNote.NoteCode AS [NoteCode2nd],
    SecondLatestNote.NoteDate AS [NotDate2nd]

FROM Locations LOC


LEFT JOIN (
            SELECT TOP 2 LocationID, NoteID, Row_Number() OVER (ORDER BY Notedate DESC) AS RowNum
            FROM Notes(nolock) 
            WHERE NoteCode = 'NOTIFY' 
            AND NoteDate BETWEEN @DateFrom AND @DateTo
            ) 
                AS TopTwoNotes ON TopTwoNotes.LocationID = LOC.LocationID 

                LEFT JOIN Notes AS LatestNote ON LatestNote.NoteID = TopTwoNotes.NoteID AND TopTwoNotes.RowNum = 1

                LEFT JOIN Notes AS SecondLatestNote ON SecondLatestNote.NoteID = TopTwoNotes.NoteID AND TopTwoNotes.RowNum = 2 

WHERE LOC.LocationID = 308644

Результат - все NULL, строка возвращается только потому, что я использую LEFT JOIN. Почему это не работает ??

Этот SQL показывает, что данные есть, с результатами ниже:

SELECT TOP 2 LocationID, NoteID, Row_Number() OVER (ORDER BY NoteDate DESC) AS RowNum
            FROM Notes(nolock) 
            WHERE NoteCode = 'NOTIFY' 
            AND NoteDate BETWEEN @DateFrom AND @DateTo
            AND LocationID = 308644 

LocationID  NoteID  RowNum
308644  10291348    1
308644  10130566    2


SELECT
    NoteID,
    NoteCode,
    NoteDate,
    LEN(CAST(Note AS VARCHAR(8000))) AS [NoteCharCount]
FROM
    Notes
WHERE
    LocationID = 308644
    AND NoteDate BETWEEN @DateFrom AND @DateTo


NoteID  NoteCode    NoteDate    NoteCharCount
10130566    NOTIFY  2017-11-08  50
10291348    NOTIFY  2017-12-13  66

Должно быть, я что-то упустил - я не могу присоединиться, используя rownum, как это?

Спасибо за вашу помощь.

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Вы можете использовать apply для этой проблемы:

SELECT n_latest.NoteCode, n_latest.NoteDate,           
       n_prev.NoteCode AS NoteCode2nd, n_prev.NoteDate AS NoteDate2nd
FROM Locations l OUTER APPLY
     (SELECT n.*
      FROM Notes n
      WHERE n.NoteCode = 'NOTIFY' AND
            n.NoteDate BETWEEN @DateFrom AND @DateTo
      ORDER BY n.NoteDate DESC
      OFFSET 0 ROWS FETCH FIRST 1 ROW ONLY
     ) n_latest OUTER APPLY
     (SELECT n.*
      FROM Notes n
      WHERE n.NoteCode = 'NOTIFY' AND
            n.NoteDate BETWEEN @DateFrom AND @DateTo
      ORDER BY n.NoteDate DESC
      OFFSET 1 ROWS FETCH FIRST 1 ROW ONLY
     ) n_prev
0 голосов
/ 04 мая 2018

Вам необходимо добавить условие LocationID = 308644 в условие where для подзапроса, в противном случае первая и вторая строки могут не содержать LocationID = 308644.

Тогда Вы используете LEFT JOIN, который не будет соответствовать LocationID = 308644, поэтому будет NULL строка.

SELECT LatestNote.notecode, 
       LatestNote.notedate, 
       SecondLatestNote.notecode AS [NoteCode2nd], 
       SecondLatestNote.notedate AS [NotDate2nd] 
FROM   locations LOC 
       LEFT JOIN (SELECT TOP 2 locationid, 
                               noteid, 
                               Row_number() 
                                 OVER ( 
                                   ORDER BY notedate DESC) AS RowNum 
                  FROM   notes(nolock) 
                  WHERE  notecode = 'NOTIFY' 
                         AND notedate BETWEEN @DateFrom AND @DateTo AND LocationID = 308644) AS TopTwoNotes 
              ON TopTwoNotes.locationid = LOC.locationid 
       LEFT JOIN notes AS LatestNote 
              ON LatestNote.noteid = TopTwoNotes.noteid 
                 AND TopTwoNotes.rownum = 1 
       LEFT JOIN notes AS SecondLatestNote 
              ON SecondLatestNote.noteid = TopTwoNotes.noteid 
                 AND TopTwoNotes.rownum = 2 
WHERE  LOC.locationid = 308644 

EDIT

Вы можете разрешить locations table LEFT JOIN для подзапроса.

SELECT LatestNote.notecode, 
       LatestNote.notedate, 
       SecondLatestNote.notecode AS [NoteCode2nd], 
       SecondLatestNote.notedate AS [NotDate2nd] 
FROM   (
        SELECT TOP 2 TopTwoNotes.locationid, 
                     TopTwoNotes.noteid, 
                     Row_number() 
                       OVER (ORDER BY TopTwoNotes.notedate DESC) AS RowNum 
        FROM   locations LOC 
               LEFT JOIN notes(nolock) TopTwoNotes
                       ON TopTwoNotes.locationid = LOC.locationid 
        WHERE  TopTwoNotes.notecode = 'NOTIFY' 
               AND TopTwoNotes.notedate BETWEEN @DateFrom AND @DateTo 
               AND LOC.locationid = 308644
        ORDER BY TopTwoNotes.notedate DESC
        ) AS TopTwoNotes 
       INNER JOIN notes AS LatestNote 
               ON LatestNote.noteid = TopTwoNotes.noteid 
                  AND TopTwoNotes.rownum = 1 
       INNER JOIN notes AS SecondLatestNote 
               ON SecondLatestNote.noteid = TopTwoNotes.noteid 
                  AND TopTwoNotes.rownum = 2 
...