oracle sql Find max avg of three attempts - sql

Hey need help with finding maximum average weight of three columnes (attempt1, attempt2 and attempt3 and showing which exercise they belong to and what date they occurred.
Atm, the results of the below query outputs, all exercises, all dates they occurred on and all the avg weights. I want it to select the max avg weight, the exercise it belongs to and date it occurred. Attached is the result of the query and ive highlighted what I want to be the output.
Result of query
SELECT e.exercise_description
, occ.occ_date, (COALESCE(OE.ATTEMPT1, 0)
+ COALESCE(OE.ATTEMPT2, 0)
+ COALESCE(OE.ATTEMPT3, 0))
/(3 -(COALESCE(OE.ATTEMPT1 - OE.ATTEMPT1, 1)
+ COALESCE(OE.ATTEMPT2 - OE.ATTEMPT2, 1)
+ COALESCE(OE.ATTEMPT3 - OE.ATTEMPT3, 1))
) AS row_avg
FROM EXERCISE E INNER JOIN Occurrence_Exercise OE
ON E.EXERCISEID=OE.EXERCISEID
INNER JOIN OCCURRENCE OCC ON OE.OCCURRENCEID=OCC.OCCURRENCEID;

You can just use window row_number() function to get the biggest avg one
SELECT e.exercise_description
, occ.occ_date
FROM
(SELECT oe.exerciseid
, oe.occurrenceid
, ROW_NUMBER() OVER(ORDER BY (COALESCE(oe.attempt1, 0) + COALESCE(oe.attempt2, 0)+ COALESCE(oe.attempt3, 0))
/ (NVL2(oe.attempt1, 1, 0) + NVL2(oe.attempt2, 1, 0) + NVL2(oe.attempt3, 1, 0))
) AS rn
FROM Occurrence_Exercise oe
) srt
INNER JOIN exercise e
ON srt.exerciseid=e.exerciseid
INNER JOIN occurrence occ
ON srt.occurrenceid=occ.occurrenceid
WHERE srt.rn = 1

Related

Summing some columns in SQL Server from joined multiple table based on unique id

my query used to report monthly salary so when choose month from 1 - 2021 to 8 - 2021 it report like this i want to get same result for each badgenumber in one row for all choosen monthsI have the following query that collect data from multiple table
SELECT
dbo.USERINFO.BADGENUMBER ,
dbo.Emp_OV_LT.Overtime ,
dbo.Emp_OV_LT.Absent ,
(dbo.Emp_OV_LT.Late + dbo.Emp_OV_LT.Early) ,
ROUND((dbo.Salaries.B_S), 3),
ROUND((dbo.Salaries.T_A + dbo.Salaries.W_A + dbo.Salaries.L_A + dbo.Salaries.C_A), 3) ,
ROUND( dbo.Salaries.Overtime, 3),
ROUND(dbo.Salaries.Absent, 3),
ROUND( dbo.Salaries.Late_Deduction,3) ,
ROUND(dbo.Salaries.Total_Salary,3),
dbo.Salaries.SSN ,
ROUND(dbo.Salaries.n_salary,3)
FROM
dbo.USERINFO
INNER JOIN
dbo.Salaries ON dbo.USERINFO.USERID = dbo.Salaries.User_ID
INNER JOIN
dbo.Emp_Salary ON dbo.USERINFO.USERID = dbo.Emp_Salary.Emp_ID
INNER JOIN
dbo.Emp_OV_LT ON dbo.Emp_OV_LT.Emp_ID = dbo.USERINFO.USERID
WHERE
dbo.Salaries.Month = dbo.Emp_OV_LT.Month
AND dbo.Salaries.Month BETWEEN '1 - 2021' AND '8 - 2021'
AND dbo.Emp_OV_LT.year = '2021'
AND dbo.Salaries.ssn > 1
ORDER BY
dbo.userinfo.ssn,
dbo.Emp_OV_LT.Month
I want to sum all selected columns based on USERINFO.BADGENUMBER when it duplicated after change the month criteria for than one month
my query used to report monthly salary so when choose month from 1 - 2021 to 1 - 2021 it report like thisOk, I am going to take a stab at this, with what I believe you are trying to accomplish. I have been staring at your post for a while, and making some assumptions.
You stated
I want to sum all selected columns
At first I thought you wanted to sum all of the columns contained in the SELECT clause, but that wouldn't make sense. So I assume that you want to choose which columns you SUM. So let's say you want to SUM dbo.Emp_OV_LT.Overtime OVER each month / year for each dbo.USERINFO.BADGENUMBER. I believe you would do something like this.
WITH CTE AS
(
SELECT
dbo.USERINFO.BADGENUMBER ,
dbo.Emp_OV_LT.Overtime ,
dbo.Emp_OV_LT.Absent ,
(dbo.Emp_OV_LT.Late + dbo.Emp_OV_LT.Early) ,
ROUND((dbo.Salaries.B_S), 3),
ROUND((dbo.Salaries.T_A + dbo.Salaries.W_A + dbo.Salaries.L_A +
dbo.Salaries.C_A), 3) ,
ROUND( dbo.Salaries.Overtime, 3),
ROUND(dbo.Salaries.Absent, 3),
ROUND( dbo.Salaries.Late_Deduction,3) ,
ROUND(dbo.Salaries.Total_Salary,3),
dbo.Salaries.SSN ,
ROUND(dbo.Salaries.n_salary,3) ,
dbo.Salaries.Month,
dbo.Emp_OV_LT.year
FROM
dbo.USERINFO
INNER JOIN
dbo.Salaries ON dbo.USERINFO.USERID = dbo.Salaries.User_ID
INNER JOIN
dbo.Emp_Salary ON dbo.USERINFO.USERID = dbo.Emp_Salary.Emp_ID
INNER JOIN
dbo.Emp_OV_LT ON dbo.Emp_OV_LT.Emp_ID = dbo.USERINFO.USERID
WHERE
dbo.Salaries.Month = dbo.Emp_OV_LT.Month
AND dbo.Salaries.ssn > 1
ORDER BY
dbo.userinfo.ssn,
dbo.Emp_OV_LT.Month
)
SELECT DISTINCT *,
SUM(Overtime) OVER (PARTITION BY [Month],
BADGENUMBER]) AS SUM_OF_OverTime
FROM CTE
WHERE [Month] BETWEEN '1 - 2021' AND '8 - 2021' AND [year] = '2021'
Without having access to the database and tables, or some sample data, this is the best I could come up with.
Edit, you must add dbo.Salaries.Month to your original SELECT since you are partitioning by that field. Also, you should move the field dbo.Emp_OV_LT.year to your SELECT and you should use that field in your WHERE clause.

How to calculate value based on average of previous month and average of same month last year in SQL

I would like to calculate targets for opened rates and clicked rates based on actuals of the last month and the same month last year.
My table is aggregated at daily level and I have grouped it by month and year to get the monthly averages. I have then created a self-join to join my current dates on the results of the previous months. This works fine for all months except for January because SQL can't know that it's supposed to join 1 on 12. Is there a way to specify this in my join clause?
Essentially, the results for January 2021 shouldn't be null because I have December 2020 data.
This is my data and my query:
CREATE TABLE exasol_last_year_avg(
date_col date,
country text,
brand text,
category text,
delivered integer,
opened integer,
clicked integer
)
INSERT INTO exasol_last_year_avg
(date_col,country,brand,category,delivered,opened,clicked) VALUES
(2021-01-01,'AT','brand1','cat1',100,60,23),
(2021-01-01,'AT','brand1','cat2',200,50,45),
(2021-01-01,'AT','brand2','cat1',300,49,35),
(2021-01-01,'AT','brand2','cat2',400,79,57),
(2021-02-02,'AT','brand1','cat1',130,78,30),
(2021-02-02,'AT','brand1','cat2',260,65,59),
(2021-02-02,'AT','brand2','cat1',390,64,46),
(2021-02-02,'AT','brand2','cat2',520,103,74),
(2020-12-02,'AT','brand1','cat1',130,78,30),
(2020-12-02,'AT','brand1','cat2',260,65,59),
(2020-12-02,'AT','brand2','cat1',390,64,46),
(2020-12-02,'AT','brand2','cat2',520,103,74),
(2020-02-02,'AT','brand1','cat2',236,59,53),
(2020-02-02,'AT','brand2','cat1',355,58,41),
(2020-02-02,'AT','brand2','cat2',473,93,67),
(2020-02-02,'AT','brand1','cat1',118,71,27)
This is written in PostgresSQL because I think it's more accessible to most people, but my production database is Exasol!
select *
from
(Select month_col,
year_col,
t_campaign_cmcategory,
t_country,
t_brand,
(t2_clicktoopenrate + t3_clicktoopenrate)/2 as target_clicktoopenrate,
(t2_openrate + t3_openrate)/2 as target_openrate
from (
with CTE as (
select extract(month from date_col) as month_col,
extract(year from date_col) as year_col,
category as t_campaign_cmcategory,
country as t_country,
brand as t_brand,
round(sum(opened)/nullif(sum(delivered),0),3) as OpenRate,
round(sum(clicked)/nullif(sum(opened),0),3) as ClickToOpenRate
from public.exasol_last_year_avg
group by 1, 2, 3, 4, 5)
select t1.month_col,
t1.year_col,
t2.month_col as t2_month_col,
t2.year_col as t2_year_col,
t3.month_col as t3_month_col,
t3.year_col as t3_year_col,
t1.t_campaign_cmcategory,
t1.t_country,
t1.t_brand,
t1.OpenRate,
t1.ClickToOpenRate,
t2.OpenRate as t2_OpenRate,
t2.ClickToOpenRate as t2_ClickToOpenRate,
t3.OpenRate as t3_OpenRate,
t3.ClickToOpenRate as t3_ClickToOpenRate
from CTE t1
left join CTE t2
on t1.month_col = t2.month_col + 1
and t1.year_col = t2.year_col
and t1.t_campaign_cmcategory = t2.t_campaign_cmcategory
and t1.t_country = t2.t_country
and t1.t_brand = t2.t_brand
left join CTE t3
on t1.month_col = t3.month_col
and t1.year_col = t3.year_col + 1
and t1.t_campaign_cmcategory = t3.t_campaign_cmcategory
and t1.t_country = t3.t_country
and t1.t_brand = t3.t_brand) as target_base) as final_tbl
Start with an aggregation query:
select date_trunc('month', date_col), country, brand,
sum(opened) * 1.0 / nullif(sum(delivered), 0) as OpenRate,
sum(clicked) * 1.0 / nullif(sum(opened), 0) as ClickToOpenRate
from exasol_last_year_avg
group by 1, 2, 3;
Then, use window functions. Assuming you have a value for every month (with no gaps). you can just use lag(). I'm not sure what your final calculation is, but this brings in the data:
with mcb as (
select date_trunc('month', date_col) as yyyymm, country, brand,
sum(opened) * 1.0 / nullif(sum(delivered), 0) as OpenRate,
sum(clicked) * 1.0 / nullif(sum(opened), 0) as ClickToOpenRate
from exasol_last_year_avg
group by 1, 2, 3
)
select mcb.*,
lag(openrate, 1) over (partition by country, brand order by yyyymm) as prev_month_openrate,
lag(ClickToOpenRate, 1) over (partition by country, brand order by yyyymm) as prev_month_ClickToOpenRate,
lag(openrate, 12) over (partition by country, brand order by yyyymm) as prev_year_openrate,
lag(ClickToOpenRate, 12) over (partition by country, brand order by yyyymm) as prev_year_ClickToOpenRate
from mcb;
This works with a different join condition:
select *
from
(Select month_col,
year_col,
t_campaign_cmcategory,
t_country,
t_brand,
(t2_clicktoopenrate + t3_clicktoopenrate)/2 as target_clicktoopenrate,
(t2_openrate + t3_openrate)/2 as target_openrate
from (
with CTE as (
select extract(month from date_col) as month_col,
extract(year from date_col) as year_col,
category as t_campaign_cmcategory,
country as t_country,
brand as t_brand,
round(sum(opened)/nullif(sum(delivered),0),3) as OpenRate,
round(sum(clicked)/nullif(sum(opened),0),3) as ClickToOpenRate
from public.exasol_last_year_avg
group by 1, 2, 3, 4, 5)
select t1.month_col,
t1.year_col,
t2.month_col as t2_month_col,
t2.year_col as t2_year_col,
t3.month_col as t3_month_col,
t3.year_col as t3_year_col,
t1.t_campaign_cmcategory,
t1.t_country,
t1.t_brand,
t1.OpenRate,
t1.ClickToOpenRate,
t2.OpenRate as t2_OpenRate,
t2.ClickToOpenRate as t2_ClickToOpenRate,
t3.OpenRate as t3_OpenRate,
t3.ClickToOpenRate as t3_ClickToOpenRate
from CTE t1
left join CTE t2
-- adjusted join condition
on ((t1.month_col = (CASE WHEN t1.month_col = 1 then t2.month_col - 11 END) and t1.year_col = t2.year_col + 1)
or (t1.month_col = (CASE WHEN t1.month_col != 1 then t2.month_col + 1 END) and t1.year_col = t2.year_col))
and t1.t_campaign_cmcategory = t2.t_campaign_cmcategory
and t1.t_country = t2.t_country
and t1.t_brand = t2.t_brand
left join CTE t3
on t1.month_col = t3.month_col
and t1.year_col = t3.year_col + 1
and t1.t_campaign_cmcategory = t3.t_campaign_cmcategory
and t1.t_country = t3.t_country
and t1.t_brand = t3.t_brand) as target_base) as final_tbl

How to devide my Coordinates into longtitue and latitude in a SQL query

I have the sql queries like this:
Select Userid, sum(cast(distanceinKM as int)) as KM, day from(
SELECT [User].Userid
,[User].ulatitude, [User].ulongitude, [Checkpoint].clatitude, [Checkpoint].clongitutde,
(geography::Point([User].ulatitude, [User].ulongitude, 4326)).STDistance
(geography::Point([Checkpoint].clatitude, [Checkpoint].clongitutde, 4326))/100 as distanceinKM, cast(Timestamp as date) as day
FROM [User] INNER JOIN
Tablelog ON [User].Userid = Tablelog.Userid INNER JOIN
[Checkpoint] ON Tablelog.checkpointid = [Checkpoint].checkpiontid ) as distance
where Day(day) = 6 AND MONTH (day) = 9 AND YEAR (day) = 2011
group by userid , day
The function works well, but I have a problem with the coordinates. In my database my coordinates are stores this way: (55.56490549999999, 9.756640400000038) but in the query I have them divided into ulatitude and ulongtitude. So I was dividing them manually but I cannot do that anymore since I have a lot of data.
What can I add in the query so I take the coordinates in this format (55.56490549999999, 9.756640400000038) and divide them .
UPDATED v-4
I've updated the query to fit the exact data format. Please try:
Select
distance.Userid,
sum(cast(distance.distanceinKM as int)) as KM,
distance.[day]
from
(
SELECT
UC_Lat_Long.Userid,
UC_Lat_Long.ulatitude,
UC_Lat_Long.ulongitude,
UC_Lat_Long.clatitude,
UC_Lat_Long.clongitutde,
(geography::Point(UC_Lat_Long.ulatitude, UC_Lat_Long.ulongitude, 4326)).STDistance(geography::Point(UC_Lat_Long.clatitude, UC_Lat_Long.clongitutde, 4326))/100 as distanceinKM,
UC_Lat_Long.[day]
FROM
(
SELECT
[User].Userid,
CONVERT(NUMERIC(28,8), LTRIM(RTRIM(SUBSTRING(ISNULL([User].Coordinates, '0,0'), 1, CHARINDEX(',', ISNULL([User].Coordinates, '0,0')) - 1)))) AS ulatitude,
CONVERT(NUMERIC(28,8), LTRIM(RTRIM(SUBSTRING(ISNULL([User].Coordinates, '0,0'), CHARINDEX(',', ISNULL([User].Coordinates, '0,0')) + 1, LEN(ISNULL([User].Coordinates, '0,0')) - CHARINDEX(',', ISNULL([User].Coordinates, '0,0')) - 1)))) AS ulongitude,
CONVERT(NUMERIC(28,8), LTRIM(RTRIM(SUBSTRING(ISNULL([Checkpoint].coordinates, '0,0'), 1, CHARINDEX(',', ISNULL([Checkpoint].coordinates, '0,0')) - 1)))) AS clatitude,
CONVERT(NUMERIC(28,8), LTRIM(RTRIM(SUBSTRING(ISNULL([Checkpoint].coordinates, '0,0'), CHARINDEX(',', ISNULL([Checkpoint].coordinates, '0,0')) + 1, LEN(ISNULL([Checkpoint].coordinates, '0,0')) - CHARINDEX(',', ISNULL([Checkpoint].coordinates, '0,0')) - 1)))) AS clongitutde,
cast([Timestamp] as date) as [day]
FROM
[User]
INNER JOIN Tablelog ON [User].Userid = Tablelog.Userid
INNER JOIN [Checkpoint] ON Tablelog.checkpointid = [Checkpoint].checkpiontid
) AS UC_Lat_Long
) as distance
where
Day(distance.[day]) = 6
AND MONTH (distance.[day]) = 9
AND YEAR (distance.[day]) = 2011
group by
distance.Userid,
distance.[day]

Using SELECT result in another SELECT

So here is my query
SELECT
*
FROM
Score AS NewScores
WHERE
InsertedDate >= DATEADD(mm, -3, GETDATE());
SELECT
ROW_NUMBER() OVER( ORDER BY NETT) AS Rank,
Name,
FlagImg,
Nett,
Rounds
FROM (
SELECT
Members.FirstName + ' ' + Members.LastName AS Name,
CASE
WHEN MenuCountry.ImgURL IS NULL THEN
'~/images/flags/ismygolf.png'
ELSE
MenuCountry.ImgURL
END AS FlagImg,
AVG(CAST(NewScores.NetScore AS DECIMAL(18, 4))) AS Nett,
COUNT(Score.ScoreID) AS Rounds
FROM
Members
INNER JOIN
Score
ON Members.MemberID = Score.MemberID
LEFT OUTER JOIN MenuCountry
ON Members.Country = MenuCountry.ID
WHERE
Members.Status = 1
GROUP BY
Members.FirstName + ' ' + Members.LastName,
MenuCountry.ImgURL
) AS Dertbl
ORDER BY;
The query is to give a result set for a GridView based leaderboard and what I want is to only get the average of Scores that are less than 3 months old. I have this in 2 parts as you can see and obviously it gives an error like this.
Msg 4104, Level 16, State 1, Line 2
The multi-part identifier "NewScores.NetScore" could not be bound.
Which is because of this AVG(CAST(NewScores.NetScore AS DECIMAL(18, 4))) AS Nett
How do I make it so that I can use NewScores there so I'm only getting the average of the scores less than 3 months old?
EDIT: Using the answers people provided I've solved it by using a join in the correct place and here is the correct query:
SELECT ROW_NUMBER() OVER(ORDER BY NETT) AS Rank, Name, FlagImg, Nett, Rounds FROM (SELECT Members.FirstName + ' ' + Members.LastName AS Name, CASE WHEN MenuCountry.ImgURL IS NULL THEN '~/images/flags/ismygolf.png' ELSE MenuCountry.ImgURL END AS FlagImg, AVG(CAST(NewScores.NetScore AS DECIMAL(18, 4))) AS Nett, COUNT(NewScores.ScoreID) AS Rounds FROM Members INNER JOIN (SELECT * FROM Score WHERE InsertedDate >= DATEADD(mm, -5, GETDATE())) NewScores ON Members.MemberID = NewScores.MemberID LEFT OUTER JOIN MenuCountry ON Members.Country = MenuCountry.ID WHERE Members.Status = 1 GROUP BY Members.FirstName + ' ' + Members.LastName, MenuCountry.ImgURL) AS Dertbl ORDER BY Nett ASC
NewScores is an alias to Scores table - it looks like you can combine the queries as follows:
SELECT
ROW_NUMBER() OVER( ORDER BY NETT) AS Rank,
Name,
FlagImg,
Nett,
Rounds
FROM (
SELECT
Members.FirstName + ' ' + Members.LastName AS Name,
CASE
WHEN MenuCountry.ImgURL IS NULL THEN
'~/images/flags/ismygolf.png'
ELSE
MenuCountry.ImgURL
END AS FlagImg,
AVG(CAST(NewScores.NetScore AS DECIMAL(18, 4))) AS Nett,
COUNT(Score.ScoreID) AS Rounds
FROM
Members
INNER JOIN
Score NewScores
ON Members.MemberID = NewScores.MemberID
LEFT OUTER JOIN MenuCountry
ON Members.Country = MenuCountry.ID
WHERE
Members.Status = 1
AND NewScores.InsertedDate >= DATEADD(mm, -3, GETDATE())
GROUP BY
Members.FirstName + ' ' + Members.LastName,
MenuCountry.ImgURL
) AS Dertbl
ORDER BY;
What you are looking for is a query with WITH clause, if your dbms supports it. Then
WITH NewScores AS (
SELECT *
FROM Score
WHERE InsertedDate >= DATEADD(mm, -3, GETDATE())
)
SELECT
<and the rest of your query>
;
Note that there is no ; in the first half. HTH.
You are missing table NewScores, so it can't be found. Just join this table.
If you really want to avoid joining it directly you can replace NewScores.NetScore with SELECT NetScore FROM NewScores WHERE {conditions on which they should be matched}

Transposing number from one column into another one where = 0

My question is this,
I have a query I'm working on and I have some values that are 0. I want to be able to take a value from a previous month that is not zero and put it in place of the zero. See the example below.
SELECT item,
stock,
sold,
level,
month,
year
FROM agingdata
GROUP BY item,
stock,
sold,
month,
year,
level
HAVING ( item = #Item )
ORDER BY year,
month
So I want take the number 2455 and input it into the stock where it says 0, taking last months balance number as the current months stock level. Is that even possible?
You can find the previous non-zero level per item (for zero level items) using this query:
SELECT find.item, find.month, find.year, result.level
FROM AgingData result
JOIN (
SELECT original.item, original.month, original.year, max(cast(cast(previous.year as varchar) + '-' + cast(previous.month as varchar) + '-1' as datetime)) previous_date
FROM AgingData original
JOIN AgingData previous
ON original.item = previous.item
AND ((original.year > previous.year)
OR (original.year = previous.year AND original.month > previous.month))
WHERE original.level = 0
AND previous.level != 0
GROUP BY original.item, original.month, original.year ) find
ON result.item = find.item
AND cast(cast(result.year as varchar) + '-' + cast(result.month as varchar) + '-1' as datetime) = find.previous_date
This will work even if the previous non-zero level is several months before.
Something along these lines, this only works if the previous month is non-zero....
SELECT cur.Item,
CASE
WHEN (cur.Stock<>0)
THEN cur.Stock
ELSE prev.Stock
END as Stock,
cur.Sold,
cur.Level,
cur.Month,
cur.Year
FROM AgingData cur
LEFT OUTER JOIN AgingData prev
ON prev.item=cur.item and prev.Month = cur.Month - 1
GROUP BY cur.Item, cur.Stock, cur.Sold, cur.Month, cur.Year, cur.Level
HAVING (cur.Item = #Item)
ORDER BY cur.Year, cur.Month