Subquery sorted by another table - sql

This is a follow-up question to Get the following record in query.
But the task is a bit more complicated. I tried to modify the SQL query but I was not able to fulfill the task.
If we have two tables, one called Activity and has rows [ActivityCode and StartTime], and the another one called Students has rows [Name and ID]
for example:
Name-----ID-----ActivityCode-----StartTime<BR>
Tom------123------Lunch------------1200<BR>
Tom------123------MathClass--------1300<BR>
Tom------123------EnglishClass-----1500<BR>
Tom------123------EndOfSchool------1700<BR>
Mary-----369-----Lunch------------1200<BR>
Mary-----369-----ScienceClass-----1300<BR>
Mary-----369-----EnglishClass-----1600<BR>
Mary-----369-----EndOfSchool------1700<BR>
And now I want to make one SQL Query to display as follow:
Name-----ID------ActivityCode-----StartTime------EndTime<BR>
Tom------123--- Lunch------------1200-----------1300<BR>
Tom------123-----MathClass--------1300-----------1500<BR>
Tom------123-----EnglishClass-----1500-----------1700<BR>
Tom------123-----EndOfSchool------1700-----------1700<BR>
Mary-----369-----Lunch------------1200-----------1300<BR>
Mary-----369-----ScienceClass-----1300-----------1600<BR>
Mary-----369-----EnglishClass-----1600-----------1700<BR>
Mary-----369-----EndOfSchool------1700-----------1700<BR>
I follow the code, credits to Gustav:
SELECT
Activity.ActivityCode,
Activity.StartTime,
Nz((Select Top 1 StartTime
From Activity As T
Where T.StartTime > Activity.StartTime
Order By StartTime Asc),
[StartTime]) AS EndTime,
CDate(TimeSerial(Val([EndTime])\100,Val([EndTime]) Mod 100,0)-
TimeSerial(Val([StartTime])\100,Val([StartTime]) Mod 100,0)) AS Duration
FROM
Activity;
I tried to modify the part
Order By StartTime Asc
Because the whole query is sorted according to the Student ID which is from another table. But some message boxes popped up and I couldn't solve it. How can I modify it? thank you.

Consider this SQL:
SELECT Students.ID, [Name], ActivityCode, StartTime,
Nz((Select Top 1 StartTime FROM Activity As T
WHERE T.StartTime > Activity.StartTime AND T.ID=Activity.ID
ORDER BY StartTime Asc),Startime) AS EndTime,
DateDiff("h",TimeSerial(StartTime/100,0,0),TimeSerial(EndTime/100,0,0)) AS Duration
FROM Students INNER JOIN Activity ON Students.ID=Activity.ID;

Related

Get the following record in query

If we have a table called Activity and has rows[ActivityCode and StartTime]
for example
ActivityCode-----StartTime<BR>
Lunch------------1200<BR>
MathClass--------1300<BR>
EnglishClass-----1500<BR>
EndOfSchool------1700<BR>
And now I want to make one SQL Query to display as follow:
ActivityCode-----StartTime-----EndTime<BR>
Lunch------------1200----------1300<BR>
MathClass--------1300----------1500<BR>
EnglishClass-----1500----------1700<BR>
EndOfSchool------1700----------1700<BR>
I am not sure how to do it. I tried to follow How to get a value from previous result row of a SELECT statement?. But it didn't work as I expected. Any help is appreciated.
You can use this query:
SELECT
Activity.ActivityCode,
Activity.StartTime,
Nz((Select Top 1 StartTime
From Activity As T
Where T.StartTime > Activity.StartTime
Order By StartTime Asc),
[StartTime]) AS EndTime,
CDate(TimeSerial(Val([EndTime])\100,Val([EndTime]) Mod 100,0)-
TimeSerial(Val([StartTime])\100,Val([StartTime]) Mod 100,0)) AS Duration
FROM
Activity;
Output:
I would use a subquery with aggregation:
select a.*,
(select nz(min(a2.starttime), a.endtime)
from activity as a2
where a2.starttime > a.starttime
) as endtime
from activity as a;
Normally in such an example, there would be an additional column identifying a "grouping" of some sort -- such as a person. If you have such a column, you would have an equality condition in the subquery as well as the inequality on time.
Also, there are much better ways to do this in almost any other database -- notably, the lead() function.

SQL different aggregates in single query

I am trying to work out a query where I have a table representing the following:
and I need the result to indicate the earliest start time (blue), the latest end time (green), and the sum of the lunch breaks (yellow):
I got the blue and green blocks right, but are struggling with the yellow aggregation.
My (partial) query looks like:
select
Name,
min(StartTime) StartTime,
max(EndTime) EndTime,
sum( <please help here with alternative to this aggregation> ) Lunch
from
SomeTable
group by
Name
When I use a normal subquery, SQL complains that the column is not contained in either a "group by" or aggregate, and I cannot use a subquery inside an aggregate.
Please point me into a direction for the "lunch" column.
This is on SQL Server.
Assuming the value is a time, then the sum is a little challenging. I would suggest converting to minutes:
select Name, min(StartTime) as StartTime, max(EndTime) as EndTime,
sum(case when activity = 'lunch'
then datediff(minute, 0, duration)
end) as lunch_minutes
from SomeTable
group by Name
would suggest you to use case when like this:
sum(case when activity = 'lunch' then duration end) as break

SQL Aggregation with only one table

So this problem has been bugging me a little for the last week or so. I'm working with a database which hasn't exactly been designed in a way that I like and I'm having to do a lot of work-arounds to get the queries to function in a way I would like.
Essentially, I'm trying to remove duplicate entries that occur as a result of an instance caused by a previous entry. For the sake of argument say that a customer places an order or issues a job (this only occurs once) but as a result of the interactions a series of other rows are created to represent, sub-orders or jobs. Essentially, all duplicate records should have the same finish time so what I'm trying to create is a query which will return the record which has the earliest start time and ignore all other records which have the same finish time. All this occurs within the same table.
Something like:
select starttime
, endtime
, description
, entrynumber
from table
where starttime = min
and endtime = endtime
Probably what you want is something like this:
;WITH OrderedTable AS
(
Select ROW_NUMBER() OVER (PARTITION BY endtime ORDER BY starttime) as rn, starttime, endtime, description, entrynumber
From Table
)
Select starttime, endtime, description, entrynumber
FROM OrderedTable
WHERE rn=1
What this does is group all the rows with the same end time, ordered by start time and give them an additional "row number" column starting at 1 and increasing. If you filter by rn = 1, you get only the earliest start time rows, ignoring the rest.

COUNT of rows satisfying a condition (resets at rows with specific conditions)

I have a question about writing query in sql (in continue of my previous question: subtract values of two rows and inserting it into a new column (not subsequent rows)):
I want to write a query that calculate the number of times that a user had won a competition before the current time, the condition of winning is place=1 ; I want the result in a new column (win-frequency) and the value of [win-frequency] changes when a new winning happens. in the following picture, I calculated win-frequency manually.
http://www.8pic.ir/images/54691148512772358477.jpg
I write the following query, but I got error:
SELECT [user-name],
submissions,
[date],
place,
recency,
[win-recency],
COUNT( SELECT [date] FROM [top-design1]] td1
WHERE td1.[user-name] = [top-design1].[user-name]
AND place=1
AND [date]< [top-design1].[date]
ORDER BY [date] DESC) as win-frequency
)
FROM [top-design1]
this is the sql fiddle:
http://sqlfiddle.com/#!3/0ec5f
You have to fix the brackets ) and [, remove the ORDER BY from the correlated subquery, and escape the column name [win-frequency]. It should be this way:
SELECT [user-name],
submissions,
[date],
place,
recency,
[win-recency],
(SELECT COUNT([date])
FROM [top-design1] td1
WHERE td1.[user-name] = [top-design1].[user-name]
AND place = 1
AND [date] < [top-design1].[date]
) as [win-frequency]
FROM [top-design1];
Updated SQL Fiddle Demo.

Latest date and time in SQL without ORDER BY

I'm trying to find a way to display the last event held (last date and time) in an events table whilst displaying all the columns for that event without using ORDER BY.
For example:
SELECT * from Events
where dateheld in (select max(dateheld) from events)
AND starttime in (select max(starttime) from events)
When I put MAX starttime, it displays nothing. When I put MIN starttime it works but displays the earliest time of that date and not the latest.
I guess you could print out your records, throw them down the stairs, and the ones that go farthest have the "lightest" dates. You cannot sort without order by. It's like wanting water that isn't wet. Unless your data naturally comes out in the order you want, you MUST sort.
Of course, if you want only the record that has the absolute most recent date, and don't need more than just that one record, then
SELECT yourdatetimefield, ...
FROM yourtable
HAVING yourdatetimefield = MAX(yourdatetimefield)
If you are only looking for the latest item:
EDIT gets a little more complicated when you have seperate date and time fields, but this should work. This is a ridiculous kludge for a situation where date and time should be stored in one field.
SELECT *
FROM (
SELECT *
FROM Events
WHERE dateTime = (SELECT MAX(dateheld) FROM Events)
) temp
WHERE starttime = (SELECT MAX(starttime) FROM (
SELECT *
FROM Events
WHERE dateTime = (SELECT MAX(dateheld) FROM Events)
) temp 2 )