Как получить только одну запись из левой таблицы против каждой записи из правой таблицы - PullRequest
0 голосов
/ 14 января 2019

У меня есть две таблицы, одна для некоторых устройств и другая для их местоположения (используя эту таблицу для отслеживания истории местоположений). Схемы таблиц:

  1. tbl_Devices:

    • DeviceSrNumber (bigint, not null, pk)
    • Некоторые другие столбцы
  2. tbl_DeviceLocation

    • SrNumber (bigint, not null, pk, identity)
    • DeviceSrNumber (bigint, not null)
    • Местоположение (varchar (300), не ноль)
    • AddDateTime (DateTime, не нуль)

Мне нужно DeviceSrNumber, последнее Location, последнее заданное местоположение AddDateTime

Что я сейчас делаю:

SELECT
    DeviceSrNumber,
    (
        SELECT TOP (1) Location
        FROM tbl_DeviceLocation
        WHERE (DeviceSrNumber = d.DeviceSrNumber)
        ORDER BY AddDateTime DESC
    ) AS 'Location',
    (
        SELECT TOP (1) AddDateTime
        FROM tbl_DeviceLocation
        WHERE (DeviceSrNumber = d.DeviceSrNumber)
        ORDER BY AddDateTime DESC
    ) AS 'AddDateTime '
FROM
    tbl_Devices AS d

Но мне нужно сделать это с более чистым соединением, потому что, насколько мне известно, подзапрос не эффективен и не рекомендуется в крупномасштабной базе данных.

Примечание. Это небольшая часть большого проекта, в котором рассматриваются миллионы записей.

Ответы [ 3 ]

0 голосов
/ 14 января 2019

Ваш запрос будет намного эффективнее:

SELECT D.DeviceSrNumber, 
       L.Location, 
       L.AddDateTime 
FROM        tbl_Devices D
OUTER APPLY
   (SELECT TOP (1) DL.Location, DL.AddDateTime
    FROM tbl_DeviceLocation DL
    WHERE D.DeviceSrNumber = DL.DeviceSrNumber
    ORDER BY DL.AddDateTime DESC
   ) L;
0 голосов
/ 14 января 2019

Попробуйте, он выберет одну единицу данных, используя последний AddDateTime

SELECT top(1) D.DeviceSrNumber, L.Location,L.AddDateTime 
FROM tbl_Devices AS D 
JOIN tbl_DeviceLoation AS L ON D.DeviceSrNumber  = L.DeviceSrNumber 
WHERE D.DeviceSrNumber  = L.DeviceSrNumber  order by L.AddDateTime desc

Обновление

Я попробовал это, и он выбрал отдельную запись в соответствии с последней записью. надеюсь, что это решить

WITH CTE AS 
(
SELECT D.DeviceSrNumber, L.Location,L.AddDateTime , RN= ROW_NUMBER() OVER (PARTITION BY  D.DeviceSrNumber ORDER BY  D.DeviceSrNumber)
FROM  tbl_Devices AS D LEFT JOIN tbl_DeviceLoation AS L ON D.DeviceSrNumber  = L.DeviceSrNumber
WHERE D.DeviceSrNumber  = L.DeviceSrNumber group by  D.DeviceSrNumber, L.Location,L.AddDateTime )
SELECT * FROM CTE where RN=1 order by CTE.AddDateTime desc
0 голосов
/ 14 января 2019

Вы можете начать с этого:

SELECT *
FROM (
    SELECT        
      d.DeviceSrNumber
    , dl.Location    LastLocation
    , dl.AddDateTime LastLocationSetDateTime
    , ROW_NUMBER() OVER(PARTITION BY d.DeviceSrNumber ORDER BY AddDateTime DESC) RN 
    FROM 
        tbl_Devices d
    JOIN tbl_DeviceLocation dl ON dl.DeviceSrNumber = d.DeviceSrNumber 
) D 
WHERE 
    RN = 1

UPDATE

SELECT        
  d.DeviceSrNumber
, MAX(dl.Location)  LastLocation
, MAX(dl.AddDateTime) LastLocationSetDateTime
FROM 
    tbl_Devices d
JOIN tbl_DeviceLocation dl ON dl.DeviceSrNumber = d.DeviceSrNumber 
GROUP BY d.DeviceSrNumber
ORDER BY AddDateTime DESC
...