MySql query counting and assigning constants based on ranges - mysql

There's one table
MEMBERS:
id - member id,
dt_activate - member's join unix datetime,
id_inviter - member's id who did invite current member (0 if member joined on his own)
Trying to write a Select that would return the following multiple rows result, where each row would contain:
(1) id - member id;
(2) cnt - count of rows in MEMBERS table where this "id" appeared in id_inviter field and at the same time the dt_activate should be between constants dt_start and dt_end;
(3) img - "imageA.gif" if cnt is between 10-19, "imageB.gif" if between 20-29, "imageC.gif" if greater than 29;
(4) reward - constant X if cnt is between 10-19, Y if between 20-29, Z if greater than 29
Unfortunately my knowledge doesn't let me go past the simple selects like:
SELECT id_inviter, sum(1) AS cnt
FROM members
WHERE dt_activate>=$dt_start AND dt_activate<=$dt_end
GROUP BY id_inviter
HAVING cnt>=10
Estimated record count for MEMBERS table might be between 10-50k.
Please help to achieve the result described above, thank you.

Try this one:
SELECT id_inviter, count (*) AS cnt,
case when count (*) <20 then 'imageA.gif'
when count (*) <30THEN 'imageB.gif' else 'imageC.gif' end as image,
case when count (*) <20 then 'X'
when count (*) <30 THEN 'Y' else 'Z' end as reward
FROM members
WHERE dt_activate>=$dt_start AND dt_activate<=$dt_end
GROUP BY id_inviter
HAVING cnt>=10

Related

SQL Query to find whether a entry if greater than sum of average of whole column +standard deviation of whole column

Let's say I have a table with
student
Marks
john
30
ron
40
I have to write a query which gives me output as student name and avg(marks column)+standardeviation(marks column) or 0 , if student marks is greater than avg(marks column)+standardeviation(marks column) then avg(marks column)+standardeviation(marks column) else 0
I have written a query but it does not work
select student, case when marks>(select avg(marks)+stddev_pop(marks) from students) then avg(marks column)+standardeviation(marks column) when marks=(select avg(marks)+stddev_pop(marks) then marks else 0 end as final_marks from students
Please can anyone suggest any way
Close. Use window functions. And in MySQL, you don't need a case because booleans are supported:
select s.student,
(s.marks > avg(s.marks) over () + stddev_pop(s.marks) over ()) as final_marks
from students s;
In older versions of MySQL, I would recommend a subquery in the from clause:
select s.*,
(s.marks > ss.avg_marks + ss.stddev_pop_marks) as final_marks
from students s cross join
(select avg(s.marks) as avg_marks,
stddev_pop(s.marks) as stddev_pop_marks
from students
) ss

Average a column based upon the value in another column SQL

Suppose I have the following data
SqlUnixTime BID ASK VALID ASSET_ID
1504900871 101.50 101.6 Y XY1
1504900870 0 101.6 Y XY1
1504900871 101.50 20 N XY1
...
In the BID & ASK columns I can have a valid price, a 0 (meaning no data) or an invalid price (see the final row).
I'd like to compute a 30 day average. I have managed to handle the 0 case using the following query:
Select ASSET_ID, AVG(NULLIF(BID,0)) as AVG_BID_30D, AVG(NULLIF(ASK,0)) as AVG_ASK_30D FROM myDB.myTable where SqlUnixTime > 1504900870 GROUP BY ASSET_ID;
However, how would I only average those values where VALID = "Y". I thought about putting a where clause in the end but then it might not select asset_id that are invalid? I just want it to have a null?
UPDATED
group it by (ASSET_ID, VALID='Y') and then the resultant again group by VALID='Y'
I think it will work.
select A.ASSET_ID, A.AVG_BID_30D, A.AVG_ASK_30D
from (Select ASSET_ID, AVG(NULLIF(BID,0)) as AVG_BID_30D, AVG(NULLIF (ASK,0)) as AVG_ASK_30D, VALID
FROM myDB.myTable where SqlUnixTime > 1504900870
GROUP BY ASSET_ID, VALID='Y') as A
group by ASSET_ID='Y';
.

calculate percentage of distinct records depending on its 'status' using stored procedure

I have a table site_level,I need to work on columns named 'market',status, id.
for column market , I want to calculate percentage of id depending on its status as completion or rejection.
id column may have duplicate rows.so i need distinct rows.
Ex. market 'germany' will have several id's with status accepted or rejected.
i want to calculate percentage like (total distinct id for market germany)/ (distinct id with status as accepted for germany)
I need the query result in below format.
market / count__id_accepted / count_id_rejected/ percentage_accepted / percentage_rejected
select result1.market AS market,count(result1.unique_id) AS distinct unique_id,count(result1.status='accepted' or null) as'count_acc',count(result1.status='accepted' or null)*100/count(result1.unique_id) as 'perc_accepted',count(result1.status='rejected' or null) as 'count_rej',count(result1.status='rejected' or null)*100/count(result1.unique_id) as 'perc_rejected',
count(result1.status='to be performed' or null) as 'count_tbp',count(result1.status='to be performed' or null)*100/count(result1.unique_id) as 'perc_tbp',count(result1.status='incomplete test' or null) as 'count_inco',
count(result1.status='incomplete test' or null)*100/count(result1.unique_id) as 'perc_inco' from result1
group by result1.market

Why does the total from my query results not add up?

I have three queries that get stats from the database, but the total does not add up correctly for my results. If I do the math myself this is what I get: // 440728 / 1128 = 390.72
However, the following is what is returned by my queries:
SELECT * FROM facebook_accts
WHERE user_id IN (SELECT id FROM `user_accts` WHERE owner_id = '121')
// returns 1128
SELECT sum(friend_count) FROM facebook_accts
WHERE user_id IN
(SELECT id FROM `user_accts` WHERE owner_id = '121')
// returns 440728
SELECT avg(friend_count) FROM facebook_accts
WHERE user_id IN
(SELECT id FROM `user_accts` WHERE owner_id = '121')
// returns 392.11 (number formatted to two decimal places by php)
this may be happening because of column friend_count having some NULL values because SUM and AVG sunctions ignore NULL values. see here.
I guess the 1128 rows contain NULL values (which AVG and SUM ignore).

MySQL Complicated SELECT

I have a MySQL table (tbl_filters) with 3 columns: id, cat, val
id & val are numeric, cat is varchar. There are multiple rows for each id.
I also have another table (tbl_info) with multiple columns, including an id which corresponds to the id from tbl_filters. There is a column called name, which is what I'm looking for.
I would like to select the name of all the rows which match a set value for cat, but only if the val for cat is the maximum for this id, and only if it is above a minimum set val.
In pseudocode it would be something like:
SELECT tbl_info.name FROM tbl_info,tbl_filters
WHERE (tbl_info.id=tbl_filters.id) AND (cat="mycat") AND (val>=0.3)
AND (there are no other rows for this id in tbl_info with a higher value for val)
Example:
tbl_filters
id,cat,val
1 eg1 0.43
1 eg2 0.60
1 eg3 0.78
tbl_info
id name
1 MyName
In the above example, a value should only be returned if I am looking for the cat called eg3, since that has the highest value. For the other cats, nothing should be returned, since they are not the highest value.
Another option would be to make a column in tbl_info just for the cat with the highest value, but that is a messy solution I would prefer to avoid.
I THINK I'm following you... The INNER-MOST query pre-qualifies the HIGHEST Value per ID of your minimum value qualification, and the category that qualifies. ONCE you get that list, re-join back to get the name from the tbl_info. I've re-joined to the tbl_filters a second time in case there were other elements on that record you want, such as the date of the rate, or other things. If you DONT need that, you can ignore the second "tf2" join and just change the fields list from tf2.val to PreQualified.HighestQualVal.
select
ti.id,
ti.name,
tf2.val
from
( select
tf.id,
max( tf.val ) as HighestQualVal
from
tbl_filters tf
where
tf.cat = "mycat"
and tf.val >= 0.3
) PreQualified
JOIN tbl_info ti
on PreQualified.id = ti.id
JOIN tbl_filters tf2
on PreQualified.id = tf2.id
AND PreQualified.HighestQualVal = tf2.val
What about?
select ti.name, MaxId.maxVal from
(select tf1.id, tf1.cat, max(tf1.val) as maxVal from tbl_filters1 tf1
where tf1.cat = 'eg3' and tf1.val >= 0.0
group by tf1.id, tf1.cat) MaxCat
inner join (
select tf2.id, max(tf2.val) as maxVal from tbl_filters2 tf2
group by tf2.id) MaxId
on (MaxCat.id = MaxId.id and MaxCat.maxVal = MaxId.maxVal)
inner join tbl_info ti on MaxId.id = ti.id
Example here
Basically, and if I'm not wrong (again), I'm getting all the maximum val per each id and cat pair. Then get the maximum val for each id. If both match, i.e. if the max for the cat is the same as the max for the whole id, then I return the results.
Feel free to correct me if I'm wrong.