SQL Highest Value With Group - sql

What I need to do is get the Highest StockOnSite per ProductID ( calculating the StockDifference ) record and concatenate StockOnSite with StockOffsite to create a column AllStock
I am completely lost? as I cannot group as we have a StockOnSite and StockOffsite
Here is the SQLFiddle
Fiddle
This is not a duplicate post, as the outer select complicates the grouping.
Thanks

I believe this is the query you've been looking for.
It evaluates StockDiff as you suggested: StockOnSite - StockOffSite and then takes the highest value for every SiteID
SELECT
SiteID, Description, StockOnSite, StockOffsite, AllStock, LastStockUpdateDateTime, StockDiff
FROM (
SELECT
*,
rank() OVER (PARTITION BY SiteID ORDER BY StockDiff DESC) AS rank
FROM (
SELECT
s.SiteID,
s.Description,
p.StockOnSite,
p.StockOffsite,
CAST(p.StockOnSite AS varchar(10)) + '/' + CAST(p.StockOffSite AS varchar(10)) AS AllStock,
p.LastStockUpdateDateTime,
p.StockOnSite - p.StockOffSite AS StockDiff
FROM
Sites s
JOIN Products p ON s.SiteID = p.OnSiteID
) foo
) goo
WHERE rank = 1
ORDER BY 1
I used a Window function to get it done.
Edit
If you need highest StockOnSite you can easily modify the Window Function by replacing StockDiff in ORDER BY StockDiff DESC with StockOnSite

You wanted to highest StockOnSite by ProductID, but the sample set all had unique productIDs. This query will get what you're asking for, but I think your question might be unclear as to what your result set needs to look like.
select pr.ProductID
, s.SiteID
,s.Description
,StockOnSite
,StockOffsite
,AllStock = cast(coalesce(pr.StockOnSite,'') as varchar(10)) + '-' + cast(coalesce(pr.StockOffsite,'') as varchar(10))
,LastStockUpdateDateTime = pr.LastStockUpdateDateTime
,Stockdiff = StockOnSite - StockOffsite
from Products pr
inner join (
select pr.ProductID
, MAX(StockOnSite) MaxStockOnSite
from dbo.Products pr
group by [ProductID]
) x
ON x.ProductID = pr.ProductID
and x.MaxStockOnSite = pr.StockOnSite
inner join dbo.Sites s
ON pr.OnSiteId = s.SiteId

this query may help you :
select * from Products p1
join
(
select onsiteid,max(stockonsite-stockoffsite) as stockdiff
from products
group by onsiteid
) p2
on p1.onsiteid = p2.onsiteid and (p1.stockonsite - p1.stockoffsite) = p2.stockdiff
you can modify select as per your need.

Related

How to increment rank when same total marks is there using mysql query?

This is my query:
SELECT
`users`.`id` AS userID,
`user_tests`.`id`,
`users`.`profilePic`,
`users`.`firstName`,
`user_tests`.`userId`,
`user_tests`.`isFirstAttempt`,
`user_tests`.`total_marks`,
FIND_IN_SET(
`user_tests`.`total_marks`,
(
SELECT
GROUP_CONCAT(
DISTINCT `user_tests`.`total_marks`
ORDER BY
CAST(
`user_tests`.`total_marks` AS DECIMAL(5, 3)
)
DESC
)
FROM
`user_tests`
WHERE
`user_tests`.`testSeriesId` = '856' AND `user_tests`.`isFirstAttempt` = '1'
)
) AS rank,
FROM
`user_tests`
LEFT JOIN `users` ON `users`.id = `user_tests`.`userId`
WHERE
`user_tests`.`isFirstAttempt` = '1' AND `user_tests`.`testSeriesId` = '856'
ORDER BY
CAST(
`user_tests`.`total_marks` AS DECIMAL(5, 3)
)
DESC
,
`submissionTimeInMinutes` ASC,
`rank` ASC;
Output:
this is the image
Expected:
Here is the expected output image
I am using MariaDB 5.5.68
I've tried using variables to increment but it's showing me the current row number instead of 1,2,3,4,5... numbers.
Can anybody help here?
Thanks.
You don't appear to need a left join as none of the user names are missing. A simple subquery will give you the the ranking by total_mark but I'm not sure whether you're counting users or something else. A CTE would let you avoid duplicating some of the logic and might possibly even be faster. I don't know if you have that option.
SELECT
u.id AS userID, t.id, u.profilePic, u.firstName,
t.userId, t.isFirstAttempt, t.total_marks,
(
SELECT count(distinct userId) from FROM user_tests t2
WHERE t.isFirstAttempt = 1 AND t.testSeriesId = 856
AND t.total_marks < t2.total_marks
) as num_tests
FROM user_tests t inner join users u ON u.id = t.userId
WHERE t.isFirstAttempt = 1 AND t.testSeriesId = 856
ORDER BY total_marks desc, submissionTimeInMinutes, num_tests desc

Remove multiple rows with same ID

So I've done some looking around and wasn't unable to find quite what I was looking for. I have two tables.
1.) Table where general user information is stored
2.) Where a status is generated and stored.
The problem is, is that there are multiple rows for the same users and querying these results in multiple returns. I can't just merge them because they aren't all the same status. I need just the newest status from that table.
Example of the table:
SELECT DISTINCT
TOP(50) cam.UserID AS PatientID,
mppi.DisplayName AS Surgeon,
ISNULL(sci.IOPStatus, 'N/A') AS Status,
tkstat.TrackerStatusID AS Stat_2
FROM
Main AS cam
INNER JOIN
Providers AS rap
ON cam.VisitID = rap.VisitID
INNER JOIN
ProviderInfo AS mppi
ON rap.UnvUserID = mppi.UnvUserID
LEFT OUTER JOIN
Inop AS sci
ON cam.CwsID = sci.CwsID
LEFT OUTER JOIN
TrackerStatus AS tkstat
ON cam.CwsID = tkstat.CwsID
WHERE
(
cam.Location_ID IN
(
'SURG'
)
)
AND
(
rap.IsAttending = 'Y'
)
AND
(
cam.DateTime BETWEEN CONCAT(CAST(GETDATE() AS DATE), ' 00:00:00') AND CONCAT(CAST(GETDATE() AS DATE), ' 23:59:59')
)
AND
(
cam.Status_StatusID != 'Cancelled'
)
ORDER BY
cam.UserID ASC
So I need to grab only the newest Stat_2 from each ID so they aren't returning multiple rows. Each Stat_2 also has an update time meaning I can sort by the time/date that column is : StatusDateTime
One way to handle this is to create a calculated row_number for the table where you need the newest record.
Easiest way to do that is to change your TKSTAT join to a derived table with the row_number calculation and then add a constraint to your join where the RN =1
SELECT DISTINCT TOP (50)
cam.UserID AS PatientID, mppi.DisplayName AS Surgeon, ISNULL(sci.IOPStatus, 'N/A') AS Status, tkstat.TrackerStatusID AS Stat_2
FROM Main AS cam
INNER JOIN Providers AS rap ON cam.VisitID = rap.VisitID
INNER JOIN ProviderInfo AS mppi ON rap.UnvUserID = mppi.UnvUserID
LEFT OUTER JOIN Inop AS sci ON cam.CwsID = sci.CwsID
LEFT OUTER JOIN (SELECT tk.CwsID, tk.TrackerStatusId, ROW_NUMBER() OVER (PARTITION BY tk.cwsId ORDER BY tk.CreationDate DESC) AS rn FROM TrackerStatus tk)AS tkstat ON cam.CwsID = tkstat.CwsID
AND tkstat.rn = 1
WHERE (cam.Location_ID IN ( 'SURG' )) AND (rap.IsAttending = 'Y')
AND (cam.DateTime BETWEEN CONCAT(CAST(GETDATE() AS DATE), ' 00:00:00') AND CONCAT(CAST(GETDATE() AS DATE), ' 23:59:59'))
AND (cam.Status_StatusID != 'Cancelled')
ORDER BY cam.UserID ASC;
Note you need a way to derive what the "newest" status is; I assume there is a created_date or something; you'll need to enter the correct colum name
ROW_NUMBER() OVER (PARTITION BY tk.cwsId ORDER BY tk.CreationDate DESC) AS rn
SQL Server doesn't offer a FIRST function, but you can reproduce the functionality with ROW_NUMBER() like this:
With Qry1 (
Select <other columns>,
ROW_NUMBER() OVER(
PARTITION BY <group by columns>
ORDER BY <time stamp column*> DESC
) As Seq
From <the rest of your select statement>
)
Select *
From Qry1
Where Seq = 1
* for the "newest" record.

ORDER in CTE lost after GROUP BY

I have the following SQL
WITH tally AS (
SELECT results.answer,
results.poll_id,
count(1) AS votes
FROM (
SELECT pr.poll_id,
unnest(pr.response) AS answer
FROM poll_responses pr
LEFT JOIN polls p ON pr.poll_id = p.id
LEFT JOIN poll_collections pc ON pc.id = p.poll_collection_id
WHERE pc.id = ${pollCollectionId}
) AS results
GROUP BY results.answer, results.poll_id
),
all_choices AS (SELECT unnest(pls.choices) AS choice,
pls.id AS poll_id
FROM poll_collections pcol
INNER JOIN polls pls
ON pcol.id = pls.poll_collection_id
WHERE pcol.id = ${pollCollectionId}),
unvoted_tally AS (SELECT ac.choice AS answer,
ac.poll_id,
0 AS total
FROM all_choices ac
LEFT JOIN tally t ON t.answer = ac.choice
WHERE t.answer IS NULL),
final_tally AS (SELECT *
FROM tally
UNION
ALL
SELECT *
FROM unvoted_tally),
sorted_tally AS (
SELECT ft.*
FROM final_tally ft
ORDER BY array_position(array(SELECT choice FROM all_choices), ft.answer)
)
SELECT json_agg(poll_results.polls) AS polls
FROM (
SELECT json_array_elements(json_agg(results)) -> 'poll' AS polls
FROM (
SELECT json_build_object(
'id', st.poll_id,
'question', pls.question,
'choice-type', pls.choice_type,
'results',
json_agg(json_build_object('choice', st.answer, 'votes', st.votes)),
'chosen', pr.response
) AS poll
FROM sorted_tally st
LEFT JOIN polls pls
ON
pls.id = st.poll_id
LEFT JOIN poll_responses pr
ON
pr.poll_id = st.poll_id AND
pr.email = ${email}
GROUP BY st.poll_id, pls.choice_type, pr.response, pls.question
) AS results)
AS poll_results;
I have a poll_responses table which store the user responses of a poll. I want to order the responses in exactly the same order they are stored in the polls table - as an array e.g., {Yes, No, Maybe}.
I applied the ORDER BY array_position(array(SELECT choice FROM all_choices), ft.answer) in the sorted_tally CTE.
However, in the file SELECT after applying GROUP BY the order is lost.
Is there a way to preserve the order of the choices?
Also, are there any optimizations applicable?
Much appreciated!
In json_build_object or json_agg you can set ORDER BY clause. First, have the last CTE SELECT needed order expression as a new column, then run in outermost query:
CTE
...
sorted_tally AS (
SELECT ft.votes
, ft.poll_id
, ft.answer
, array_position(array(SELECT choice FROM all_choices),
ft.answer) AS choice_order
FROM final_tally ft
ORDER BY
)
Outermost Query
...
json_build_object(
'id', st.poll_id,
'question', pls.question,
'choice-type', pls.choice_type,
'results', json_agg(json_build_object('choice', st.answer,
'votes', st.votes)
ORDER BY st.choice_order),
'chosen', pr.response
) AS poll
ORDER BY in a CTE doesn't really matter. It may work, but SQL Server is free to re-order the rows unless you specify ORDER BY in the outermost query to order all the results.

Multiple MAX values select using inner join

I have query that work for me only when values in the StakeValue don't repeat.
Basically, I need to select maximum values from SI_STAKES table with their relations from two other tables grouped by internal type.
SELECT a.StakeValue, b.[StakeName], c.[ProviderName]
FROM SI_STAKES AS a
INNER JOIN SI_STAKESTYPES AS b ON a.[StakeTypeID] = b.[ID]
INNER JOIN SI_PROVIDERS AS c ON a.[ProviderID] = c.[ID] WHERE a.[EventID]=6
AND a.[StakeGroupTypeID]=1
AND a.StakeValue IN
(SELECT MAX(d.StakeValue) FROM SI_STAKES AS d
WHERE d.[EventID]=a.[EventID] AND d.[StakeGroupTypeID]=a.[StakeGroupTypeID]
GROUP BY d.[StakeTypeID])
ORDER BY b.[StakeName], a.[StakeValue] DESC
Results for example must be:
[ID] [MaxValue] [StakeTypeID] [ProviderName]
1 1,5 6 provider1
2 3,75 7 provider2
3 7,6 8 provider3
Thank you for your help
There are two problems to solve here.
1) Finding the max values per type. This will get the Max value per StakeType and make sure that we do the exercise only for the wanted events and group type.
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
2) Then we need to get only one return back for that value since it may be present more then once.
Using the Max Value, we must find a unique row for each I usually do this by getting the Max ID is has the added advantage of getting me the most recent entry.
SELECT MAX(SMaxID.ID) AS ID
FROM SI_STAKES AS SMaxID
INNER JOIN (
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
) AS SMaxVal ON SMaxID.StakeTypeID = SMaxVal.StakeTypeID
AND SMaxID.StakeValue = SMaxVal.MaxStakeValue
AND SMaxID.EventID = SMaxVal.EventID
AND SMaxID.StakeGroupTypeID = SMaxVal.StakeGroupTypeID
3) Now that we have the ID's of the rows that we want, we can just get that information.
SELECT Stakes.ID, Stakes.StakeValue, SType.StakeName, SProv.ProviderName
FROM SI_STAKES AS Stakes
INNER JOIN SI_STAKESTYPES AS SType ON Stake.[StakeTypeID] = SType.[ID]
INNER JOIN SI_PROVIDERS AS SProv ON Stake.[ProviderID] = SProv.[ID]
WHERE Stake.ID IN (
SELECT MAX(SMaxID.ID) AS ID
FROM SI_STAKES AS SMaxID
INNER JOIN (
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
) AS SMaxVal ON SMaxID.StakeTypeID = SMaxVal.StakeTypeID
AND SMaxID.StakeValue = SMaxVal.MaxStakeValue
AND SMaxID.EventID = SMaxVal.EventID
AND SMaxID.StakeGroupTypeID = SMaxVal.StakeGroupTypeID
)
You can use the over clause since you're using T-SQL (hopefully 2005+):
select distinct
a.stakevalue,
max(a.stakevalue) over (partition by a.staketypeid) as maxvalue,
b.staketypeid,
c.providername
from
si_stakes a
inner join si_stakestypes b on
a.staketypeid = b.id
inner join si_providers c on
a.providerid = c.id
where
a.eventid = 6
and a.stakegrouptypeid = 1
Essentially, this will find the max a.stakevalue for each a.staketypeid. Using a distinct will return one and only one row. Now, if you wanted to include the min a.id along with it, you could use row_number to accomplish this:
select
s.id,
s.maxvalue,
s.staketypeid,
s.providername
from (
select
row_number() over (order by a.stakevalue desc
partition by a.staketypeid) as rownum,
a.id,
a.stakevalue as maxvalue,
b.staketypeid,
c.providername
from
si_stakes a
inner join si_stakestypes b on
a.staketypeid = b.id
inner join si_providers c on
a.providerid = c.id
where
a.eventid = 6
and a.stakegrouptypeid = 1
) s
where
s.rownum = 1

MSSQL Paging is returning random rows when not supposed too

I'm trying to do some basic paging in MSSQL. The problem I'm having is that I'm sorting the paging on a row that (potentially) has similar values, and the ORDER BY clause is returning "random" results, which doesn't work well.
So for example.
If I have three rows, and I'm sorting them by a "rating", and all of the ratings are = '5' - the rows will seemingly "randomly" order themselves. How do I make it so the rows are showing up in the same order everytime?
I tried ordering it by a datetime that the field was last edited, but the "rating" is sorted in reverse, and again, does not work how i expect it to work.
Here is the SQL I'm using thus far. I know it's sort of confusing without the data so.. any help would be greatful.
SELECT * FROM
(
SELECT
CAST(grg.defaultthumbid AS VARCHAR) + '_' +
CAST(grg.garageid AS VARCHAR) AS imagename,
(
SELECT COUNT(imageid)
FROM dbo.images im (nolock)
WHERE im.garageid = grg.garageid
) AS piccount,
(
SELECT COUNT(commentid)
FROM dbo.comments cmt (nolock)
WHERE cmt.garageid = grg.garageid
) AS commentcount,
grg.GarageID, mk.make, mdl.model, grg.year,
typ.type, usr.username, grg.content,
grg.rating, grg.DateEdit as DateEdit,
ROW_NUMBER() OVER (ORDER BY Rating DESC) As RowIndex
FROM
dbo.garage grg (nolock)
LEFT JOIN dbo.users (nolock) AS usr ON (grg.userid = usr.userid)
LEFT JOIN dbo.make (nolock) AS mk ON (grg.makeid = mk.makeid)
LEFT JOIN dbo.type (nolock) AS typ ON (typ.typeid = mk.typeid)
LEFT JOIN dbo.model (nolock) AS mdl ON (grg.modelid = mdl.modelid)
WHERE
typ.type = 'Automobile' AND
grg.defaultthumbid != 0 AND
usr.username IS NOT NULL
) As QueryResults
WHERE
RowIndex BETWEEN (2 - 1) * 25 + 2 AND 2 * 25
ORDER BY
DateEdit DESC
Try ordering by both, e.g.:
ORDER BY Rating DESC, DateEdit ASC
The query first numbers the rows by [Rating], and then re-sorts the results by [DateEdit]. Possibly not what you intended. Ordering by [RowIndex] ASC should sort it out.
ROW_NUMBER() OVER (ORDER BY [Rating] DESC) As [RowIndex]
...
ORDER BY [RowIndex]