MySQL moving average calculation - mysql

How can i edit the ON operator part of my query below such that i would like the current code to work where id<=14 (which is t2.id <= t1.id as shown below) so when t1 id =14, t2 is the cumulative id from 1 to 14 (as it is now).
but for id >14 I would like the ON operator to be (t2.id=t1.id>=t1.id-2 and <=t1.id) so when t1 id=15, t2.id should be between 13 and 15. when t1 id =16, t2.id should be between 14 and 16 and so on.
I'm doing this because when i calculate col E for ids after id=14, i am only interested in getting the average of the previous 2 rows for C and D on a moving average.
My query has 2 sub queries and it updates column E. The table looks like this:
--------------------------
id | A | B | E |
--------------------------
1 | NULL | NULL |NULL|
--------------------------
2 | 4 | 6 |NULL|
--------------------------
3 | 6 | 9 |NULL|
--------------------------
This is my query where i got help from this link: Mysql Nested sub queries unknown column error
Update t join
(SELECT t1.id ,ifnull(t1.A/AVG(t2.A),0) C ,ifnull(t1.B/AVG(t2.B),0) D
FROM t t1
JOIN t t2
ON t2.id <= t1.id
group by t1.id ) AS tt
on(t.id = tt.id)
SET E = (tt.C + tt.D)/2;
Thanks,

where id<=14 (which is t2.id <= t1.id as shown below) so when t1 id =14, t2 is the cumulative id from 1 to 14 (as it is now).
Update t join
(
SELECT t1.id ,ifnull(t1.A/AVG(t2.A),0) C ,ifnull(t1.B/AVG(t2.B),0) D
FROM t t1
JOIN t t2
ON case when t2.id < 15 then t2.id <= t1.id else t2.id=t1.id>=t1.id-2 and <=t1.id end
group by t1.id
) tt on(t.id = tt.id)
SET E = (tt.C + tt.D)/2;

Related

Mysql Left Outer Join on 3 tables failing

I have 3 tables in my Mysql DB as follows:
daily_data_update:
----------------------------------------------
id date code user_id followup_status
----------------------------------------------
1 08/10/2020 AD123 1 1
2 08/10/2020 AD134 2 2
3 08/10/2020 AD123 1 1
---------------------------------------------
users:
-------------------------------------
id first_name user_region
------------------------------------
1 Peter scotland
2 Susan ireland
------------------------------------
followupstatus
------------------------------------
id followup_status
---------------------------------------
1 Paid
2 Unpaid
----------------------------------------
I need to select date,code and followup_status from daily_data_update WHERE user_id in users along with followup_status. My query is as follows:
SELECT t1.`date`,
t1.`code`,
t3.`followup_status`
FROM `daily_data_update` AS t1,
followupstatus AS t3
LEFT OUTER JOIN users AS t2 ON t1.user_id = t2.id
WHERE t2.id IS NOT NULL
AND t2.user_region = 'scotland'
But the query is failing as Unknown column 't1.user_id' in 'on clause'
What is wrong with my query and how can i resolve it ?? Requesting help..
Try this query:
SELECT t1.`date`,
t1.`code`,
t3.`followup_status`
FROM `daily_data_update` AS t1
LEFT JOIN followupstatus AS t3 ON t1.followup_status = t3.id
LEFT JOIN users AS t2 ON t1.user_id = t2.id
WHERE t2.id IS NOT NULL
AND t2.user_region = 'scotland'
Hope this works!!

SQL Combining data from 3 tables to from a 4th table based on some conditions

I have 3 tables:-
table1 :-
ReportType | ResourceId
t2 123
t3 5
table2:-
Id | Name | Created
1 A 10
2 B 11
123 C 12
table3:-
Id | Name | Created
4 D 13
5 E 14
6 F 15
table1's ResourceId and table2 and 3's Id column have same values
I want to create a 4th table like this:-
ReportType | ResourceId | Name | Created
t2 123 C 12
t3 5 E 14
such that wherever table1's ReportType is t2 I want the Name and Created value from table2 for the condition table1.ResourceId = table2.Id and wherever table1's ResourceType is t3 I want the Name and Created value from table3 for the condition table1.ResourceId = table3.Id.
PS: This isn't some sort of HomeWork. I have been stuck at this query for the past 1 hour, I have read various answers and tried a few queries of my own before posting the question. Any help would really be appreciated.
Explanation in comments :)
--here we join first and second table, but we filter results to include only ReportType = t2
select t1.ReportType, t1.ResourceId, t2.Name, t2.Created from table1 as t1 join table2 as t2 on t1.ResourceId = t2.id
where t1.ReportType = 't2'
union all
--here we join first and third table, but we filter results to include only ReportType = t3
select t1.ReportType, t1.ResourceId, t3.Name, t3.Created from table1 as t1 join table3 as t3 on t1.ResourceId = t3.id
where t1.ReportType = 't3'
You can use the below query:
select report_type, resourceid,name, created from dbo.t2, dbo.t1
where report_type='t2' and ResourceId=id
UNION
select report_type, resourceid,name, created from dbo.t3, dbo.t1
where report_type='t3' and ResourceId=id;

MySQL merge two tables with different data

The following are my mysql tables
Table 1:
ID | commonID | Date | text | active
1 11 01.02 abc 1
2 11 02.02 123 1
3 11 03.02 xyz 0
Table 2:
ID | commonID | Date | value | active
1 11 01.02 abc 1
2 11 04.02 123 1
3 11 03.02 xyz 1
The Final result should display this:
| date | text | value
01.02 abc abc
02.02 123 (null)
03.02 (null) xyz
04.02 (null) 123
The Idea here is, to merge the two tables. All entries with a defined commonID like 11 in the example will be selected from both tables. then the tables will be united.
Conditions:
If there are matching dates in TABLE1 and TABLE2 they will be merged
If there is a solo date in TABLE1 or TABLE2, the value/text for the table with no date will become NULL
If there is a record in TABLE1 or TABLE2 that has active = FALSE, it will not be processed.
There can be matching and not matching dates in BOTH tables.
I want to use this for display chronologic events, if there is an event in both tables, there should be only one line for this.
What could be the Solution here?
Try this:
SELECT T1.date,
CASE WHEN T1.active = 1 THEN T1.text END as text,
CASE WHEN T2.active =1 THEN T2.value END as value
FROM Table1 T1 LEFT JOIN
Table2 T2 ON T1.date=T2.date
UNION
SELECT T2.date,
CASE WHEN T1.active = 1 THEN T1.text END as test,
CASE WHEN T2.active = 1 THEN T2.value END as value
FROM Table1 T1 RIGHT JOIN
Table2 T2 ON T1.date=T2.date
Result:
DATE TEXT VALUE
01.02 abc abc
02.02 123 (null)
03.02 (null) xyz
04.02 (null) 123
Sample SQL Fiddle.
Try this:
SELECT t1.date,t1.text,t2.value FROM table1 t1
LEFT JOIN table2 t2 ON t1.commonId = t2.commonId and t1.date = t2.date and t2.active = 1
where t1.active = 1
UNION
SELECT t2.date,t1.text,t2.value FROM table2 t2
LEFT JOIN table1 t1 ON t1.commonId = t2.commonId and t1.date = t2.date and t1.active = 1
where t2.active = 1
Sample http://sqlfiddle.com/#!2/d2c4d/2
Here's one way...
SELECT commonid
, date
, MAX(text) text
, MAX(value) value
FROM
( SELECT id
, commonid
, date
, text
, NULL value
, active
FROM table1
WHERE active <> 0
UNION
SELECT id
, commonid
, date
, NULL
, value
, active
FROM table2
WHERE active <> 0
) x
GROUP
BY commonid,date;
You can move the WHERE active <> 0 bit out of the UNIONs if you like, to just before the GROUP BY.

Complex query over two tables

I have two tables:
table1:
id
--
1
2
3
table2: (left out primary index)
id2 | cond
----------
3 | 1
3 | 0
2 | 1
2 | 1
2 | 0
I would need to construct a query that implicitly calculates this intermediary table:
temp:
id | c1 | c2
------------
1 | 0 | 2
2 | 2 | 2
3 | 1 | 2
with c1 = countRows(id2 == id && cone == 1) and c2 == countRows(id2 = 2 && cond == 1).
and then selects SELECT id FROM temp ORDER BY ABS(c1 - c2)*RAND().
My current try is kind of like:
SELECT id, COUNT(t1.id2) AS c1, COUNT(t2.id2) AS c2
FROM table1 LEFT JOIN (table2 AS t1) ON id=t1.id2 LEFT JOIN (table2 AS t2) ON t2.id2=2
WHERE t1.cond=1 AND t2.cond=1
GROUP BY t1.id2
ORDER BY ABS(c1 - c2)*RAND()
LIMIT 1
Which has multiple problems:
It doesn't select rows with no entry in table2
It doesn't correctly count
There seems to be a problem with group columns (c1, c2) in the ORDER BY part 3.
Help would be appreciated.
Update:
table1 represents players for example
table2 would be rounds played, with cond indicating a win
c1 represents the rounds won by each player
c2 represents the rounds won by a reference player (player 2 in this case)
SELECT t1.id, SUM(IFNULL(t2.cond, 0) = 1) AS c1, (SELECT SUM(cond = 1) FROM table2 WHERE id2 = 2) AS c2
FROM table1 t1
LEFT JOIN table2 t2 ON t1.id = t2.id2
GROUP BY t1.id
ORDER BY ABS(SUM(IFNULL(t2.cond, 0) = 1) - c2) * RAND();
Let's see if the first part of your query is returning valid results..
SELECT
t1.id AS id
COUNT(t2.id2) AS c1
COUNT(CASE WHEN t3.id2 = 2 THEN t3.id2 ELSE NULL END) as c2
FROM
table1 AS t1
LEFT JOIN table2 as t2
ON t1.id = t2.id2 AND t2.cond = 1
LEFT JOIN table2 as t3
ON t3.id2 = 2 AND t3.cond = 1
GROUP BY
t2.id2,
t3.id2
Can you provide schema?

MySQL moving average calculation using CASE

How can i edit the ON operator part of my query below such that i would like the current code to work where id<4 (which is t2.id <= t1.id as shown below) so when t1 id=3, t2 is the cumulative id from id=1 to id=3 (as it is now).
but for id >3 I would like the ON operator to be (t2.id=t1.id>=t1.id-2 and <=t1.id) so when t1 id=4, t2.id should be between 2 and 4 inclusive. when t1 id =5, t2.id should be between 3 and 5 inclusive and so on.
I'm doing this because when i calculate col E for ids after id=3, i am only interested in getting the average of the previous 2 rows for C and D on a moving average.
Iam translating my excel formula into SQL so i know what is the correct values for col E.
My query has 2 sub queries and it updates column E. The table and correct data in EXCEL looks like this:
id A B C D E
1 NULL NULL NULL NULL NULL
2 4 6 1 1 1
3 6 9 1.2 1.2 1.2
4 8 7 1.33 0.954 1.143
5 10 5 1.25 0.714 0.982
6 12 2 1.2 0.428 0.814
http://www.sqlfiddle.com/#!2/17a0ad/1
EXCEL formulas (notice that the formulas change after id=3 to a moving average):
id C D E
2 =A2/AVERAGE(A1:A2) =B2/AVERAGE(B1:B2) =(C2+D2)/2
3 =A3/AVERAGE(A1:A3) =B3/AVERAGE(B1:B3) =(C3+D3)/2
4 =A4/AVERAGE(A2:A4) =B4/AVERAGE(B2:B4) =(C4+D4)/2
5 =A5/AVERAGE(A3:A5) =B5/AVERAGE(B3:B5) =(C5+D5)/2
6 =A6/AVERAGE(A4:A6) =B6/AVERAGE(B4:B6) =(C6+D6)/2
Here is my SQL query:
Update followers join
(
SELECT t1.id ,ifnull(t1.A/AVG(t2.A),null) C ,ifnull(t1.B/AVG(t2.B),null) D
FROM followers t1
JOIN followers t2
ON
case when t2.id < 4 then t2.id <= t1.id else t2.id<= t1.id and t2.id>=t1.id-2 end
group by t1.id
) AS tt on(followers.id = tt.id)
SET E = (tt.C + tt.D)/2;
Although this query works, the numbers that i want for col E are not exactly correct. They are correct only for id<=4 but not for id=5 or id=6 in col E.
I believe my syntax for CASE by the ON operator might be wrong.
I ran this query in sql fiddle and got this result:
ID A B E
1(null)(null)(null)
2 4 6 1
3 6 9 1.2
4 8 7 1.14
5 10 5 1.08
6 12 2 0.92
As we can see, the excel and sql output are different.
Thanks,
I think the query that you want is a very slight modification:
Update followers join
(SELECT t1.id, ifnull(t1.A/AVG(t2.A),null) as C, ifnull(t1.B/AVG(t2.B),null) as D
FROM followers t1 JOIN
followers t2
ON (case when t1.id < 4 then t2.id <= t1.id
----------------------------^
else t2.id<= t1.id and t2.id>=t1.id-2
end)
group by t1.id
) tt
on followers.id = tt.id
SET E = (tt.C + tt.D)/2;
You can express the on using basic boolean logic as:
on t2.id <= t1.id and (t1.id < 4 or t2.id >= t1.id - 2)