仅从一个查询中选择特定行信息

时间:2014-09-11 20:43:05

标签: sql sql-server row greatest-n-per-group ssms

好的,所以我遇到了一个严重的问题

我有原始查询(在下面这一个中是查询A)从SiteAppointmentArrivals中选择所有信息(包括空),这很棒 - 因为我需要显示用户何时没有到达指定站点- 缺席。

但是,这些网站都分组在不同的组中。因此,一个组可能有五个站点,另一个组可能只有一个,等等。有时当用户登录到一个分组站点时,他们只会登录到一个站点 - 逻辑上他们应该登录到所有站点 - 但是在系统中它目前显示他们已登录到一个站点,其他站点为NULL。

现在,我只想在每个组中选择一个站点(因此max(s.siteid)适用于登录所有站点或根本不显示任何站点的人员。但是,对于那些奇怪的人,他们有到达日期和空值 - 两行显示。我想消除此实例中的NULL行,因为他们通过登录其中一个站点逻辑登录到该组。

我创建了这个伪代码 - 尝试组合查询的两个版本 - 一个包含所有信息,另一个包含只有到达人员的信息。

如果在B中找到来自A(所有信息)的GroupID(仅到达信息),则显示B行信息,如果A中的GroupID不在B中,则显示A行。我认为逻辑会适当地捕获我需要的东西,但我不知道如何在SQL中表达它

编辑简洁

Select DISTINCT
CASE WHEN a.GroupID=b.GroupID THEN b.*
WHEN a.GroupID <> b.GroupID THEN a.* END -- Psuedo Code
From
(SELECT DISTINCT
    max(s.SiteID) SiteID,
    s.GroupID,
    saa.Time ArrivalTime,
    sas.ScannerUserID
FROM 
    dbo.Sites s
    INNER JOIN dbo.SiteAppointments sa ON s.SiteID = sa.SiteID
    INNER JOIN dbo.SiteAppointmentsScanners sas ON sa.SiteAppointmentID = sas.SiteAppointmentID
    LEFT JOIN dbo.SiteAppointmentArrivals saa ON sa.SiteAppointmentID = saa.SiteAppointmentId 
                                          AND saa.ScannerUserID = sas.ScannerUserID
WHERE 
    ProjectID = 110
    AND 
        (
            (CAST(sa.StartDateTime AS DATE) >= '09/03/2014' AND CAST(sa.StartDateTime AS DATE) <= '09/03/2014')
            OR
            (CAST(sa.EndDateTime AS DATE) >= '09/03/2014' AND CAST(sa.EndDateTime AS DATE) <= '09/03/2014')
        )
    AND ((CAST(saa.Date AS DATE) >= '09/03/2014' AND CAST(saa.Date AS DATE) <= '09/03/2014') OR saa.Date IS NULL)
GROUP BY
    s.GroupID,
    saa.Time,
    sas.ScannerUserID
 )a

LEFT JOIN 


(SELECT DISTINCT
    max(s.SiteID) SiteID,
    s.GroupID,
    saa.Time ArrivalTime,
    sas.ScannerUserID
FROM 
    dbo.Sites s
    INNER JOIN dbo.SiteAppointments sa ON s.SiteID = sa.SiteID
    INNER JOIN dbo.SiteAppointmentsScanners sas ON sa.SiteAppointmentID = sas.SiteAppointmentID
    INNER JOIN dbo.SiteAppointmentArrivals saa ON sa.SiteAppointmentID = saa.SiteAppointmentId 
                                          AND saa.ScannerUserID = sas.ScannerUserID
WHERE 
    ProjectID = 110
    AND 
        (
            (CAST(sa.StartDateTime AS DATE) >= '09/03/2014' AND CAST(sa.StartDateTime AS DATE) <= '09/03/2014')
            OR
            (CAST(sa.EndDateTime AS DATE) >= '09/03/2014' AND CAST(sa.EndDateTime AS DATE) <= '09/03/2014')
    )
    AND ((CAST(saa.Date AS DATE) >= '09/03/2014' AND CAST(saa.Date AS DATE) <= '09/03/2014') OR saa.Date IS NULL)
GROUP BY
    s.GroupID,
    saa.Time,
    sas.ScannerUserID
 ) b ON a.SiteID=b.SiteID

一个例子:

SiteID | GroupID | ArrivalTime             | Scanner
------------------------------------------------------
12345  | 54321   | NULL                    | 1011
------------------------------------------------------
67890  | 54321   | 2014-09-03 09:09:48.053 | 1011

所以这里 - 扫描器/用户已进入组内的站点(所以从技术上讲,即使其他站点为NULL,他也已登录到组中)所以我想隐藏NULL值并保持到达值。

2 个答案:

答案 0 :(得分:2)

我认为您需要使用ROW_NUMBER()排名功能:

WITH SiteArrivals AS (
SELECT DISTINCT
    s.SiteID,
    s.GroupID,
    saa.Time ArrivalTime,
    sas.ScannerUserID,
    ROW_NUMBER() OVER (PARTITION BY s.GroupID ORDER BY saa.Time DESC, s.SiteID DESC) rn
FROM 
    dbo.Sites s
    INNER JOIN dbo.SiteAppointments sa ON s.SiteID = sa.SiteID
    INNER JOIN dbo.SiteAppointmentsScanners sas ON sa.SiteAppointmentID = sas.SiteAppointmentID
    LEFT JOIN dbo.SiteAppointmentArrivals saa ON sa.SiteAppointmentID = saa.SiteAppointmentId 
                                          AND saa.ScannerUserID = sas.ScannerUserID )
SELECT * 
FROM SiteArrivals sa WHERE SiteID IS NOT NULL and rn = 1

这是一个演示此解决方案的SqlFiddle - http://sqlfiddle.com/#!3/b57c6/4

答案 1 :(得分:0)

如果我正确理解了这个问题,你只需要复制&#34;到达那些行的到达时间,其中Scanner / user相同且GroupID相同,但SiteID不同且未指定ArrivalTime。

在这种情况下,您只需使用以下查询:

;
with f1 as
(
    SELECT DISTINCT
        max(s.SiteID) SiteID,
        s.GroupID,
        saa.Time ArrivalTime,
        sas.ScannerUserID
    FROM dbo.Sites s
    INNER JOIN dbo.SiteAppointments sa
        ON s.SiteID = sa.SiteID
    INNER JOIN dbo.SiteAppointmentsScanners sas
        ON sa.SiteAppointmentID = sas.SiteAppointmentID
    LEFT JOIN dbo.SiteAppointmentArrivals saa
        ON sa.SiteAppointmentID = saa.SiteAppointmentId 
        AND saa.ScannerUserID = sas.ScannerUserID
    WHERE 
        ProjectID = 110
        AND 
            (
                (CAST(sa.StartDateTime AS DATE) >= '09/03/2014' AND CAST(sa.StartDateTime AS DATE) <= '09/03/2014')
                OR
                (CAST(sa.EndDateTime AS DATE) >= '09/03/2014' AND CAST(sa.EndDateTime AS DATE) <= '09/03/2014')
            )
        AND ((CAST(saa.Date AS DATE) >= '09/03/2014' AND CAST(saa.Date AS DATE) <= '09/03/2014') OR saa.Date IS NULL)
    GROUP BY
        s.GroupID,
        saa.Time,
        sas.ScannerUserID
 ),
 f2 as
 (
    select GroupID, ScannerUserID, max(ArrivalTime) ArrivalTime
    from f1
    group by GroupID, ScannerUserID
 )
 select f1.SiteID, f1.GroupID, f2.ArrivalTime, f1.ScannerUserID
 from f1 f1
 left join f2 f2
    on f1.GroupID = f2.GroupID
    and f1.ScannerUserID = f2.ScannerUserID

可以在此处找到演示此解决方案的SqlFiddle:http://sqlfiddle.com/#!3/623b2c/10