Count the "ratio?" for wins and losses - sql

I've already got this to work but it's a really bad approach and i need some help with factorization of my query.
SELECT `GameDate`,
COUNT(CASE
WHEN `P1Outcome`= 'win' AND P2Param = 'a' THEN 1
END) AS a_win,
COUNT(CASE
WHEN `P1Outcome`= 'loss' AND P2Param = 'a' THEN 1
END) AS a_loss,
COUNT(CASE
WHEN `P1Outcome`= 'win' AND P2Param = 'b' THEN 1
END) AS b_win,
COUNT(CASE
WHEN `P1Outcome`= 'loss' AND P2Param = 'b' THEN 1
END) AS b_loss
FROM games
WHERE `P2Param` IN ( 'a', 'b', 'c' )
GROUP BY GameDate
This will get me an query that i can use in my php application but i would like to skip having to make the actual ratio calculation in php and fetch it directly with SQL.
So basically what i've been trying to do is something similar to this:
COUNT(CASE
WHEN `P1Outcome`= 'win' AND P2Param = 'a' THEN 1 Else -1
END) AS a_ratio,
But just as the beginer i'm, i can't figure it out how i can make this to work.
EDIT:
Sorry for not explaining my regards in more details, here is the thing. I'm creating an statistics component and i need to fetch the ratio for a period of time in order to display it as an graph. So the following things are required:
GameDate (1,2,3,4... days ago)
The ratio for the player based on to different params (maps in this case)
So in short this is what i got at the moment:
GameDate a_win a_loss b_win b_loss
2011/04/25 x x x x
2011/04/23 x x x x
....
So everything works out great, but i would like to have the actual ratio calculation made in SQL because at the moment i need to make it in php e.g $ratio = $q[a_win]-$q[a_loss] and due to the fact that I've a lot of different param my query is like double the size because i need to fetch both the win and loss instead of just the ratio like i want in the first place.

SELECT `GameDate`,
SUM(CASE `P2Param`
WHEN 'a' THEN CASE P1Outcome WHEN 'win' THEN 1 ELSE -1 END
ELSE 0
END) AS a_ratio,
SUM(CASE `P2Param`
WHEN 'b' THEN CASE P1Outcome WHEN 'win' THEN 1 ELSE -1 END
ELSE 0
END) AS b_ratio
FROM games
WHERE `P2Param` IN ( 'a', 'b', 'c' )
GROUP BY GameDate

What is very important COUNT just returns number of rows regardless of what you count unless you use COUNT(DISTINCT ...) which in turn returns count of distinct values. To sum up some values which you produce for every row use SUM(...). Make sure what happens in your DBMS when an expression in the SUM() function evaluates to NULL - some databases will just make the whole SUM return NULL.
To get ratio of any kind of data you can do:
select _date_, (SUM(case when _your_test_ then 1 else 0 end) / count(1)) as ratio
from _yout_table_
group by _date_
And if you just want to calculate a sum of some values:
select _date_, SUM(case when _your_test_ then 1 else 0 end) as number_of_something
from _yout_table_
group by _date_

What about:
SELECT COUNT(id), P1Outcome, P2Param
FROM games
GROUP BY P2Param, P1Outcome
It will returns you a resultset with 3 columns:
counted values for param and outcome
outcome
param
With that you can do more in my opinion.

SELECT GameDate, P2Param, SUM(CASE WHEN P1Outcome = 'win' THEN 1 ELSE -1 END) AS ratio
FROM games
GROUP BY GameDate, P2Param

Related

SQL or operator how to use with having

i have a table which i am joining with with operator. I can have 2 combinations id that table FDEL - 1 or 0 and FDVE 1 or 0, what i would like to do is to dispay if - item has fdve, or item has fdel (and count) but it doesnt work (i can see all fdve, or all fdel)
select
lpad(purchase_id,10,0) as purchase_id,
sum(has_label_fdel) as FDEL_count,
case when LABELS like '%FDVE%' then 1 else 0 end as HAS_LABEL_FDVE,
sum(has_label_fdve) as FDVE_count
from
"SRC_ORACLEIWP"."PURCHASE_ANALYSIS_RULES"
group by
lpad(purchase_id,10,0),has_label_fdve
having FDVE_count>0 -- FDEL_count>0
You want one resut row per product, so group by product only. Use SUMfor counting and MAX for the aggregated yes/no.
select
lpad(purchase_id,10,0) as padded_purchase_id,
max(has_label_fdve) as has_labels_fdve,
sum(has_label_fdve) as fdve_count,
max(has_label_fdel) as has_labels_fdel,
sum(has_label_fdel) as fdel_count
from src_oracleiwp.purchase_analysis_rules
group by padded_purchase_id
having has_labels_fdve = 1
or has_labels_fdel = 1
order by padded_purchase_id;
I've changed your alias names slightly, so they are digfferent from the columns you have (because such ambiguities can sometimes lead to problems).
The check on labels like '%FDVE%' is unnecessary, because you already have the has_label_fdve flag, which is always 0 or 1. Or so it seems. If the flags can be null, use COALESCE on them or do use LIKE expressions.
If you don't have has_label_fdve and has_label_fdel yet, use the labels column instead:
select
lpad(purchase_id,10,0) as padded_purchase_id,
max(case when labels like '%FDVE%' then 1 else 0 end) as has_labels_fdve,
sum(case when labels like '%FDVE%' then 1 else 0 end) as fdve_count,
max(case when labels like '%FDEL%' then 1 else 0 end) as has_labels_fdel,
sum(case when labels like '%FDEL%' then 1 else 0 end) as fdel_count
from src_oracleiwp.purchase_analysis_rules
group by padded_purchase_id
having has_labels_fdve = 1
or has_labels_fdel = 1
order by padded_purchase_id;

GROUP BY SUM CASE expression

I want to group by account number, but I am running into problems if I get multiple RATE_CD's for an account - I get a NONCOMPLIANT_CNT of 2, but I want it to be only 1 per account even if there is more than 1 RATE_CD.
Below is the SQL I'm playing around with, any ideas on how I can return the NONCOMPLIANT_CNT per account, and not roll up the count if there is more than 1 RATE_CD?
SELECT ID
,ACCOUNT_NBR SUM(CASE
WHEN GROUP_CD = 'RED'
AND TYPE_CD IN ('CHK')
THEN 1
ELSE 0
END) AS 'COMPLIANT_CNT'
,SUM(CASE
WHEN GROUP_CD = 'RED'
AND TYPE_CD IN (
'CN'
,'RN'
)
AND RATE_CD <> 'BLK'
THEN 1
ELSE 0
END) AS 'NONCOMPLIANT_CNT'
,SUM(CASE
WHEN GROUP_CD = 'RED'
AND TYPE_CD IN (
'CN'
,'RN'
,'CHK'
)
THEN 1
ELSE 0
END) AS 'TOTAL_CNT'
FROM DETAIL
LEFT OUTER JOIN RATE_LOOKUP ACCOUNT_NBR = ACCOUNT_NBR
GROUP BY ID
,ACCOUNT_NBR
,RATE_CD
If you only want 1 instead of how many actual, change your SUM() to MAX(). So if they have 5 entries, it would still show as at least 1, otherwise will be 0 for the given column aggregate.

Calculate Win/Loss Streak Query

I'm trying to find a way to calculate win/loss streak for a user. My table has a field defined as "W/L" and each win is entered as "W" and each loss is entered as "L" Here is what the current table looks like:
ID Result
1 L
2 W
3 W
4 W
Here is an example I found, seems pretty straight forward but I'm apparently missing an operator though. Not sure what I'm missing.
SELECT SUM(CASE WHEN Result = 'W' THEN 1 ELSE 0 END) as Wins,
SUM(CASE WHEN Result = 'L' THEN 1 ELSE 0 END) as Losses
FROM Table1
Is it best to create a query for this or more suited for a VBA type function?
You can use something like,
SELECT
Sum(IIF(Result = 'W', 1, 0)) As TotalWins,
Sum(IIF(Result = 'L', 1, 0)) As TotalLooses
FROM Table1;

nested SQL queries on one table

I am having trouble formulating a query to get the desired output.
This query involves one table and two columns.
First column bld_stat has 4 different values Private, public, Public-Abandoned, Private-Abandoned the other column bld_type, single_flr, multi_flr, trailer, Whs.
I need to get results that look like this:
So far I can get the first two columns but after that I have not been able to logically get a query to work
SELECT bld_stat, COUNT(grade) AS single_flr
FROM (SELECT bld_stat,bld_type
FROM bld_inventory WHERE bld_type = 'single_flr') AS grade
GROUP BY bld_stat,bld_type,grade
The term you are going for is pivoting. I think this should work...no need for the subquery, and I've changed your group by to only bld_stat
SELECT bld_stat,
sum(case when bld_type = 'singl_flr' then 1 else 0 end) AS single_flr,
sum(case when bld_type = 'multi_flr' then 1 else 0 end) AS multi_flr,
sum(case when bld_type = 'trailer' then 1 else 0 end) AS trailer,
sum(case when bld_type = 'whs' then 1 else 0 end) AS WHS
FROM bld_inventory
GROUP BY bld_stat

Query to get percent of a total using select(count)

I'm calculating the change in pain between day 1 and day 2.
There are two fields, Pain_Admit_Comfort and Pain_48_Hr_Comfort, the options in each is Yes/No.
I need to find everyone that had pain on Admit and is More Comfortable 2 days later.
This is the query. The first two statements return correct numbers. I can't figure out how to divide using the same statements as numerator and denominator.
select
(select COUNT (PAIN_48_HR_COMFORT_C)
FROM CASES WHERE PAIN_48_HR_COMFORT_C='Yes') as Forty_Eight_Hours,
(SELECT COUNT (PAIN_ADMIT_COMFORT_C)
FROM CASES WHERE PAIN_ADMIT_COMFORT_C='YES') as Admit_Uncomfort_Yes,
((select COUNT (PAIN_48_HR_COMFORT_C)
FROM CASES WHERE PAIN_48_HR_COMFORT_C='Yes')
/
(SELECT COUNT (PAIN_ADMIT_COMFORT_C)
FROM CASES WHERE PAIN_ADMIT_COMFORT_C='YES')) AS Percent_Changed
from CASES
Thanks
I don't spot any immediate problems with your statement but following statement should return the correct results and is perhaps a bit easier to read.
SELECT feh.Forty_Eight_Hours
, auy.Admit_Uncomfort_Yes
, Percent_Changed = CAST(feh.Forty_Eight_Hours AS FLOAT) / auy.Admit_Uncomfort_Yes
FROM (
SELECT Forty_Eight_Hours = COUNT(PAIN_48_HR_COMFORT_C)
FROM CASES
WHERE PAIN_48_HR_COMFORT_C = 'Yes'
) feh
CROSS APPLY (
SELECT Admit_Uncomfort_Yes = COUNT (PAIN_ADMIT_COMFORT_C)
FROM CASES
WHERE PAIN_ADMIT_COMFORT_C = 'Yes'
) auy
Your query, and the other answers, are very inefficient (multiple selects).
What you want is called a "pivot", and the most efficient way of coding it using just one select over the table (your query uses 4) is as follows:
select
sum(case when PAIN_48_HR_COMFORT_C = 'Yes' then 1 else 0 end) as Forty_Eight_Hours,
sum(case when PAIN_ADMIT_COMFORT_C = 'Yes' then 1 else 0 end) as Admit_Uncomfort_Yes
sum(case when PAIN_ADMIT_COMFORT_C = 'Yes' AND PAIN_48_HR_COMFORT_C = 'NO' then 1 else 0 end) as Improved_pain
FROM CASES
I'm not sure what the columns mean - you may need to change a 'YES' to 'NO' etc to get the "has"/"has not" pain correct.