My query
SELECT TOP 1 *, COUNT(*) AS totalRun
FROM history
ORDER BY starttime DESC`
Estimated outcome is all the data from 1 row in the history table with the latest starttime and a fieldtotalrun with the total amount of records, but... I get the following error.
Msg 8120, Level 16, State 1, Line 1
Column 'history.id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
What am I doing wrong?
EDIT
example of the result:
These are all the fields of the row with the latest starttime in the history table with the extra COUNT field 'totalRun'
Aggregates can only be expressed in two cases.
Where you have a GROUP BY statement
Where you use the OVER clause
The following will give you the most recent start time and the number of rows in your source table that share that start time...
SELECT
starttime,
COUNT(*) AS row_count
FROM
history
GROUP BY
starttime
ORDER BY
starttime DESC
In this structure the only fields you can select are the ones in the GROUP BY statement (and you can have several), or aggregates *(such as SUM(), COUNT(), etc).
If, however, you want the COUNT(*) to be done over the whole table, and not just the rows grouped together, you can use the OVER clause in the SELECT statement.
SELECT
*,
COUNT(*) OVER (PARTITION BY 1) AS row_count
FROM
history
ORDER BY
starttime DESC
Because this doesn't use a GROUP BY, you can then also select * rather than just teh fields you are grouping by.
If you need something different, please could you include some example data and the results you would desire?
You either aggregate or group by a column. You have columns that are neither
SELECT TOP 1
starttime, COUNT(*) AS totalRun
FROM history
GROUP BY starttime, foo
ORDER BY starttime DESC;
If you need a column foo, then add it as follows
SELECT TOP 1
starttime, foo, COUNT(*) AS totalRun
FROM history
GROUP BY starttime, foo
ORDER BY starttime DESC, foo;
I could not unerstand the requirement properly. Why you are using top 1 with count(*)
and without the group by clause.
If you want the result TotalRuns earned on last date then you can use this query
SELECT TOP 1 starttime, COUNT(1) AS totalRun
FROM history Group by starttime ORDER BY starttime DESC
If this is the requirement:
Estimated outcome is all the data from 1 row in the history table with the latest starttime and a fieldtotalrun with the total amount of records,
select top 1 *
from
(Select *
from history
where starttime= (select max(starttime) from history) )i
full outer join
(select count(1) count , max(starttime) sttime as fieldtotalrun
from history ) j on i.starttime=j.sttime
Related
I have table as below:
I want write a sql query to get output as below:
the query should select all the records from the table but, when multiple records have same Id column value then it should take only one record having latest Date.
E.g., Here Rudolf id 1211 is present three times in input---in output only one Rudolf record having date 06-12-2010 is selected. same thing with James.
I tried to write a query but it was not succssful. So, please help me to form a query string in sql.
Thanks in advance
You can partition your data over Date Desc and get the first row of each partition
SELECT A.Id, A.Name, A.Place, A.Date FROM (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Date DESC) AS rn
FROM [Table]
) A WHERE A.rn = 1
you can use WITH TIES
select top 1 PERCENT WITH TIES * from t
order by (row_number() over(partition by id order by date desc))
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=280b7412b5c0c04c208f2914b44c7ce3
As i can see from your example, duplicate rows differ only in Date. If it's a case, then simple GROUP BY with MAX aggregate function will do the job for you.
SELECT Id, Name, Place, MAX(Date)
FROM [TABLE_NAME]
GROUP BY Id, Name, Place
Here is working example: http://sqlfiddle.com/#!18/7025e/2
In the following sql fiddle, how would I change the view to get the desired output?
http://sqlfiddle.com/#!6/a737a/1
VIEW
select
sum(dollars) as totalDollars,
sum(dollars)/count(id) as factor,
count(id) as numberOfEvents,
id as eventID,
event_date
from
events
group by
id,
event_date
Query
select
*
from eventStats
where
event_date between '1/1/2015' and '1/16/2015'
desired output
The numberOfevents should = 2 (the actual number of events, not the number of records for each event, determined by the where clause in the query) to properly do the math in the view.
You can count distinct fk_id without the group by clause:
select count(distinct fk_id) as number_of_IDs
from [myTable]
where [someCondition]
Use distinct keyword in count function:
select
count(distinct fk_id) as number_of_IDs
,id
from
myTable
where
someCondition
group by
id
The below statement retrieves the top 2 records within each group in SQL Server. It works correctly, however as you can see it doesn't scale at all. I mean that if I wanted to retrieve the top 5 or 10 records instead of just 2, you can see how this query statement would grow very quickly.
How can I convert this query into something that returns the same records, but that I can quickly change it to return the top 5 or 10 records within each group instead, rather than just 2? (i.e. I want to just tell it to return the top 5 within each group, rather than having 5 unions as the below format would require)
Thanks!
WITH tSub
as (SELECT CustomerID,
TransactionTypeID,
Max(EventDate) as EventDate,
Max(TransactionID) as TransactionID
FROM Transactions
WHERE ParentTransactionID is NULL
Group By CustomerID,
TransactionTypeID)
SELECT *
from tSub
UNION
SELECT t.CustomerID,
t.TransactionTypeID,
Max(t.EventDate) as EventDate,
Max(t.TransactionID) as TransactionID
FROM Transactions t
WHERE t.TransactionID NOT IN (SELECT tSub.TransactionID
FROM tSub)
and ParentTransactionID is NULL
Group By CustomerID,
TransactionTypeID
Use Partition by to solve this type problem
select values from
(select values ROW_NUMBER() over (PARTITION by <GroupColumn> order by <OrderColumn>)
as rownum from YourTable) ut where ut.rownum<=5
This will partitioned the result on the column you wanted order by EventDate Column then then select those entry having rownum<=5. Now you can change this value 5 to get the top n recent entry of each group.
I have the following query
select * from
(
SELECT distinct
rx.patid
,rx.fillDate
,rx.scriptEndDate
,MAX(datediff(day, rx.filldate, rx.scriptenddate)) AS longestScript
,rx.drugClass
,COUNT(rx.drugName) over(partition by rx.patid,rx.fillDate,rx.drugclass) as distinctFamilies
FROM [I 3 SCI control].dbo.rx
where rx.drugClass in ('h3a','h6h','h4b','h2f','h2s','j7c','h2e')
GROUP BY rx.patid, rx.fillDate, rx.scriptEndDate,rx.drugName,rx.drugClass
) r
order by distinctFamilies desc
which produces results that look like
This should mean that between the two dates in the table the patID that there should be 5 unique drug names. However, when I run the following query:
select distinct *
from rx
where patid = 1358801781 and fillDate between '2008-10-17' and '2008-11-16' and drugClass='H4B'
I have a result set returned that looks like
You can see that while there are in fact five rows returned for the second query between the dates of 2008-10-17 and 2009-01-15, there are only three unique names. I've tried various ways of modifying the over clause, all with different levels of non-success. How can I alter my query so that I only find unique drugNames within the timeframe specified for each row?
Taking a shot at it:
SELECT DISTINCT
patid,
fillDate,
scriptEndDate,
MAX(DATEDIFF(day, fillDate, scriptEndDate)) AS longestScript,
drugClass,
MAX(rn) OVER(PARTITION BY patid, fillDate, drugClass) as distinctFamilies
FROM (
SELECT patid, fillDate, scriptEndDate, drugClass,rx.drugName,
DENSE_RANK() OVER(PARTITION BY patid, fillDate, drugClass ORDER BY drugName) as rn
FROM [I 3 SCI control].dbo.rx
WHERE drugClass IN ('h3a','h6h','h4b','h2f','h2s','j7c','h2e')
)x
GROUP BY x.patid, x.fillDate, x.scriptEndDate,x.drugName,x.drugClass,x.rn
ORDER BY distinctFamilies DESC
Not sure if DISTINCT is really necessary - left it in since you've used it.
This query gets the desired rows -grouped by subject- and I also want to know the items count in each group.
SELECT log.* FROM [hm_deliverylog] AS log
WHERE log.deliveryid IN
(
SELECT MAX([deliveryid]) FROM [hm_deliverylog]
WHERE [deliverytime] > DATEADD(HOUR, -12, GETDATE())
GROUP BY deliverysubject
)
ORDER BY deliveryid DESC
How can I count the groups? Like below?
SELECT joined.groupcount, log.* FROM [hm_deliverylog] AS log
P.S: Imagine the Gmail inbox; it displays the newest message and shows the message count. I want to group the messages with same subject and count them...
One way is to put the COUNT() calculation in the subquery and instead of using IN, make that a derived table to be joined:
SELECT log.*
, grp.cnt AS groupcount
FROM
[hm_deliverylog] AS log
JOIN
(
SELECT MAX([deliveryid]) AS deliveryid
, COUNT(*) AS cnt
FROM [hm_deliverylog]
WHERE [deliverytime] > DATEADD(HOUR, -12, GETDATE())
GROUP BY deliverysubject
) AS grp
ON grp.deliveryid = log.deliveryid
ORDER BY
log.deliveryid DESC ;
You can use OVER clause:
SELECT COUNT(deliveryid) OVER (PARTITION BY deliverysubject) As GroupCount
Determines the partitioning and ordering of a rowset before the
associated window function is applied. That is, the OVER clause
defines a window or user-specified set of rows within a query result
set. A window function then computes a value for each row in the
window. You can use the OVER clause with functions to compute
aggregated values such as moving averages, cumulative aggregates,
running totals, or a top N per group results.
SELECT log.*, COUNT(*) OVER (PARTITION BY deliverysubject) AS groupcount
FROM [hm_deliverylog] AS log
GROUP BY deliverysubject