Отличное ключевое слово SQL недостаточно фильтруется - PullRequest
0 голосов
/ 29 марта 2012

Я новичок в sql и уже почти один день застрял в следующей проблеме:

У меня есть две таблицы, из которых я получаю значения, devices и devices_LOG.Мне нужно отобразить все записи devices_LOG, где devices.status = '1' И мне нужно, чтобы они были уникальными (т.е. я хочу видеть только одну запись devices_LOG для каждого устройства).Мой код выглядит так:

    SELECT DISTINCT 
                     devices_LOG.device_id, MAX(devices_LOG.LogDate) AS LogDate,
                     manufacturers.name, devices_LOG.LogType, devices_LOG.userName, 
                     devices_LOG.userFullname, devices.invnumber, devices.modelname,
                     devices.modelnumber
    FROM             devices_LOG 
    INNER JOIN
                     devices ON devices_LOG.device_id = devices.id AND 
                     devices_LOG.device_id = devices.id 
    INNER JOIN
                     manufacturers ON devices.manufacturer_id = manufacturers.id
    WHERE            (devices.devicestatus = '1') AND (devices_LOG.LogType = 'Out')
    GROUP BY         devices_LOG.device_id, manufacturers.name, devices_LOG.LogType,
                     devices_LOG.userName, devices_LOG.userFullname, devices.invnumber, 
                     devices.modelname, devices.modelnumber
    ORDER BY         devices_LOG.device_id

, который отлично подходит для возврата только записей для вещей, которые имеют device.status = '1', но он возвращает несколько записей журнала для чего-то с одним и тем же device.id.Итак, результаты моего запроса выглядят так:

    device_id  LogDate       username    LogType    modelname   ...etc
    1          11/12/2011    foo         out        generic
    1          11/10/2011    world       out        generic
    2          9/10/2011     hello       out        generic3
    2          8/9/2011      bye         out        generic3

, когда мне нужно, чтобы это выглядело так:

    device_id  LogDate       username    LogType    modelname   ...etc
    1          11/12/2011    foo         out        generic
    2          9/10/2011     hello       out        generic3

Я пытался использовать MAX в LogDate, пытался группировать, выбирать разные,и т.д .... но я просто не могу понять это.Любые идеи?

Я понимаю, что мое заявление sql сейчас довольно уродливо, возможно потому, что я безуспешно пробовал все, что могу придумать до этого момента, поэтому любая помощь будет принята с благодарностью, спасибо

Ответы [ 6 ]

1 голос
/ 29 марта 2012

Я бы пошел с этим запросом, который можно увидеть в действии на http://www.sqlfiddle.com/#!3/70c0e/6:

;WITH Base AS
(
    SELECT
        D.id
        , MAX(L.LogDate) AS LastLogEntry
    FROM devices D
    INNER JOIN devices_LOG L
        ON L.device_id = D.id
    WHERE D.devicestatus = '1'
    GROUP BY D.id
)
SELECT 
    L.device_id
    , B.LastLogEntry AS LogDate
    , M.name
    , L.LogType
    , L.userName
    , L.userFullname
    , D.invnumber
    , D.modelname
    , D.modelnumber
FROM Base B
INNER JOIN devices D
    ON D.id = B.id
INNER JOIN manufacturers M
    ON M.id = D.manufacturer_id
INNER JOIN devices_LOG L
    ON L.device_id = B.id
    AND L.LogDate = B.LastLogEntry
1 голос
/ 29 марта 2012

У вас почти есть его, но чтобы получить максимум для каждого устройства, вы должны присоединиться к журналу и найти максимум для каждого устройства, тогда группировка не требуется:

SELECT devices_LOG.device_id,
  devices_LOG.LogDate AS LogDate,
  manufacturers.name,
  devices_LOG.LogType,
  devices_LOG.userName,
  devices_LOG.userFullname,
  devices.invnumber,
  devices.modelname,
  devices.modelnumber
FROM devices_LOG
INNER JOIN devices
ON devices_LOG.device_id  = devices.id
AND devices_LOG.device_id = devices.id
INNER JOIN manufacturers
ON devices.manufacturer_id  = manufacturers.id
JOIN (SELECT devices_LOG.device_id,
  MAX(devices_LOG.LogDate) as LogDate
  FROM devices_LOG
  WHERE devices_LOG.LogType = 'Out'
  GROUP BY devices_LOG.device_id) maxLog 
ON maxLog.LogDate = devices_LOG.LogDate
WHERE (devices.devicestatus = '1')
AND (devices_LOG.LogType    = 'Out')
ORDER BY devices_LOG.device_id 
0 голосов
/ 29 марта 2012

Q # 1: почему вы повторяете эту строку дважды?С devices_LOG INNER ПРИСОЕДИНЯЙТЕСЬ к устройствам ON devices_LOG.device_id = devices.id AND devices_LOG.device_id = devices.id

Ваша проблема в таблице производителей.у него есть два значения для имени.Производители.имя как имя пользователя Foo / World Hello / Bye

Вот почему вы видите две строки.это не проблема журнала устройства / макс.

Пожалуйста, исправьте меня, если я что-то пропустил.(Я следовал вашему порядку кода)

0 голосов
/ 29 марта 2012

Я думаю, что это отличное место для использования DENSE_RANK () и CTE.

WITH LOG as 
    (
     SELECT devices_LOG.*,
           DENSE_RANK() over (partition by device_id order by device_id asc, LogDate desc) as nRank
     FROM devices_LOG
     WHERE nRank = 1
    )

SELECT DISTINCT 
                 LOG.device_id, LOG.LogDate AS LogDate,
                 manufacturers.name, LOG.LogType, LOG.userName, 
                 LOG.userFullname, devices.invnumber, devices.modelname,
                 devices.modelnumber
FROM             LOG   ---Notice I have changed which table you are selecting from. 
INNER JOIN
                 devices ON LOG.device_id = devices.id
INNER JOIN
                 manufacturers ON devices.manufacturer_id = manufacturers.id
WHERE            (devices.devicestatus = '1') AND (LOG.LogType = 'Out')
GROUP BY         LOG.device_id, manufacturers.name, LOG.LogType,
                 LOG.userName, LOG.userFullname, devices.invnumber, 
                 devices.modelname, devices.modelnumber
ORDER BY         LOG.device_id
0 голосов
/ 29 марта 2012

Просто оберните запись журнала в CTE и используйте ROW_NUMBER с разделом для получения необходимых данных.

Например, если вы хотите самую старую запись журнала, вы можете изменить ORDER BY LogDate DESC на ASC.

WITH Log AS (
SELECT ROW_NUMBER() OVER (PARTITION BY device_id ORDER BY LogDate DESC) AS RN, *
FROM Devices_LOG
WHERE LogType = 'Out'
)

SELECT DISTINCT 
                     Log.device_id, Log.LogDate AS LogDate,
                     manufacturers.name, Log.LogType, Log.userName, 
                     Log.userFullname, devices.invnumber, devices.modelname,
                     devices.modelnumber
    FROM             devices 
    INNER JOIN
                     Log ON Log.device_id = devices.id AND 
                     Log.RN = 1 
    INNER JOIN
                     manufacturers ON devices.manufacturer_id = manufacturers.id
    WHERE            (devices.devicestatus = '1')
    ORDER BY         devices.device_id
0 голосов
/ 29 марта 2012

Что если вы просто сгруппируете по devices_LOG.device_id?

...
    GROUP BY         devices_LOG.device_id
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...