SQL distinct关键字不够过滤

时间:2012-03-29 16:13:42

标签: sql sql-server sql-server-2008

我是sql的新手,现在已经被困在以下问题上近一天了:

我有两个表,我从中提取值,设备和设备_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

我尝试在LogDate上使用MAX,尝试分组,选择不同等等......但我无法弄明白。有什么想法吗?

我意识到我的sql语句现在非常难看,可能是因为我一直在尝试一切我能想到的,没有运气,所以任何帮助都会非常感激,谢谢

6 个答案:

答案 0 :(得分:1)

你几乎拥有它,但要获得每个设备的最大值,你应该加入日志并找到每个设备的最大值,然后不需要分组:

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 

答案 1 :(得分:1)

我会使用此查询,可以在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

答案 2 :(得分:0)

如果您只是按设备_LOG.device_id分组怎么办?

...
    GROUP BY         devices_LOG.device_id
...

答案 3 :(得分:0)

只需将日志条目包装在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

答案 4 :(得分:0)

我认为这是一个使用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

答案 5 :(得分:0)

问题1:你为什么两次重复这一行? 来自devices_LOG INNER JOIN设备ON devices_LOG.device_id = devices.id                   和                       devices_LOG.device_id = devices.id

您的问题出在制造商表中。它有两个名称值。 manufacturers.name为用户名 美孚/世界 你好/再见

这就是你看到两行的原因。它不是设备日志/最大问题。

如果我错过任何事情,请纠正我。 (我按照你的代码顺序)