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.