I am trying to create a query in SQL Server but having some difficulties. I will try to supply some sample data so it is easier. There are multiple tables I am trying to pull from:
Units:
UnitID
------
101
102
103
104
etc..
Jobs:
JobID
------
1
2
etc.
Job Units:
UnitID | JobID | DispatchDate
-----------------------------
102 | 12 | Dec 12 2015
104 | 14 | Dec 12 2015
102 | 18 | Dec 12 2015
108 | 18 | Dec 12 2015
102 | 11 | Dec 12 2015
104 | 10 | Dec 12 2015
What I would like for a desired outcome would reflect this data set:
UnitID | Job 1 | Job 2 | Job 3
------------------------------
102 | 12 | 18 | 11
103 | | |
104 | 14 | 10 |
105 | | |
106 | | |
107 | | |
108 | 18 | |
So basically, I want to display the job the Unit has been out to up to three jobs, but I still need to show the other units that haven't gone out, or only have gone out once or twice.
I currently am exporting this data set out to three separate listviews and using three separate stored procedures, but this isn't getting the job done and is a mess, so I won't even bother posting my code, but if needed I can.
Any help is greatly appreciated. Thanks!
Edit: As per request of /u/Pasty, here is the code I am working on:
select UnitID, case when (select COUNT(JobID)
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 12 2015') >= 1
then (select top 1 JobID
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 12 2015'
order by JobID asc )
else null
end as 'Job 1', case when (select COUNT(JobID)
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 12 2015') >= 2
then (select top 1 JobID
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 12 2015'
order by JobID desc )
else null
end as 'Job 2', case when (select COUNT(JobID)
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 12 2015') >= 3
then (select top 1 JobID
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 12 2015'
order by JobID asc )
else null
end as 'Job 3'
from Units U
order by UnitID asc
You need to use LEFT JOIN in order to achieve the desired result. If you have table A and B and want to display matches in B and all items from A, LEFT JOIN allow's you to do that. A good visual explanation of SQL JOINS can be found here - A Visual Explanation of SQL Joins.
How can you create the desired output in your case (I am assuming the tables are named Job, Unit ans Unit_has_Job):
Unit | UnitId
-----------
101
102
103
104
105
107
Job | JobId
--------------
1
2
3
4
5
Unit_has_JobId | UnitId | JobId
----------------------------------
101 | 1
101 | 3
101 | 4
102 | 4
105 | 3
select u.UnitId, ISNULL(j.JobId, 0) as [JobId] from unit as u
left join unit_has_job as uhj on u.UnitId = uhj.UnitId
left join job as j on uhj.JobId = j.JobId
The result is:
UnitId | JobId
101 | 1
101 | 3
101 | 4
102 | 4
103 | 0
104 | 0
105 | 3
107 | 0
I have created an example in SQL-Fiddle.
With the ISNULL function you mark the empty slots. The different JobId for every UnitId is equivalent to the columns in your desired output.
Using LINQ2SQL and the GroupBy method you can easily group the jobs per unit from the result and iterate over them:
var jobsPerUnit = result.GroupBy (r => r.UnitId);
foreach (var jobs in jobsPerUnit)
{
Console.WriteLine("Unit: " + jobs.Key);
foreach (var job in jobs)
{
if (job.JobId > 0)
{
Console.WriteLine("Job: " + job.JobId);
}
}
Console.WriteLine("=================");
}
The output:
Unit: 101
Job: 1
Job: 3
Job: 4
=================
Unit: 102
Job: 4
=================
Unit: 103
=================
Unit: 104
=================
Unit: 105
Job: 3
=================
Unit: 107
=================
Columns in SQL are the result of a selection/projection, which can't be created so easily dynamically. One possible solution is to use dynamic SQL in order to create a temp table, fill it and then select from this temp table, but the overhead is probably not worth it. You still need a cursor for this solution.
If you want to do everything on the SQL-side, then one possible solution would be to iterate with a cursor over the result and group by UnitId.
I was just playing around and this is what I came up with:
SQLFiddle
IF OBJECT_ID(N'dbo.UNITS', 'U') IS NOT NULL
DROP TABLE dbo.UNITS
GO
CREATE TABLE UNITS(ID INT IDENTITY(1, 1), UnitID INT, JobID INT, DispatchDate DATETIME)
GO
INSERT INTO UNITS
VALUES(102, 12, 'Dec 12 2015')
,(104, 14, 'Dec 12 2015')
,(102, 18, 'Dec 12 2015')
,(108, 18, 'Dec 12 2015')
,(102, 11, 'Dec 12 2015')
,(104, 10, 'Dec 12 2015')
,(103, NULL, NULL)
,(105, NULL, NULL)
,(106, NULL, NULL)
,(107, NULL, NULL)
GO
SELECT
UnitId
,Job_1 = JobIDs.value('/JobID[1]','INT')
,Job_2 = JobIDs.value('/JobID[2]','INT')
,Job_3 = JobIDs.value('/JobID[3]','INT')
FROM
(
SELECT
UnitID
,JobIDs = CONVERT(XML,'<JobID>'
+ REPLACE(Units.JobIDs, '|', '</JobID><JobID>')
+ '</JobID>')
FROM
(
SELECT DISTINCT
U.UnitId
,JobIDs = STUFF((
SELECT
'|' + CAST(UU.JobID AS NVARCHAR(25))
FROM
UNITS UU
WHERE
UU.UnitID = U.UnitID
ORDER BY
UU.ID, UU.JobID
FOR XML PATH (''), type).value('.', 'nvarchar(max)'), 1, 1, '')
FROM
UNITS U
GROUP BY
U.UnitID) Units) UJ
There is an easier way to get to the same result, where you don't need to run inner selects all the time. This yields a much simpler execution plan and faster execution if you put on the proper indexes.
Note that there is a LEFT JOIN in the inner query (LEFT JOIN JobUnits ju), that will produce an row for each row in Units, regardless if it has related JobUnit.
select UnitID,
SUM(CASE WHEN cnt=1 THEN JobID ELSE 0 END) AS Job1,
SUM(CASE WHEN cnt=2 THEN JobID ELSE 0 END) AS Job2,
SUM(CASE WHEN cnt=3 THEN JobID ELSE 0 END) AS Job3,
SUM(CASE WHEN cnt=4 THEN JobID ELSE 0 END) AS Job4,
SUM(CASE WHEN cnt=5 THEN JobID ELSE 0 END) AS Job5
FROM (
select ju.UnitID, ju.JobID, count(1) as cnt
FROM Units u
LEFT JOIN JobUnits ju on (u.UnitID = ju.UnitID)
LEFT JOIN JobUnits ju2 on (ju.UnitID = ju2.UnitID AND ju.UnitID <= ju2.UnitID)
)
GROUP BY UnitID
The only disadvantage of this SELECT that it will not preserve the order (12, 18, 11 in case of 102), instead it orders it ascending way (11, 12, 18) - I don't know if it is an advantage or disadvantage in your business case.
You can preserve the order if you compare the ROWNUMs, but that requires two more subselects, and I'm not sure if it worth or not.
I ended up solving this scenario with quite a mess of code, but it works and I'm tired, so I am just going to go with it.
select UnitID, case when (select COUNT(JobID)
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 4 2015') >= 1
then (select top 1 JobID
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 4 2015'
order by JobID asc )
else null
end as 'Job 1', case when (select COUNT(JobID)
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 4 2015') >= 1
then (select Customer
from Customers C
full
where CustomerID=())
else null
end as 'Customer 1',
case when (select COUNT(JobID)
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 4 2015') >= 2
then
(SELECT TOP 1 JobID
FROM
(
SELECT TOP 2 JobID
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 4 2015'
ORDER BY JobID desc
) sub
ORDER BY JobID asc)
else null
end as 'Job 2',
case when (select COUNT(JobID)
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 4 2015') >= 3
then
(SELECT TOP 1 JobID
FROM
(
SELECT TOP 3 JobID
from JobUnits
where UnitID=U.UnitID
and DispatchDate='Dec 4 2015'
ORDER BY JobID desc
) sub
ORDER BY JobID desc)
else null
end as 'Job 3'
from Units U
order by UnitID asc
Related
I am new in SQL lite, I have a datetime column in this format:
id
datetime
1
2020-12-26 19:08:49
2
2020-12-26 19:08:50
3
2020-12-26 19:08:51
4
2020-12-26 19:08:51
5
2020-12-26 19:09:07
6
2020-12-26 19:11:45
7
2020-12-26 19:52:49
8
2020-12-26 19:52:50
How can i compute the difference between the first element with the 2nd
the 3rd with 4th element ??
Use window function FIRST_VALUE() to get the datetime of the the 1st row and with the function strftime() you can calculate the difference of each row:
SELECT *
FROM (
SELECT id,
strftime('%s', datetime) - strftime('%s', FIRST_VALUE(datetime) OVER (ORDER BY id)) AS diff_in_secs
FROM tablename
)
WHERE id > 1
Or with a self join:
SELECT t.id,
strftime('%s', t.datetime) - strftime('%s', m.datetime)
FROM tablename t
INNER JOIN (SELECT * FROM tablename ORDER BY id LIMIT 1) m
ON m.id < t.id
I used id and datetime for the column names and tablename for the table's name, you can change them to the actual ones.
See the demo.
Results:
> id | diff_in_secs
> -: | -----------:
> 2 | 1
> 3 | 2
> 4 | 2
> 5 | 18
> 6 | 176
> 7 | 2640
> 8 | 2641
I am trying to create a stored proc in SQL Server 2008.
I have a "Timings" Table (which could have thousands of records):
StaffID | MachineID | StartTime | FinishTime
1 | 1 | 01/01/2018 12:00 | 01/01/18 14:30
2 | 1 | 01/01/2018 12:00 | 01/01/18 13:00
3 | 2 | 01/01/2018 12:00 | 01/01/18 13:00
3 | 2 | 01/01/2018 13:00 | 01/01/18 14:00
4 | 3 | 01/01/2018 12:00 | 01/01/18 12:30
5 | 3 | 01/01/2018 11:00 | 01/01/18 13:30
This shows how long each staff member was working on each machine.
I would like to produce a results table as below:
MachineID | StaffQty | TotalMins
1 | 1 | 90
1 | 2 | 60
2 | 1 | 120
3 | 1 | 120
3 | 2 | 30
This would show how many minutes each machine had only one person using it, how many minutes each machine had 2 people using it etc.
Normally, I would post what I have tried so far, but all my attempts seem to be so far away, I don't think there is much point.
Obviously, I would be very grateful of a complete solution but I would also appreciate even just a little nudge in the right direction.
I think this answers your question:
declare #t table (StaffID int, MachineID int, StartTime datetime2,FinishTime datetime2)
insert into #t(StaffID,MachineID,StartTime,FinishTime) values
(1,1,'2018-01-01T12:00:00','2018-01-01T14:30:00'),
(2,1,'2018-01-01T12:00:00','2018-01-01T13:00:00'),
(3,2,'2018-01-01T12:00:00','2018-01-01T12:30:00')
;With Times as (
select MachineID,StartTime as Time from #t
union
select MachineID,FinishTime from #t
), Ordered as (
select
*,
ROW_NUMBER() OVER (PARTITION BY MachineID ORDER BY Time) rn
from Times
), Periods as (
select
o1.MachineID,o1.Time as StartTime,o2.Time as FinishTime
from
Ordered o1
inner join
Ordered o2
on
o1.MachineID = o2.MachineID and
o1.rn = o2.rn - 1
)
select
p.MachineID,
p.StartTime,
MAX(p.FinishTime) as FinishTime,
COUNT(*) as Cnt,
DATEDIFF(minute,p.StartTime,MAX(p.FinishTime)) as TotalMinutes
from
#t t
inner join
Periods p
on
p.MachineID = t.MachineID and
p.StartTime < t.FinishTime and
t.StartTime < p.FinishTime
group by p.MachineID,p.StartTime
Results:
MachineID StartTime FinishTime Cnt TotalMinutes
----------- --------------------------- --------------------------- ----------- ------------
1 2018-01-01 12:00:00.0000000 2018-01-01 13:00:00.0000000 2 60
1 2018-01-01 13:00:00.0000000 2018-01-01 14:30:00.0000000 1 90
2 2018-01-01 12:00:00.0000000 2018-01-01 12:30:00.0000000 1 30
Hopefully you can see what each of the CTEs is doing. The only place where this may not give you exactly the results you're seeking is if one person's FinishTime is precisely equal to another person's StartTime on the same machine. Should be rare in real data hopefully.
For Sql server 2012+,
Please mention your Sql server version.
Try my script with other sample data.
Please post other sample data if it is not working.
I think my script can be fix for other Test scenario.
create table #temp(StaffID int,MachineID int,StartTime datetime,FinishTime datetime)
insert into #temp VALUES
(1, 1,'01/01/2018 12:00','01/01/18 14:30')
,(2, 1,'01/01/2018 12:00','01/01/18 13:00')
,(3, 2,'01/01/2018 12:00','01/01/18 12:30')
;
WITH CTE
AS (
SELECT t.*
,t1.StaffQty
,datediff(MINUTE, t.StartTime, t.FinishTime) TotalMinutes
FROM #temp t
CROSS APPLY (
SELECT count(*) StaffQty
FROM #temp t1
WHERE t.machineid = t1.machineid
AND (
t.StartTime >= t1.StartTime
AND t.FinishTime <= t1.FinishTime
)
) t1
)
SELECT MachineID
,StaffQty
,TotalMinutes - isnull(LAG(TotalMinutes, 1) OVER (
PARTITION BY t.MachineID ORDER BY t.StartTime
,t.FinishTime
), 0)
FROM cte t
drop table #temp
for Sql server 2008,
;
WITH CTE
AS (
SELECT t.*
,t1.StaffQty
,datediff(MINUTE, t.StartTime, t.FinishTime) TotalMinutes
,ROW_NUMBER() OVER (
PARTITION BY t.machineid ORDER BY t.StartTime
,t.FinishTime
) rn
FROM #temp t
CROSS APPLY (
SELECT count(*) StaffQty
FROM #temp t1
WHERE t.machineid = t1.machineid
AND (
t.StartTime >= t1.StartTime
AND t.FinishTime <= t1.FinishTime
)
) t1
)
SELECT t.MachineID
,t.StaffQty
,t.TotalMinutes - isnull(t1.TotalMinutes, 0) TotalMinutes
FROM cte t
OUTER APPLY (
SELECT TOP 1 TotalMinutes
FROM cte t1
WHERE t.MachineID = t1.machineid
AND t1.rn < t.rn
ORDER BY t1.rn DESC
) t1
I know similar questions have been asked before, however the grouping is throwing me off and hopefully I can get some help. I currently have a working MS Access model that does custom calculations to an Oracle connection, however my data is now pushing the 2GB mark with the custom calculations and trying SQL Server Express as an alternative and need a bit of help.
The database structure is from a 3rd party application so have to live with what I have - its UGLY.
ID | ATRSTUDY | ENDTIME | NAME | COUNT
---+----------+--------------------+-------------+-------
1 | A | Jan 1, 18 00:15 | NorthBound | 10
2 | A | Jan 1, 18 00:15 | SouthBound | 20
3 | A | Jan 1, 18 00:15 | Both Dir | 30
4 | B | Jan 1, 18 00:15 | EastBound | 30
5 | B | Jan 1, 18 00:15 | WestBound | 40
5 | B | Jan 1, 18 00:15 | Both Dir | 70
My existing MS-Access SQL is:
TRANSFORM Sum(CountData_Local.Count) AS SumOfCount
SELECT CountData_Local.ATRSTUDY, DateValue([CountData_Local]![ENDTIME]) AS CNTDATE, CountData_Local.ENDTIME
FROM DataVariables, CountData_Local
GROUP BY CountData_Local.ATRSTUDY, DateValue([CountData_Local]![ENDTIME]), CountData_Local.ENDTIME
PIVOT IIf([NAME]="EastBound" Or [NAME]="NorthBound" Or [NAME]="First Direction","C1",IIf([NAME]="WestBound" Or [NAME]="SouthBound" Or [NAME]="Second Direction","C2",IIf([NAME]="Both Dir","TC")));
The end result I am try to achieve is a pivot table that combines the 3 rows into one row as follows:
ATRSTUDY | CNDDATE | ENDTIME | C1 | C2 | TC
---------+-----------+---------+----+----+---
A | Jan 1, 18 | 00:15 |10 | 20 | 30
B | Jan 1, 18 | 00:15 |30 | 40 | 70
Thanks in advance!
Here is my SQL to date. Still having a bit of trouble with showing date and time and adding a filter for a date range which I currently have filtered out.
Perfect situation, date would be a between A and B.
Select atrstudy, endtime, sum(c1), sum(c2), sum(tc) from
(
with t as
(
select
sdata.oid,
sdata.atrstudy,
case upper(datatyp.name)
when 'EASTBOUND' then 'C1'
when 'NORTHBOUND' then 'C1'
when 'FIRST DIRECTION' then 'C1'
when 'WESTBOUND' then 'C2'
when 'SOUTHBOUND' then 'C2'
when 'SECOND DIRECTION' then 'C2'
when 'BOTH DIRECTIONS' then 'TC'
else datatyp.name
end as namedir,
/* trunc(datadtlbs.starttime) as starttime, */
endtime as endtime,
datadtlbs.count as counttot,
sdata.gcrecord
from roy.atrstudydata sdata
left outer join roy.atrstudydatadtl datadtl
on sdata.oid = datadtl.parent
join roy.atrstudydattyp datatyp
on sdata.direction = datatyp.oid
left outer join roy.atrstudydatadtlbs datadtlbs
on datadtl.oid = datadtlbs.oid
/* where trunc(datadtlbs.endtime) > '31-DEC-15' can remove this where clause*/)
select atrstudy, endtime, C1, C2, TC from t
pivot
(sum(COUNTtot) for NAMEdir in ('C1' as C1, 'C2' as C2, 'TC' as TC)))
group by atrstudy, endtime
order by atrstudy, endtime
MS SQL Server has PIVOT to do such things.
And CASE can be used to group those names as codes.
Example snippet:
--
-- Using a table variable for easy testing in the example
--
declare #Count_data table (id int identity(1,1) primary key, ATRSTUDY varchar(1), ENDTIME datetime, NAME varchar(30), [COUNT] int);
insert into #Count_data (ATRSTUDY, ENDTIME, NAME, [COUNT]) values
('A','2018-01-01T18:00:15','NorthBound',10),
('A','2018-01-01T18:00:15','SouthBound',20),
('A','2018-01-01T18:00:15','Both Directions',30),
('B','2018-01-01T18:00:15','EastBound',30),
('B','2018-01-01T18:00:15','WestBound',40),
('B','2018-01-01T18:00:15','Both Directions',70);
select ATRSTUDY, ENDDATE, ENDTIME, [C1], [C2], [TC]
from (
select
d.ATRSTUDY,
cast(d.ENDTIME as date) as ENDDATE,
left(cast(d.ENDTIME as time),5) as ENDTIME,
(case -- if the Name column has a Case-Insensitive collation then lower or upper case won't matter.
when d.Name in ('eastbound', 'northbound', 'first direction') then 'C1'
when d.Name in ('westbound', 'southbound', 'second direction') then 'C2'
when d.Name like 'both dir%' then 'TC'
else d.Name
end) as ColName,
d.[count]
From #Count_data d
) as q
pivot (
sum([count])
for ColName in ([C1], [C2], [TC])
) as pvt
order by ATRSTUDY, ENDDATE, ENDTIME;
Output:
ATRSTUDY ENDDATE ENDTIME C1 C2 TC
-------- ---------- ------- -- -- --
A 2018-01-01 18:00 10 20 30
B 2018-01-01 18:00 30 40 70
I have the following table in my database:
Month|Year | Value
1 |2013 | 100
4 |2013 | 101
8 |2013 | 102
2 |2014 | 103
4 |2014 | 104
How can I fill in "missing" rows from the data, so that if I query from 2013-03 through 2014-03, I would get:
Month|Year | Value
3 |2013 | 100
4 |2013 | 101
5 |2013 | 101
6 |2013 | 101
7 |2013 | 101
8 |2013 | 102
9 |2013 | 102
10 |2013 | 102
11 |2013 | 102
12 |2013 | 102
1 |2014 | 102
2 |2014 | 103
3 |2014 | 103
As you can see I want to repeat the previous Value for a missing row.
I have created a SQL Fiddle of this solution for you to play with.
Essentially it creates a Work Table #Months and then Cross joins this will all years in your data set. This produces a complete list of all months for all years. I then left join the Test data provided in your example (Table named TEST - see SQL fiddle for schema) back into this list to give me a complete list with Values for the months that have them. The next issue to overcome was using the last months values if this months didn't have any. For that, I used a correlated sub-query i.e. joined tblValues back on itself only where it matched the maximum Rank of a row which has a value. This then gives a complete result set!
If you want to filter by year\month you can add this into a WHERE clause just before the final Order By.
Enjoy!
Test Schema
CREATE TABLE TEST( Month tinyint, Year int, Value int)
INSERT INTO TEST(Month, Year, Value)
VALUES
(1,2013,100),
(4,2013,101),
(8,2013,102),
(2,2014,103),
(4,2014,104)
Query
DECLARE #Months Table(Month tinyint)
Insert into #Months(Month)Values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12);
With tblValues as (
select Rank() Over (ORDER BY y.Year, m.Month) as [Rank],
m.Month,
y.Year,
t.Value
from #Months m
CROSS JOIN ( Select Distinct Year from Test ) y
LEFT JOIN Test t on t.Month = m.Month and t.Year = y.Year
)
Select t.Month, t.Year, COALESCE(t.Value, t1.Value) as Value
from tblValues t
left join tblValues t1 on t1.Rank = (
Select Max(tmax.Rank)
From tblValues tmax
Where tmax.Rank < t.Rank AND tmax.Value is not null)
Order by t.Year, t.Month
Can anyone help me with query, I have table
vendorid, agreementid, sales
12001 1004 700
5291 1004 20576
7596 1004 1908
45 103 345
41 103 9087
what is the goal ?
when agreemtneid >1 then show me data when sales is the highest
vendorid agreementid sales
5291 1004 20576
41 103 9087
Any ideas ?
Thx
Well you could try using a CTE and ROW_NUMBER something like
;WITH Vals AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY AgreementID ORDER BY Sales DESC) RowID
FROM MyTable
WHERE AgreementID > 1
)
SELECT *
FROM Vals
WHERE RowID = 1
This will avoid you returning multiple records with the same sale.
If that was OK you could try something like
SELECT *
FROM MyTable mt INNER JOIN
(
SELECT AgreementID, MAX(Sales) MaxSales
FROM MyTable
WHERE AgreementID > 1
) MaxVals ON mt.AgreementID = MaxVals.AgreementID AND mt.Sales = MaxVals.MaxSales
SELECT TOP 1 WITH TIES *
FROM MyTable
ORDER BY DENSE_RANK() OVER(PARTITION BY agreementid ORDER BY SIGN (SIGN (agreementid - 2) + 1) * sales DESC)
Explanation
We break table MyTable into partitions by agreementid.
For each partition we construct a ranking or its rows.
If agreementid is greater than 1 ranking will be equal to ORDER BY sales DESC.
Otherwise ranking for every single row in partition will be the same: ORDER BY 0 DESC.
See how it looks like:
SELECT *
, SIGN (SIGN (agreementid - 2) + 1) * sales AS x
, DENSE_RANK() OVER(PARTITION BY agreementid ORDER BY SIGN (SIGN (agreementid - 2) + 1) * sales DESC) AS rnk
FROM MyTable
+----------+-------------+-------+-------+-----+
| vendorid | agreementid | sales | x | rnk |
+----------|-------------|-------+-------+-----+
| 0 | 0 | 3 | 0 | 1 |
| -1 | 0 | 7 | 0 | 1 |
| 0 | 1 | 3 | 0 | 1 |
| -1 | 1 | 7 | 0 | 1 |
| 41 | 103 | 9087 | 9087 | 1 |
| 45 | 103 | 345 | 345 | 2 |
| 5291 | 1004 | 20576 | 20576 | 1 |
| 7596 | 1004 | 1908 | 1908 | 2 |
| 12001 | 1004 | 700 | 700 | 3 |
+----------+-------------+-------+-------+-----+
Then using TOP 1 WITH TIES construction we leave only rows where rnk equals 1.
you can try like this.
SELECT TOP 1 sales FROM MyTable WHERE agreemtneid > 1 ORDER BY sales DESC
I really do not know the business logic behind agreement_id > 1. It looks to me you want the max sales (with ties) by agreement id regardless of vendor_id.
First, lets create a simple sample database.
-- Sample table
create table #sales
(
vendor_id int,
agreement_id int,
sales_amt money
);
-- Sample data
insert into #sales values
(12001, 1004, 700),
(5291, 1004, 20576),
(7596, 1004, 1908),
(45, 103, 345),
(41, 103, 9087);
Second, let's solve this problem using a common table expression to get a result set that has each row paired with the max sales by agreement id.
The select statement just applies the business logic to filter the data to get your answer.
-- CTE = max sales for each agreement id
;
with cte_sales as
(
select
vendor_id,
agreement_id,
sales_amt,
max(sales_amt) OVER(PARTITION BY agreement_id) AS max_sales
from
#sales
)
-- Filter by your business logic
select * from cte_sales where sales_amt = max_sales and agreement_id > 1;
The screen shot below shows the exact result you wanted.