SQL different aggregates in single query - sql

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

Related

SQL Why am I getting the invalid identifier error?

I am trying to use columns that I created in this query to create another column.
Let me first my messy query. The query looks like this:
SELECT tb.team, tb.player, tb.type, tb.date, ToChar(Current Date-1, 'DD-MON-YY') as yesterday,
CASE WHEN to_date(tb.date) = yesterday then 1 else 0 end dateindicator,
FROM (
COUNT DISTINCT(*)
FROM TABLE_A, dual
where dateindicator = 1
Group by tb.team
)
What I am trying to do here is:
creating a column with "Yesterday's date"
Using the "Yesterday" column to create another column called dateindicator indicating each row is yesterday's data or not.
then using that dateindicator, I want to count the distinct number of player for each team that has 1 of the dateindicator column.
But I am getting the "invalid identifier" error. I am new to this oracle SQL, and trying to learn here.
You cannot use an Alias in your Select statement.
see here: SQL: Alias Column Name for Use in CASE Statement
you need to use the full toChar(.. in the CASE WHEN.
Also:
Your WHERE-condition (Line 5) doesnt belong there.. it should be:
SELECT DISTINCT .>. FROM .>. WHERE. you have to specify the table first. then you can filter it with where.
If I follow your explanation correctly: for each team, you want to count the number of players whose date column is yesterday.
If so, you can just filter and aggregate:
select team, count(*) as cnt
from mytable
where mydate >= trunc(sysdate) - 1 and mydate < trunc(sysdate)
group by team
This assumes that the dates are stored in column mydate, that is of date datatype.
I am unsure what you mean by counting distinct players; presumably, a given player appears just once per team, so I used count(*). If you really need to, you can change that to count(distinct player).
Finally: if you want to allow teams where no player matches, you can move the filtering logic within the aggregate function:
select team,
sum(case when mydate >= trunc(sysdate) - 1 and mydate < trunc(sysdate) then 1 else 0 end) as cnt
from mytable
group by team

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 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.

How do I add the values of a column together dependant on another column

It's quite a hard one to explain but probably (hopefully) an easy one to solve so I'll just explain what it is I'm trying to achieve.
I have a table where multiple logs can be entered for a day each as a seperate row, I then have a decimal as another column, I'm trying to create a summary for each day which would be something like
01/01/1900 | | 5.5
When there's one entry for the 01/01/1900 with 2.5, one with 3 in the main table so adding the values together for the day?
My only issue is adding the dates together if the dates the same, I was thinking something like
Select distinct date and joining it with a table that gets the sum of the decimal column where date is... and that's where im not too sure?
Any help would be great! thanks
If your table is named logs with data like
log_date | value
1900-01-01 | 2.5
1900-01-01 | 3
then your query is
SELECT sum(value) FROM logs GROUP BY log_date
What you're looking for is probably a GROUP BY clause.
SELECT [ yourdatecol, ] sum(yourdecimalcol) FROM yourtable
[ WHERE yourdatecol = .. ]
GROUP BY [ get_ymd_from_date(yourdatecol) | yourdatecol ] ;
With such syntax you'll get sum of row sets, selected by the same datecol value. You may also want to approximate date ( e.g. taking only Y/M/D part from it ), if date contains H/M/ss and what you want is per-day sums. Optional parts I enclosed in square brackets.
SELECT log_date,sum(value) FROM logs GROUP BY log_date
CREATE VIEW Summary
AS
SELECT
DateValue,
SUM(DecimalValue) DayTotal
FROM
EventTable
GROUP BY
DateValue;
Then
SELECT
*
FROM
Summary
WHERE
DateValue = '1900-01-01'
Try this :
SELECT CONVERT(VARCHAR, DateColumn, 103) AS OutputDate, SUM(ValueColumn) AS TotalValue
FROM YourTable
GROUP BY CONVERT(VARCHAR, DateColumn, 103)
I'm presuming a DateTime is used, lets call it logdate. I'm also presuming the other one is a decimal, lets call it logdecimal.
Using SQL server 2008 you can do (the is a type called date which is without the time-part):
SELECT
CAST(logdate as date) as TheDay,
SUM(logdecimal) as TheSum
FROM logTable
GROUP BY CAST(logdatetime as date)
Using a SQL server without the type date, maybe something like:
SELECT
CONVERT(varchar(10), logdate, 101) as TheDay,
SUM(logdecimal) as TheSum
FROM logTable
GROUP BY CONVERT(varchar(10), logdate , 101)
Regards, Olle
Edit: This one will work if it is a DateTime (including time part) you want to group as a date (not including time part). Looks like this was not the case in this question.

How to get number of hits by time regardless of Date?

I am working on a sql view that should get the average number of hits by hour of the day, regardless of what day/date it is for traffic monitoring (12:00:00.000 - 12:59:59.999). Any ideas?
EDIT
Now I have the total, how do I get the average? SELECT AVG("FUNCTION BELOW") DOES NOT WORK
SELECT COUNT(*) AS total, DATEPART(hh, LogDate) AS HourOfDay
FROM dbo.Log
GROUP BY DATEPART(hh, LogDate)
Convert to DATEPART(hh,.....
Example SELECT DATEPART(hh,GETDATE())
Since you are on SQL Server 2008, you can use the time data type, just convert to time
example
SELECT CONVERT(TIME,GETDATE())
Then you can filter that also
Since I am not sure what your output is supposed to be like I am showing you both, but if all you need is to group by hour, then just do a datepart(hh.....
The query below may be good enough for you. It divides the count by the difference between todays date and the minimum date in the LogDate column.
SELECT DATEPART(hh,LogDate) as Hour
,CAST(COUNT(*)as decimal)/DATEDIFF(d,(SELECT MIN(LogDate) from log)
,CURRENT_TIMESTAMP) as AverageHits
, COUNT(*) as Count
FROM log
GROUP BY DATEPART(hh,LogDate)
ORDER by DATEPART(hh,LogDate) asc