I wish to get the overall ranking of a runner's race time by a particular event.
SELECT a.EventName, b.RunEventName, c.RaceTime, RANK() OVER (ORDER BY RaceTime)Rank
FROM dbo.Event AS a, dbo.RunEvent as b, dbo.RegistrationEvent as c, dbo.Registration as d
WHERE b.EventId = a.EventId
AND c.RunEventId = b.RunEventId
AND c.RegistrationId = d.RegistrationId
AND b.RunEventId = '1'
AND NOT RaceTime IS NULL AND NOT RaceTime = 0
My query results are as shown below:
EventName RunEventName RaceTime Rank
--------------------------------------------------------------
1 Event 1 Run 1049 1
2 Event 1 Run 1179 2
3 Event 1 Run 1407 3
4 Event 1 Run 1648 4
5 Event 1 Run 1817 5
6 Event 1 Run 1865 6
If I do an SQL statement to only display row number 5, my results are:
EventName RunEventName RaceTime Rank
----------------------------------------------------------------
1 Event1 Run 1817 1
The expected output for rank should be 5 but it shows 1 instead.
Use your current query as a CTE, and then select the row you want from the CTE.
WITH cte AS ({your current query})
SELECT * FROM cte
WHERE Rank=5
Related
I have a set of data that I want to classify into groups based on a prior record id existing on the newer rows. The initial record of the group has a prior sequence id = 0.
The data is as follows:
customer id
sequence id
prior_sequence id
1
1
0
1
2
1
1
3
2
2
4
0
2
5
4
2
6
0
2
7
6
Ideally, I would like to create the following grouping column and yield the following results:
customer id
sequence id
prior sequence id
grouping
1
1
0
1
1
2
1
1
1
3
2
1
2
4
0
2
2
5
4
2
2
6
0
3
2
7
6
3
I've attempted to utilize island gap logic utilizing the ROW_NUMBER() function. However, I have been unsuccessful in doing so. I suspect the need here is more along the lines of a recursive CTE, which I am attempting at the moment.
I agree that a recursive CTE will do the job. Something like:
WITH reccte AS
(
/*query that determines starting point for recursion
*
* In this case we want all records with no prior_sequence_id
*/
SELECT
customer_id,
sequence_id,
prior_sequence_id,
/*establish grouping*/
ROW_NUMBER() OVER (ORDER BY sequence_id) as grouping
FROM yourtable
WHERE prior_sequence_id = 0
UNION
/*join the recursive CTe back to the table and iterate*/
SELECT
yourtable.customer_id,
yourtable.sequence_id,
yourtable.prior_sequence_id,
reccte.grouping
FROM reccte
INNER JOIN yourtable ON reccte.sequence_id = yourtable.prior_sequence_id
)
SELECT * FROM reccte;
It looks like you could use a simple correlated query, at least given your sample data:
select *, (
select Sum(Iif(prior_sequence_id = 0, 1, 0))
from t t2
where t2.sequence_id <= t.sequence_id
) Grouping
from t;
See Example Fiddle
I have 2 BigQuery tables:
1- Trips
car start end
---------------------------------------------------
1 2019-03-13T17:07:00 2019-03-13T17:17:00
2 2019-03-13T17:07:00 2019-03-13T17:22:00
3 2019-03-13T17:07:00 2019-03-13T17:34:00
4 2019-03-13T17:07:00 2019-03-13T17:12:00
2- Tracking
car created_at status
--------------------------------------
1 2019-03-13T17:01:00 1
1 2019-03-13T17:02:00 1
1 2019-03-13T17:03:00 1
1 2019-03-13T17:04:00 1
1 2019-03-13T17:05:00 2
1 2019-03-13T17:06:00 2
1 2019-03-13T17:18:00 3
1 2019-03-13T17:19:00 3
1 2019-03-13T17:20:00 3
1 2019-03-13T17:21:00 3
1 2019-03-13T17:22:00 3
The tracking table contains the status of a car until it was on a trip. My objective is to get the status of a car on the previous moment of a trip.
My approach so far was:
select *,
(select status created_at from tracking
where car = tracking.car
AND start > created_at
order by created_at desc
limit 1
) as previous_status
from trips
But I'm getting the following error:
Correlated subqueries that reference other tables are not supported unless they can be de-correlated, such as by transforming them into an efficient JOIN.
Any clue on how to rewrite the query for BigQuery?
To get the previous event use LAG() OVER() as in:
SELECT actor.login
, type
, LAG(type, 1) OVER(PARTITION BY actor.login ORDER BY created_at) prev_type
FROM `githubarchive.day.20190313`
WHERE actor.login IN ('00aquir', '0123hoang')
LIMIT 100
Rownum Status
1 2
2 1
3 3
4 2
5 3
6 1
The condition is to query records appear before the first record of status=3 which in the above scenario the expected output will be rownum = 1 and 2.
In the case if there is no status=3 then show everything.
I'm not sure from where to start hence currently no findings
If you are using SQL Server 2012+, then you can use window version of SUM with an ORDER BY clause:
SELECT Rownum, Status
FROM (
SELECT Rownum, Status,
SUM(CASE WHEN Status = 3 THEN 1 ELSE 0 END)
OVER
(ORDER BY Rownum) AS s
FROM mytable) t
WHERE t.s = 0
Calculated field s is a running total of Status = 3 occurrences. The query returns all records before the first occurrence of a 3 value.
Demo here
Please see fiddle: http://sqlfiddle.com/#!6/e6768/2
I have data, like below:
DRIVER DROP
1 1
1 2
1 ReturnToBase
1 4
1 5
1 ReturnToBase
1 6
1 7
2 1
2 2
2 ReturnToBase
2 4
I am trying to group my data, so for each driver, each group of return to bases have a grouping number.
My output should look like this:
DRIVER DROP GROUP
1 1 1
1 2 1
1 ReturnToBase 1
1 4 2
1 5 2
1 ReturnToBase 2
1 6 3
1 7 3
1 ReturnToBase 3
2 1 1
2 2 1
2 ReturnToBase 1
2 4 2
I've tried getting this result with a combination of windowed functions but I've been miles off so far
Below is what I had so far, it isn't supposed to be functional I was trying to figure out how it could be done, if it's even possible.
SELECT
ROW_NUMBER() OVER (Partition BY Driver order by Driver Desc) rownum,
Count(1) OVER (Partition By Driver Order By Driver Desc) counter,
Count
DropNo,
Driver,
CASE DropNo
WHEN 'ReturnToBase' THEN 1 ELSE 0 END AS EnumerateRound
FROM
Rounds
You can use the following query:
SELECT id, DRIVER, DROPno,
1 + SUM(flag) OVER (PARTITION BY DRIVER ORDER BY id) -
CASE
WHEN DROPno = 'ReturnToBase' THEN 1
ELSE 0
END AS grp
FROM (
SELECT id, DRIVER, DROPno,
CASE
WHEN DROPno = 'ReturnToBase' THEN 1
ELSE 0
END AS flag
FROM rounds ) AS t
Demo here
This query uses windowed version of SUM with ORDER BY in the OVER clause to calculate a running total. This version of SUM is available from SQL Server 2012 onwards AFAIK.
Fiddling a bit with this running total value is all we need in order to get the correct GROUP value.
EDIT: (credit goes to #Conrad Frix)
Using CROSS APPLY instead of an in-line view can considerably simplify things:
SELECT id, DRIVER, DROPno,
1 + SUM(x.flag) OVER (PARTITION BY DRIVER ORDER BY id) - x.flag
FROM rounds
CROSS APPLY (SELECT CASE WHEN DROPno = 'ReturnToBase' THEN 1 ELSE 0 END) AS x(flag)
Demo here
Added a sequential ID column to your example for use in a recursive CTE:
with cte as (
select ID,DRIVER,DROPno,1 as GRP
FROM rounds
where ID = 1
union all
select a.ID
,a.DRIVER
,a.DROPno
,case when b.DROPno = 'ReturnToBase'
or b.DRIVER <> a.DRIVER then b.GRP + 1
else b.GRP end
from rounds a
inner join cte b
on a.ID = b.ID + 1
)
select * from cte
SQL Fiddle
Let's say there is a result set...I need to print it out like so:
ID Count
1 5
1 5
1 5
1 5
1 5
2 2
2 2
3 1
Thanks in advance.
Do you mean that your query:
SELECT ID, COUNT(*) AS "Count"
FROM tableX
GROUP BY ID ;
produces this:
ID Count
1 5
2 2
3 1
but you want this?:
ID Count
1 5
1 5
1 5
1 5
1 5
2 2
2 2
3 1
Then, this query will do:
SELECT grp.ID, grp."Count"
FROM
tableX AS t
JOIN
( SELECT ID, COUNT(*) AS "Count"
FROM tableX
GROUP BY ID
) AS grp
ON grp.ID = t.ID ;
It will work in almost all DBMS and in all versions of SQL-Server. For SQL-Server versions 2005 and newer (and also in Oracle and Postgres), the answer with the OVER clause looks more elegant and may be prefered. Test in your version which one is more efficient. I think that in 2012 version, queries with OVER clause are quite efficient.
You can use count() with OVER clause:
select a, count(*) over (partition by a) as [count]
from tableName ;
It's called window function. I recommend you study these.