Iteration SQL Query? - sql

I have very difficult scenario in my Oracle DB. I have a table setup as following:
ID File_route_group CollectID DeliveryID Sequence
---------- ------------ --------- ------------ --------
11483 12 123 411 1
12174 12 411 523 2
12465 12 523 611 3
12165 46 215 662 1
52462 12 266 394 4
12199 46 662 718 2
61244 12 394 980 5
Each line represents a "route" a certain file has taken and the following row (next sequence) should always have the same CollectID as the previous sequences DeliveryID.
In this example row ID 52462 is wrong. It should have collectID 611 (as row with sequence 3 have that as its deliveryID).
Is there a way to create a query that would have returned this row (with id 52462)? Like following:
ID File_route_group CollectID DeliveryID Sequence
---------- ------------ --------- ------------ --------
52462 12 266 394 4

WITH cte AS
( SELECT ID,
File_route_group,
CollectID,
DeliveryID,
Sequence,
LAG(DeliveryID, 1) OVER (PARTITION BY File_route_group
ORDER BY Sequence)
Previous_DeliveryID
FROM Routes
)
SELECT *
FROM cte
WHERE ( CollectID <> Previous_DeliveryID
OR CollectID IS NULL
OR Previous_DeliveryID IS NULL
)
AND Sequence > 1 ;
Tested at SQL-Fiddle

You can join the table with itself to represent the relation between the 'current' and the 'previous' entry:
SELECT * FROM route current_route
JOIN route last_route
ON current_route.Sequence = last_route.Sequence + 1
AND current_route.File_route_grp = last_route.File_route_grp
WHERE current_route.CollectID <> last_route.DeliveryID
Note that while the usage of LAG() proposed in the other answers is the more elegant and possibly more performant way of doing this in Oracle, this solution is more portable and also works, e.g. with MySQL and other DBMS.

In a derived table use the LAG function to get the PreviousDeliveryID then filter that where the CollectionId does not equal PreviousDeliveryID
SELECT ID, Customer_id, CollectID, DeliveryID, Sequence
FROM (
SELECT ID, Customer_id, CollectID, DeliveryID, Sequence, LAG(DeliveryID, 1) OVER(ORDER BY ID) AS PrevDeliveryID
FROM Routes
) AS t
WHERE t.CollectionID <> t.PrevDeliveryID

Related

SQL Server: How to retrieve all record based on recent datetime

First off, apologies if this has been asked elsewhere as I was unable to find any solution. The best I get is retrieving latest 1 record or 2-3 records. I'm more in search of all records (the number could be dynamic, could be 1 or 2 or maybe 50+) based on recent Datetime value. Well so basically here is the problem,
I have a table as follows,
APILoadDatetime
RowId
ProjectId
Value
2021-07-13 15:09:14.620
1
Proj-1
101
2021-07-13 15:09:14.620
2
Proj-2
81
2021-07-13 15:09:14.620
3
Proj-3
111
2021-07-13 15:09:14.620
4
Proj-4
125
2021-05-05 04:46:07.913
1
Proj-1
99
2021-05-05 04:46:07.913
2
Proj-2
69
2021-05-05 04:46:07.913
3
Proj-3
105
2021-05-05 04:46:07.913
4
Proj-4
115
...
...
...
...
What I am looking to do is, write up a query which will give me all the recent data based on Datetime, so in this case, I should get the following result,
APILoadDatetime
RowId
ProjectId
Value
2021-07-13 15:09:14.620
1
Proj-1
101
2021-07-13 15:09:14.620
2
Proj-2
81
2021-07-13 15:09:14.620
3
Proj-3
111
2021-07-13 15:09:14.620
4
Proj-4
125
The RowId shows (as the name suggests) gives the number of Rows for a particular Datetime block. This will not always be 4, it's dynamic based on the data received so could be 1,2,4 or even 50+ ...
Hope I was able to convey the question properly, Thank you all for reading and Pre-Thank you to those who provide solution to this.
you can use window function row_number to find out the latest entry for each projectid:
select * from (
select * , rank() over (order by APILoadDatetime desc) rn
from tablename
) t where rn = 1
select top 1 with ties
*
from
tablename
order by
row_number() over(
partition by RowId
order by APILoadDatetime desc
);
TOP 1 works with WITH TIES here.
WITH TIES means that when ORDER BY = 1, then SELECT takes this record (because of TOP 1) and all others that have ORDER BY = 1 (because of WITH TIES).
Update #1:
If you need the last record by APILoadDatetime and several records which might have the same APILoadDatetime (as the first found), then the query is simplier:
select top 1 with ties
*
from
tablename
order by
APILoadDatetime desc;

Most Efficient SQL to Calculate Running Streak Occurrences

I am looking for the most efficient manner to determine the longest occurrence of a streak within a given data set; specifically, to determine the longest winning streak of games.
Below is the SQL that I have thus far, and it does seem to perform very fast, and as expected from the limited testing I've done on a dataset with around 100,000 records.
DECLARE #HistoryDateTimeLimit datetime = '3/15/2018';
CTE to create result subset from voting dataset.
WITH Results AS (
SELECT
EntityPlayerId,
(CASE
WHEN VoteTeamA = 1 AND ParticipantAScore > ParticipantBScore THEN 'W'
WHEN VoteTeamA = 0 AND ParticipantBScore > ParticipantAScore THEN 'W'
ELSE 'L'
END) AS WinLoss,
match.ScheduledStartDateTime
FROM
[dbo].[MatchVote] vote
INNER JOIN [dbo].[MatchMetaData] match ON vote.MatchId = match.MatchId
WHERE
IsComplete = 1
AND ScheduledStartDateTime >= #HistoryDateTimeLimit
)
CTE to create subset of data with streak type as WinLoss and total count of votes in the partition using ROW_NUMBER().
WITH Streaks AS (
SELECT
EntityPlayerId,
ScheduledStartDateTime,
WinLoss,
ROW_NUMBER() OVER (PARTITION BY EntityPlayerId ORDER BY ScheduledStartDateTime) -
ROW_NUMBER() OVER (PARTITION BY EntityPlayerId, WinLoss ORDER BY ScheduledStartDateTime) AS Streak
FROM
Results
)
CTE to summarize the partitioned vote streaks by WinLoss and a begin date/time, with the total count in the streak.
WITH StreakCounts AS (
SELECT
EntityPlayerId,
WinLoss,
MIN(ScheduledStartDateTime) StreakStart,
MAX(ScheduledStartDAteTime) StreakEnd,
COUNT(*) as Streak
FROM
Streaks
GROUP BY
EntityPlayerId, WinLoss, Streak
)
CTE to select the MAXIMUM (longest) vote streak for WinLoss of W (win) grouped by players.
WITH LongestWinStreak AS (
SELECT
EntityPlayerId,
MAX(Streak) AS LongestStreak
FROM
StreakCounts
WHERE
WinLoss = 'W'
GROUP BY
EntityPlayerId
)
Selecting the useful data from the LongestWinStreak CTE.
SELECT * FROM LongestWinStreak
This is the 3rd iteration of the code; at first I feel like I was overthinking and using windows with the LAG function to define a reset period that was later used for partitioning.
[UPDATE]: SQLFiddle example at http://sqlfiddle.com/#!18/5b33a/1 -- Sample data for the two tables that are used above are as follows.
The data is meant to show the schema, and can be extrapolated for your own testing/usage;
MatchVote table data.
EntityPlayerId IsExtMatch MatchId VoteTeamA VoteDateTime IsComplete
-------------------- ------------ -------------------- --------- ----------------------- ----------
158 1 152639 0 2018-03-20 23:25:28.910 1
158 1 156058 1 2018-03-13 23:36:57.517 1
MatchMetaData table data.
MatchId IsTeamTournament MatchCompletedDateTime ScheduledStartDateTime MatchIsFinalized TournamentId TournamentTitle TournamentLogoUrl TournamentLogoThumbnailUrl GameName GameShortCode GameLogoUrl ParticipantAScore ParticipantAName ParticipantALogoUrl ParticipantBScore ParticipantBName ParticipantBLogoUrl
--------- ---------------- ----------------------- ----------------------- ---------------- -------------------- ------------------ ----------------------- ---------------------------- --------------------------------- -------------- ----------------------- ------------------ ------------------- --------------------- ----------------- ------------------- --------------------
23354 1 2014-07-30 00:30:00.000 2014-07-30 00:00:00.000 1 543 Sample https://...Small.png https://...Small.png Dota 2 Dota 2 https://...logo.png 3 Natus Vincere.US https://...VI.png 0 Not Today https://...ay.png
44324 1 2014-12-15 12:40:00.000 2014-12-15 11:40:00.000 1 786 Sample https://...Small.png https://...Small.png Counter-Strike: Global Offensive CS:GO https://...logo.png 0 Avalier's stars https://...oto.png 1 Kassad's Legends https://...oto.png

Get last entry from each user in database

I have a Postgresql database, and I'm having trouble getting my query right, even though this seems like a common problem.
My table looks like this:
CREATE TABLE orders (
account_id INTEGER,
order_id INTEGER,
ts TIMESTAMP DEFAULT NOW()
)
Everytime there is a new order, I use it to link the account_id and order_id.
Now my problem is that I want to get a list that has the last order (by looking at ts) for each account.
For example, if my data is:
account_id order_id ts
5 178 July 1
5 129 July 6
4 190 July 1
4 181 July 9
3 348 July 1
3 578 July 4
3 198 July 1
3 270 July 12
Then I'd like the query to return only the last row for each account:
account_id order_id ts
5 129 July 6
4 181 July 9
3 270 July 12
I've tried GROUP BY account_id, and I can use that to get the MAX(ts) for each account, but then I have no way to get the associated order_id. I've also tried sub-queries, but I just can't seem to get it right.
Thanks!
select distinct on (account_id) *
from orders
order by account_id, ts desc
https://www.postgresql.org/docs/current/static/sql-select.html#SQL-DISTINCT:
SELECT DISTINCT ON ( expression [, ...] ) keeps only the first row of each set of rows where the given expressions evaluate to equal. The DISTINCT ON expressions are interpreted using the same rules as for ORDER BY (see above). Note that the "first row" of each set is unpredictable unless ORDER BY is used to ensure that the desired row appears first.
The row_number() window function can help:
select account_id, order_id, ts
from (select account_id, order_id, ts,
row_number() over(partition by account_id order by ts desc) as rn
from tbl) t
where rn = 1

Getting count of each row in oracle sql

Consider below table:
EmpId EmpType ExpUniId
1 A 234
1 B 453
2 A 454
I want to write a sql query such that I get following data
EmpId EmpType ExpUniId Count
1 A 234 2
1 B 453 2
2 A 454 1
Count implies number of rows corresponding to each Emp Id
I am using Oracle Sql.
Thanks
You are looking for the analytic version of count():
select t.*,
count(*) over (partition by EmpId) as Count
from table t;

Retrieve single record with recent date from a table having same column value in multiple records

I've a table with data as below:
LabId lab_name Measured_date value
------ -------- ------------- -----
1519253 LAST_DBP 19-JUN-12 78
1519252 LAST_SBP 19-JUN-12 151
1519267 LDL 27-AUG-12 84
1519262 LDL 17-AUG-12 86
1519250 SBP 17-AUG-12 181
I wanted to retrieve data from this table such that, if more than one record exists for same lab_name I would need the record with latest measured_date. So my desired output should look like:
LabId lab_name Measured_date value
------ -------- ------------- -----
1519253 LAST_DBP 19-JUN-12 78
1519252 LAST_SBP 19-JUN-12 151
1519267 LDL 27-AUG-12 84
1519250 SBP 17-AUG-12 181
Thanks
Gopi
use Analytic fn: Rank()
WITH TEMP AS
(
SELECT LabId , lab_name ,Measured_date ,value,
rank() OVER (PARTITION BY lab_name ORDER BY Measured_date desc) AS RK
FROM TABLE1
)
SELECT LabId , lab_name ,Measured_date ,value FROM TEMP WHERE RK=1;