简体   繁体   中英

Need first record based on the earliest date - Sql Server 2012

I have the below data.

Base table
Id   DateTime
201  2015-05-03 08:01
301  2015-05-03 08:20
401  2015-05-03 08:40

Extract Table
Id   DateTime            Location
201  2015-05-03 07:50    City A
201  2015-05-03 08:01    City B
201  2015-05-03 08:50    City C
301  2015-05-03 07:15    City E
301  2015-05-03 08:01    City F
301  2015-05-03 08:20    City G
401  2015-05-03 08:40    City X
401  2015-05-03 08:55    City Y

Desired Result:
Location  Id    DateTime
City A    201   2015-05-03 07:50
City E    301   2015-05-03 07:15
City X    401   2015-05-03 08:40

To clear the picture, I am trying to get the first location for each customer where they checked in. Since I will be filtering some Locations I will need to have

WHERE Location in ('City A','City B','City C','City E','City F','City G','City X','City Y')

Thanks.

Perhaps this is what you want?

select b.id,
       (CASE WHEN b.ADateTime = e.RDateTime THEN e.Location
             ELSE (SELECT TOP 1 e.Location
                   FROM Extract e2
                   WHERE e2.id = e.id
                   ORDER BY RdateTime ASC
                  ) 
        END) AS [Test],
       a.Location
from Base b inner join
     Extract e 
     on b.id = e.id
where b.id = 301;

This gets the location associated with the minimum matching id . There are definitely other ways to expression this logic, assuming this is what you are really looking for.

I still think a LEFT JOIN is the way to go:

SELECT extract.id, extract.location
FROM [base]
INNER JOIN [extract] ON [base].id = [extract].id
LEFT JOIN extract [earlierExtract] ON [extract].id = [earlierExtract].id
    AND [earlierExtract].DATETIME < [extract].DATETIME
    AND [earlierExtract].Location IN (
        'City A'
        ,'City B'
        ,'City C'
        ,'City E'
        ,'City F'
        ,'City G'
        ,'City X'
        ,'City Y'
        )
WHERE extract.Location IN (
        'City A'
        ,'City B'
        ,'City C'
        ,'City E'
        ,'City F'
        ,'City G'
        ,'City X'
        ,'City Y'
        )
    AND earlierextract.id IS NULL

The easiest way to get what you want utilizes a Windowed Aggregate Function, ROW_NUMBER:

select *
from
 (
   SELECT ...,
      ROW_NUMBER() -- assign a sequence, oldest row gets 1
      OVER (PARTITION BY e.id
            ORDER BY e.[DateTime]) as rn
   FROM [base] as b
   JOIN [extract] as e
     ON b.id = e.id
   WHERE Location in ('City A','City B','City C','City E','City F','City G','City X','City Y')
     AND ... -- any additional filter you need
 ) as dt
WHERE rn = 1 -- first join all rows, then return only the oldest.

Another solution would be to use an EXISTS, to bring back only the earliest record.

--Sample data population...
DECLARE @BaseTable TABLE (ID INT, DateTime SMALLDATETIME) 
DECLARE @ExtractTable TABLE (ID INT, DateTime SMALLDATETIME, Location VARCHAR(25))
INSERT INTO @BaseTable (ID, DateTime) SELECT 201, '2015-05-03 08:01'
INSERT INTO @BaseTable (ID, DateTime) SELECT 301, '2015-05-03 08:20'
INSERT INTO @BaseTable (ID, DateTime) SELECT 401, '2015-05-03 08:40'
INSERT INTO @ExtractTable (ID, DateTime, Location) SELECT 201, '2015-05-03 07:50', 'City A'
INSERT INTO @ExtractTable (ID, DateTime, Location) SELECT 201, '2015-05-03 08:01', 'City B'
INSERT INTO @ExtractTable (ID, DateTime, Location) SELECT 201, '2015-05-03 08:50', 'City C'
INSERT INTO @ExtractTable (ID, DateTime, Location) SELECT 301, '2015-05-03 07:15', 'City E'
INSERT INTO @ExtractTable (ID, DateTime, Location) SELECT 301, '2015-05-03 08:01', 'City F'
INSERT INTO @ExtractTable (ID, DateTime, Location) SELECT 401, '2015-05-03 08:40', 'City X'
INSERT INTO @ExtractTable (ID, DateTime, Location) SELECT 401, '2015-05-03 08:55', 'City Y'

--Example of lookup, using EXISTS to bring back the earliest check-in location of the customer...
SELECT
     ExtractTable.Location
    ,BaseTable.ID
    ,ExtractTable.DateTime
FROM @BaseTable BaseTable
INNER JOIN @ExtractTable ExtractTable ON
        EXISTS
            (
                SELECT 1
                FROM @ExtractTable Ext
                WHERE Ext.ID=BaseTable.ID
                GROUP BY Ext.ID
                HAVING MIN(Ext.DateTime)=ExtractTable.DateTime
            )
WHERE ExtractTable.Location IN 
    (
         'City A'
        ,'City B'
        ,'City C'
        ,'City E'
        ,'City F'
        ,'City G'
        ,'City X'
        ,'City Y'
    )

I think you'll find this much much more manageable than the existing solutions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM