MAX with extra criteria - mysql

I have the following part of a query I'm working on in MYSQL.
SELECT
MAX(CAST(MatchPlayerBatting.BatRuns AS SIGNED)) AS HighestScore
FROM
MatchPlayerBatting
It returns the correct result. However there is another column I need it to work off.
That is if the maximum value it finds also has a value of "not out" within "BatHowOut", it should show the result as for example 96* rather than just 96.
How could this be done?
To help make the data concrete, consider two cases:
BatRuns BatHowOut
96 not out
96 lbw
BatRuns BatHowOut
96 not out
102 lbw
For the first data, the answer should be '96*'; for the second, '102'.

You can achieve this using self-join like this:
SELECT t1.ID
, CONCAT(t1.BatRuns,
CASE WHEN t1.BatHowOut = 'Not Out' THEN '*' ELSE '' END
) AS HighScore
FROM MatchPlayerBatting t1
JOIN
(
SELECT MAX(BatRuns) AS HighestScore
FROM MatchPlayerBatting
) t2
ON t1.BatRuns = t2.HighestScore
See this sample SQLFiddle with highest "Not Out"
See this another sample SQLFiddle with highest "Out"
See this another sample SQLFiddle with two highest scores

How about ordering the scores in descending order and selecting only the first record?
select concat(BatRuns , case when BatHowOut = 'not out' then '*' else '' end)
from mytable
order by cast(BatRuns as signed) desc,
(case when BatHowOut = 'not out' then 1 else 2 end)
limit 1;
Sample here.
If you want to find highest score score for each player, here is a solution that may not be elegant, but quite effective.
select PlayerID,
case when runs != round(runs)
then concat(round(runs),'*')
else
round(runs)
end highest_score
from (select PlayerID,
max(cast(BatRuns as decimal) +
case when BatHowOut = 'not out' then 0.1 else 0 end
) runs
from MatchPlayerBatting
group by PlayerID) max_runs;
This takes advantage of the fact that, runs can never be fractions, only whole numbers. When there is a tie for highest score and one of them is unbeaten,
adding 0.1 to the unbeaten score will make it the highest. This can be later removed and concatenated with *.
Sample here.

Related

To get total count based on condition

I am struggling to get the count of a particular person. As I am new to tableau I don't know how to write the condition for this query.
SELECT COUNT(*) as cnt
FROM
Expert_CollaborationsRequests
WHERE
ExpertID=3 AND
IsAccepted = 1
Generate a calculated field as:
Calculation1: IF ExpertID=3 AND IsAccepted = 1 THEN 1 ELSE 0 END
Then, place this field on a shelf (row, columns, etc.) and select Measure (Sum).
You can use LOD (Level of Detail) like so:
{ FIXED [ExpertID]: SUM(IF [IsAccepted]= 1 THEN 1 ELSE 0 END) }
This will give you aggregated values for each user.
For more information on LOD, please follow official Tableau help link here
SELECT COUNT(ExpertID),COUNT(IsAccepted ) as cnt
FROM
Expert_CollaborationsRequests
WHERE
ExpertID=3 OR
IsAccepted = 1

how to know the source table from a complex sql query

PFB the query in which I want know the actual table where I can find these (pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK )....
select count(1),pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK from
(SELECT vw1.pin_ein, vw1.engineer_pin,
vw1.transaction_date, vw1.effective_week,
vw1.stores_tools_cost,
(vw1.stores_total_cost - vw1.stores_tools_cost
) stores_total_cost_excl_tools,
vw1.item_count, vw1.stores_visit_count,
CASE
WHEN vw1.stores_total_cost <
5
THEN vw1.stores_visit_count
END stores_low_cost_visit_count,
vw1.actual_ouc ouc, er.eng_name engineer_name,
CASE
WHEN c.home_parked IS NOT NULL
THEN c.home_parked
ELSE 'N'
END home_parker,
CASE
WHEN c.home_parked IS NOT NULL
THEN c.commute_time
ELSE -99
END commute_time,
vw1.stores_com_cost ---v9.3---
FROM (SELECT pin_ein, engineer_pin, actual_ouc,
transaction_date, effective_week,
NVL
(SUM
(CASE
WHEN ( cow LIKE '%TOOL%'
OR cow LIKE
'%TOOLE%'
)
THEN transaction_value
END
),
0
) stores_tools_cost,
SUM
(transaction_value
) stores_total_cost,
SUM (transaction_quantity)
item_count,
COUNT
(DISTINCT sta_code
) stores_visit_count,
NVL
(SUM
(CASE
WHEN cow in (SELECT cow FROM orbit_odw.stores_cow_ref)
THEN transaction_value
END
),
0
) stores_com_cost ---v9.3---
FROM orbit_odw.stores_transaction_dtls
WHERE effective_week BETWEEN 201543
AND 201610
/***Ver 6.0---last 13 weeks data to be considered***/
AND transaction_date
BETWEEN to_date('19-10-2015','dd-mm-yyyy')
AND to_date('06-03-2016','dd-mm-yyyy')
/***Ver 6.0---last 13 weeks data to be considered***/
GROUP BY pin_ein,
engineer_pin,
actual_ouc,
transaction_date,
effective_week) vw1,
(SELECT *
FROM orbit_odw.dim_wms_rmdm
WHERE current_status = 1) er,
(SELECT engineer_ein, commute_time,
home_parked
FROM orbit_odw.eng_parking_at_home_dtls
WHERE rec_end_date > SYSDATE
AND home_parked = 'Y') c
WHERE TO_CHAR (vw1.pin_ein) = er.ein
AND vw1.pin_ein = c.engineer_ein(+)) group by pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK having count(1)>1;
Please help..
thanks in advance
Basically if i understand your problem correctly. You need to understand from where your outer SELECT is fetching data. So there is a simple rule set used to get these data. Steps are as follows.
Check the column output i.e in your case it's
pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK
Check the inline view or table from which your outer query is
fetching the data. In your case its the only inline view you have
used --> So bit easy to identify :P
Now to identify how your inline view VW1 is populating data. In your
case table orbit_odw.stores_transaction_dtls is used to populate the
required fields.
Hope this much information is required. Also for simple queries you can always go to ALL_TAB_COLUMNS system tables to identify a table's column easily.

summation in mysql does not work properly and returns 0

I have a sql query as follow:
but the problem is that if the the second select staement with dataitem=3 returns null then the whole calculation becomes 0. For example for first select I have 100 and for second it returns null. Adding them should result 100 but it gives back 0!!!!!
can anyone say the reason and also what to do to get rid of that?
Here is also copiable code:
select( (
SELECT sum(Sentiment)
FROM entity_epoch_data
WHERE EpochID IN
(SELECT ID
FROM epoch
WHERE StartDateTime>='2013-11-1'
AND EndDateTime<='2013-11-30')
AND EntityID =86
AND DataitemType=0
)+
(SELECT sum(Sentiment)
FROM entity_epoch_data
WHERE EpochID IN
(SELECT ID
FROM epoch
WHERE StartDateTime>='2013-11-1'
AND EndDateTime<='2013-11-30')
AND EntityID =86
AND DataitemType=3)
)
Just add to the SQLs that represent values the IFNULL command like IFNULL((select sum()......), 0) it should work fine.
But a little peace of advice. You should improve that query.
I beleave that this query you do the same thing.
SELECT sum(entity_epoch_data.Sentiment)
FROM entity_epoch_data INNER JOIN epoch
ON entity_epoch_data.EpochID = epoch.id
WHERE epoch.StartDateTime>='2013-11-1'
and epoch.EndDateTime<='2013-11-30'
AND entity_epoch_data.EntityID =86
and entity_epoch_data.DataitemType in (0,3)
You are summing the sums of the DataitemType 3 and 0 it just can be one query with a join
Use CASE statements instead of the statements you're using.
select sum(case when StartDateTime>='2013-11-1' and EndDateTime<='2013-11-30' and DataitemType=0 then Sentiment else 0 end) as Sentiment_0, sum(case when StartDateTime>='2013-11-1' and EndDateTime<='2013-11-30' and DataitemType=3 then Sentiment else 0 end) as Sentiment3 from (tables_joined) where EntityID =86
Adding null is undefined and therefore returns null or 0. You can use a CASE expression to avoid that problem.
SELECT SUM(CASE null = sentiment THEN 0 ELSE sentiment END) FROM ....
If your DB does not support CASE inside the SUM() function create a VIEW that uses CASE to substitute the null values with 0.

Separating/Sorting single column values into several columns using case function

I have two tables that I want to join and split with a case function depending on the values in one of the columns. (I know, sounds weird so let me explain)
It's a process where I run separate batches. Every batch has several samples that are measured in instances of voltage readings in several locations. My two tables looks like this:
Sample Readings
id id
BatchesID SampleID
... voltage
... location
When a batch is run, it takes one sample at a time and for every location (25 locations) it takes about 20 readings of the voltage before moving on to the next one.
I want to look at one batch at a time, and for every Sample.id, I want to gather the AVG(voltage) for all the locations. My table for Readings turns out like:
SampleID location voltage
1 1 5.23
1 1 4.53
... ... ...
1 25 7.89
2 1 4.96
2 1 5.04
... ... ...
2 25 6.09
...
But I want it to look like:
SampleID avg_v_for_1 avg_v_for_2 ... avg_v_for_25
1 4.73 5.24 ... 6.35
2 3.87 4.76 ... 9.32
... ... ... ... ...
200 6.73 3.87 ... 8.23
Basically, what I want to do is for every separate sample, I want to take the average voltage for all the measurements in every location and put in on a single row. What my current syntax looks like is this:
SELECT Readings.SampleID, Sample.BatchesID
(case when location = '1' then AVG(voltage) else 0 end) avg_v_for_1,
(case when location = '2' then AVG(voltage) else 0 end) avg_v_for_2,
...
(case when location = '25' then AVG(voltage) else 0 end) avg_v_for_25
FROM DB.Readings
INNER JOIN Sample
ON Readings.SampleID = Sample.id
WHERE Sample.BatchesID = 'specific_batch_id'
GROUP BY Readings.location, Sample.id;
The problem is that this generates the following table:
SampleID avg_v_for_1 avg_v_for_2 ... avg_v_for_25
1 4.73 0 ... 0
1 0 4.76 ... 0
1 0 0 ... 6.73
2 3.87 0 ... 0
2 0 4.83 ... 0
...
How can I get MySQL to gather ALL the average values for EVERY location on a SINGLE row? I have tried removing the group by location and only group by sampleID but then I only get the values for the first location and everything else becomes 0.
Any help is appreciated, thank you!
I add another answer with explanation how the the query with AVG(case ..when ... then..end) works, and why the version with case ... when ... then AVG(..) end doesn't give expected results.
The first remark: the ANSI SQL standard for group by queries is the following:
SELECT column1, column2, ... column_n, aggregate_function (expression)
FROM tables
WHERE predicates
GROUP BY column1, column2, ... column_n;
where aggregated_function can be a function such a: SUM, MAX, MIN, COUNT, AVG
There are several rules (restrictions) for the GROUP BY CLASUE, see this link for details: http://etutorials.org/SQL/Mastering+Oracle+SQL/Chapter+4.+Group+Operations/4.2+The+GROUP+BY+Clause/
one of them says that:
GROUP BY clause must include all nonaggregate expressions
It means, that all columns in SELECT clause must be listed in the GROUP BY clause,
for example this query:
SELECT col1, col2, AVG( expression )
FROM table
GROUP BY col2
is wrong, because col1 is not listed in the GROUP BY clause, and this query won't work on all databases (Oracle, Postgresql, MS-SQL etc.) - except MySql (why - I'll tell about it later).
The expression within the aggregated function can refer to all columns of the table, regardless of the column is listed in the GROUP BY clause or not.
Because of the above the query:
SELECT Readings.SampleID,
(case when location = '1' then AVG(voltage) else 0 end) avg_v_for_1
....
GROUP BY sampleId
simply won't work on all databases that are compliant with ANSI SQL, this query will give a syntax error because location is out of AVG function, but is not listed in the GROUP BY clause.
The question - why this query works on MySql ?
Because MySql implemented it's own extension to the GROUP BY query, see this link --> http://dev.mysql.com/doc/refman/5.6/en/group-by-extensions.html
In MySql the select list can refer to nonaggregated columns not listed in the GROUP BY clause. Becaue of this extension our query is syntactically correct and runs on MySql, but gives unexpected (unwanted) results, since an order of expression's evaluation is different:
1. it first runs an aggregated (group by) query and evaluates AVG( price ),
2. then evaluates CASE WHEN ... THEN, but for resultset returned by the aggregated query from point 1
The query with the clause AVG( case when ... then ):
1. first calucates the expression CASE-WHEN-THEN for all table rows
2. then runs an aggregated query for resultset returned by #1 and calculates the AVG.
Try:
SELECT Readings.SampleID, Sample.BatchesID
AVG(case when location = '1' then voltage else null end) avg_v_for_1,
AVG(case when location = '2' then voltage else null end) avg_v_for_2,
...
AVG(case when location = '25' then voltage else null end) avg_v_for_25
FROM DB.Readings
........
GROUP BY sample_id
--- EDIT --> use ifnull function to change nulls into 0
SELECT Readings.SampleID, Sample.BatchesID
ifnull( AVG(case when location = '1' then voltage else null end), 0 ) avg_v_for_1,
ifnull( AVG(case when location = '2' then voltage else null end), 0 ) avg_v_for_2,
...
ifnull( AVG(case when location = '25' then voltage else null end), 0 ) avg_v_for_25
FROM DB.Readings
........
GROUP BY sample_id

mysql query question on count

SELECT if((COUNT(vote=1)-COUNT(vote=0) > 0,1,count(groupid))
FROM sample WHERE uid = $uid GROUP BY groupid
In the if statement, I was wondering if there is any simple way to achieve this: COUNT(vote=1)-COUNT(vote=0) > 0
Use SUM instead of COUNT:
SELECT if((SUM(vote=1)-SUM(vote=0) > 0,1,count(groupid))
FROM sample WHERE uid = $uid GROUP BY groupid
You want the sum of vote, except 0 counts as -1:
SELECT if(sum(if(vote, 1, -1)) > 0, 1, count(groupid))
...
are you trying to do
Select columns,
case when (COUNT(vote=1) - COUNT(vote=0)) > 0
then 'something'
else 'something else' as foo
From Sample
Where uid=$uid
Group By groupid
I don't quite understand what you are trying to achieve.
With my example, you select the columns (or just that case), when the difference is greater than 0. If it is greater show 'something' else show 'something else'
although, i don't have a way to test it on this computer, but maybe it will lead you or someone else in the right direction.