I have a table with id and values shown below. is it possible to get another column which takes the value divided by the cumulative average as we go down the row?
original table : t1
+----+----------------------+
| id | Val |
+----+---------------------+-
| 1 | NULL |
| 2 | 136 |
| 3 | 42 |
table i want to get
+----+---------------------+-----------------------------+
| id | Val | VAL/(AVG(VAL) ) |
+----+---------------------+-----------------------------+
| 1 | NULL | NULL |
| 2 | 136 | 136/((136+0)/2)=2.000 |
| 3 | 42 | 42/((42+136+0)/3)=0.708 |
here is my query:
SELECT t1.id, t1.Val, Val/AVG(t1.Val)
FROM followers t1
JOIN followers t2
ON t2.id <= t1.id
group by t1.id;
however i get this instead:
+----+---------------------+----------------------+
| id | Val | VAL/(AVG(VAL) ) |
+----+---------------------+----------------------+
| 1 | NULL | NULL |
| 2 | 136 | 1.0000 |
| 3 | 42 | 1.0000 |
seems like AVG(Val) returns the same value from the col Val.
I was hoping to do something similar to this link here but instead of sum i want average.
MySQL SELECT function to sum current data
I re-implemented the edits and took rows with NULL into account:
+----+---------------------+---------------------+
| id | Val | VAL/(AVG(VAL) ) |
+----+---------------------+----------------------+
| 1 | NULL | NULL |
| 2 | 136 | 1.0000 |<---need this to = 2.000
| 3 | 42 | 0.4719 |<---need this to = 0.708
SELECT t1.id, t1.Val, t1.Val/(SUM(t2.Val)/(t1.id)) AS C
FROM followers t1
JOIN followers t2
ON t2.id <= t1.id
group by t1.id;
I think you want t2.val in the avg():
SELECT t1.id, t1.Val, t1.Val/AVG(t2.Val)
FROM followers t1 JOIN
followers t2
ON t2.id <= t1.id
group by t1.id;
EDIT:
Mike Brand is correct that the above is a lousy way to do what you want. In MySQL, you can do the same using variables:
select t.id, t.val,
(case when (#n := #n + 1) is null then null
when (#cumval := #cumval + val) is null then null
else t.val / (#cumval / #n)
end)
from followers t cross join
(select #n := 0, #cumval := 0) vars
order by t.id;
This might misbehave with NULL values of val, but it gives the idea for a faster way to do the calculation in MySQL.
Related
I have a table like this:
id | path | name | date | data
---+-----------+------+------------+-----
1 | Docs | 1000 | 2022-01-01 | aaa0
2 | Docs/1000 | Text | 2022-01-11 | AAA0
3 | Docs | 1001 | 2022-02-02 | aaa1
4 | Docs/1001 | Text | 2022-02-12 | AAA1
How can I select all rows with path 'Docs' and add the date of the corresponding 'Text', i.e:
id | path | name | date | date_of_text | data
---+------+------+------------+--------------+-----
1 | Docs | 1000 | 2022-01-01 | 2022-01-11 | AAA0
3 | Docs | 1001 | 2022-02-02 | 2022-02-12 | AAA1
You can achieve the desired result with self join -
SELECT T1.id, T1.path, T1.name, T1.date, T2.date date_of_text, T2.data
FROM table_name T1
LEFT JOIN table_name T2 ON T1.name = SUBSTRING(path, POSITION("/" IN path) + 1, LENGTH(path))
WHERE T1.path = 'Docs'
Lots of ways to do this including
correlated sub query
select t.*,id % 2 ,(select date from t t1 where t1.ID = t.id + 1) datetext
from t
where id % 2 > 0;
self join
select t.*,t.id % 2 , t1.date
from t
join t t1 on t1.ID = t.id + 1
where t.id % 2 > 0;
Aggregation
select min(id) id,min(path) path,min(date) date,upper(data) data ,max(date) datetext
from t
group by t.data;
I have the following table:
+----+-----------+------+
| id | table2_id | type |
+----+-----------+------+
| 1 | 100 | A |
| 2 | 100 | B |
| 3 | 100 | C |
| 4 | 100 | A |
| 5 | 250 | A |
+----+-----------+------+
I need a select statement that would get all the records before the first occurrence of type C, per table2_id.
So I want records 1, 2, and 5
I'd do this in code with a loop, but I need to do it in MySQL specifically.
If you are running MySQL 8.0, you can do this with window functions:
select *
from (
select t.*,
min(case when type = 'C' then id end) over(partition by table2_id) min_id
from mytable t
) t
where min_id is null or id < min_id
In all versions, you could use not exists:
select t.*
from mytable t
where not exists (
select 1
from mytable t1
where t1.table2_id = t.table2_id and t1.id <= t.id and t1.type = 'C'
)
I have the following two tables related by the ID column as the Primary Key. My Goal is to query the values from the "Name" column in Table 1 which correspond to the User_id with the Max and Min "Score" Column Values from Table 2.
Table 1:
| ID | Name |
|----|------|
| 1 | Foo |
| 2 | Bar |
| 3 | Zoo |
| 4 | Bar |
| 5 | Foo |
| 6 | Zar |
Table 2:
| ID | Score |
|----|-------|
| 1 | 98 |
| 2 | 67 |
| 3 | 86 |
| 4 | 59 |
| 5 | 75 |
| 6 | 73 |
The final output should give me something like this:
| Name | Score |
|------|-------|
| Foo | 98 |
| Bar | 59 |
You can try the below -
select name, score
from table1 t1 join table2 t2 on t1.id=t2.id
where
score=(select max(score) from t2)
or
score=(select min(score) from t2)
(
SELECT name, score
FROM table1 NATURAL JOIN table2
ORDER BY 2 ASC LIMIT 1
)
UNION ALL
(
SELECT name, score
FROM table1 NATURAL JOIN table2
ORDER BY 2 DESC LIMIT 1
)
If you are running MySQL 8.0, you can use window functions:
select t1.name, t2.score
from table1 t1
inner join (
select t2.*,
rank() over(order by score) rn_asc,
rank() over(order by score desc) rn_desc
from table2 t2
) t2 on t2.id = t1.id
where 1 in (rn_asc, rn_desc)
The idea is to rank records of table2 by increasing and decreasing score, and use that information for filtering. Note that this allows top and bottom ties.
I have 3 tables. I need to join those 3 and get 2 fields from each table. And there will be few where conditions. Where condition is for date range. Even if one table has the the result I need to show it along with other table data showing as 0.
I have tried using inner join. But what it does is taking only 1st where condition and if no result in first it will not go for next conditions. My table structures and required output are shown below.
table1
+--------+---------+------------+
| amount | site_id | date |
+--------+---------+------------+
| 10 | 1 | 12/12/2014 |
| 50 | 2 | 10/12/2014 |
| 30 | 3 | 05/11/2014 |
+--------+---------+------------+
table2
+--------+---------+------------+
| amount | site_id | date |
+--------+---------+------------+
| 100 | 1 | 2/11/2014 |
| 40 | 2 | 10/10/2014 |
| 30 | 3 | 05/11/2014 |
+--------+---------+------------+
table3
+--------+---------+------------+
| amount | site_id | date |
+--------+---------+------------+
| 60 | 1 | 12/12/2014 |
| 50 | 3 | 11/12/2014 |
| 70 | 4 | 05/09/2014 |
+--------+---------+------------+
output : total amounts between 01/12/2014 and 31/12/2014
+---------+---------------+---------------+---------------+-------+
| site_id | table1_amount | table2_amount | table3_amount | total |
+---------+---------------+---------------+---------------+-------+
| 1 | 60 | 0 | 60 | 120|
| 3 | 0 | 0 | 50 | 50 |
+---------+---------------+---------------+---------------+-------+
Can anyone suggest a query to get this output?
This is what I have done so far
select sum(table1.amount),sum(table2.amount),sum(table3.amount),(sum(table1.amount)+sum(table2.amount)+sum(table3.amount)) from table1 inner join table2 on table1.site_id=table2.site_id inner join table3 on table3.site_id=table2.site_id where table1.date>='01/12/2014' and table1.date<='31/12/2014' or table2.date>='01/12/2014' and table2.date<='31/12/2014' or table3.date>='01/12/2014' and table3.date<='31/12/2014' group by table1.site_id
Try this:
SELECT S.site_id,
IFNULL(t1.table1_Amount, 0) AS table1_Amount,
IFNULL(t2.table2_Amount, 0) AS table2_Amount,
IFNULL(t3.table3_Amount, 0) AS table3_Amount,
(IFNULL(t1.table1_Amount, 0) + IFNULL(t2.table2_Amount, 0) + IFNULL(t3.table3_Amount, 0)) AS total
FROM Site S
LEFT OUTER JOIN ( SELECT t1.site_id, SUM(t1.amount) AS table1_Amount
FROM table1 t1
WHERE t1.date >= '01/12/2014' AND t1.date <= '31/12/2014'
GROUP BY t1.site_id
) AS t1 ON S.site_id = t1.site_id
LEFT OUTER JOIN ( SELECT t2.site_id, SUM(t2.amount) AS table2_Amount
FROM table2 t2
WHERE t2.date >= '01/12/2014' AND t2.date <= '31/12/2014'
GROUP BY t2.site_id
) AS t2 ON S.site_id = t2.site_id
LEFT OUTER JOIN ( SELECT t3.site_id, SUM(t3.amount) AS table3_Amount
FROM table1 t3
WHERE t3.date >= '01/12/2014' AND t3.date <= '31/12/2014'
GROUP BY t3.site_id
) AS t3 ON S.site_id = t3.site_id;
I am creating an application for my school and I am in trouble constructing the right query.
I have 2 tables,table1 and table2.
table1
---------------------------------------------------------
| StudentID | SubjectID | Present | Type |
---------------------------------------------------------
| 2 | 3 | yes | 1 |
| 2 | 2 | yes | 2 |
| 3 | 1 | no | 3 |
---------------------------------------------------------
table2
---------------------------------------------------------
| SubjectID | SubjectName | Number1 | Number2 |
---------------------------------------------------------
| 1 | Name1 | 6 | 4 |
| 2 | Name2 | 4 | 8 |
| 3 | Name3 | 5 | 2 |
---------------------------------------------------------
SubjectID in table1 is foreign key references table2.
I want to build a query sql that gives me the StudentID`s from table1
that didnt miss any Type 3 subject (i.e no row like this
---------------------------------------------------------
| StudentID | SubjectID | Present | Type |
---------------------------------------------------------
| 3 | 1 | no | 3 |
---------------------------------------------------------
And have completed 75 percent of type 1 (i.e
I find it like this
SELECT t1.StudentID,t1.SubjectID ,t1.Type,t2.Number1 as num
FROM table1 as t1,table2 as t2
WHERE t1.Present=yes and t2.SubjectID=t1.SubjectID
GROUP BY StudentID,SubjectID
HAVING COUNT(*)/num >= 75/100
But I cant combine the two things together.
You can combine queries by giving them aliases and joining as subqueries...
SELECT finisher.StudentID FROM
(
SELECT DISTINCT StudentID
FROM table1 t1
JOIN table2 t2 ON t2.SubjectID = t1.SubjectID
WHERE t1.Present = 'yes' AND t1.Type1 = 1
GROUP BY t1.StudentID, t2.SubjectID
HAVING COUNT(*) / t2.Number2 >= 0.75
) finisher
JOIN
(
SELECT DISTINCT t1.StudentID
FROM table1 t1
LEFT JOIN
(
SELECT DISTINCT StudentID
FROM table1
WHERE Type = 3 AND Present = 'no'
) missed ON missed.StudentID = t1.StudentID
WHERE t1.Type = 3
AND missed.StudentID IS NULL
) notmissed ON finisher.StudentID = notmissed.StudentID
"StudentID`s from table1 that didnt miss any Type 3"... I assume here you don't want to include students without any type 3 rows.
Seems like this is done and duste, but how about...
SELECT x.*
FROM
( SELECT t1.StudentID
, t1.SubjectID
, t1.Type
, t2.Number1 num
FROM table1 t1
JOIN table2 t2
ON t2.SubjectID=t1.SubjectID
WHERE t1.Present='yes'
GROUP
BY t1.StudentID
, t1.SubjectID
HAVING COUNT(*)/num >= 0.75
) x
LEFT
JOIN table1 y
ON y.student_id = x.student_id
AND y.subject_id = x.subject_id
AND y.type = 3
AND y.present = 'no'
WHERE y.student_id IS NULL;