MySQL Get the number of times values appear in a column? - mysql

In MySQL, I have a table that holds the outcomes of rounds of a contest. This table has a result column that contains the values 'won' 'lost' or 'draw'. How can I group by the competitor and get the counts of specific values? The idea is to be able to sort competitors based on the number of wins and losses, and calculate scores within the database query.
So, my table is:
+--------------+---------+--------+
| CompetitorId | MatchId | Result |
+--------------+---------+--------+
| 1 | 1 | won |
| 2 | 1 | lost |
| 1 | 2 | won |
| 3 | 2 | lost |
+--------------+---------+--------+
The result I am trying to get is:
+--------------+------+--------+
| CompetitorId | Wins | Losses |
+--------------+------+--------+
| 1 | 2 | 0 |
| 2 | 0 | 1 |
| 3 | 0 | 1 |
+--------------+------+--------+
The query I tried was this:
SELECT CompetitorId, COUNT(result='won') AS wins, COUNT(result='lost') AS losses
FROM match_competitors
GROUP BY CompetitorId

You can use sum with a case inside, giving a value of 1 when is the column you need and 0 when is not:
SELECT CompetitorId, sum(case result
when 'won' then 1
else 0
end) as wins,
sum(case result
when 'lost' then 1
else 0
end) as losses
FROM match_competitors
GROUP BY CompetitorId

Related

How to distribute a row into different row grouped by the value it has and date created?

I have a table consisting of result, name and created_at like :
id | name | result | created_at
1 | Sam | 1 | 2018-07-12 05:08:04
2 | Tam | 1 | 2018-07-12 06:08:04
3 | Qam | 0 | 2018-07-12 07:08:04
4 | Yam | 1 | 2018-09-12 04:08:04
5 | Xam | 0 | 2018-09-12 06:08:04
6 | Lam | 0 | 2018-11-12 07:08:04
(the 1 represents pass where as 0 represent fails) I want to group the data by created at date which displays the count of result success or failed in seperate colums like:
fail | pass | created_at
0 | 2 | 2018-07-12 05:08:04
1 | 1 | 2018-09-12 04:08:04
1 | 0 | 2018-11-12 07:08:04
I could count the value of just pass or fail with this query: select count(result) from call_history where result = 1 GROUP BY DATE(created_at), but wasn't able to provide double where clause for different rows.
You can use a case expression to return a non-null result only for successes/failures, and then use count, which skips nulls:
SELECT COUNT(CASE result WHEN 0 THEN 1 END) AS fail,
COUNT(CASE result WHEN 1 THEN 1 END) AS pass,
created_at
FROM call_history
GROUP BY created_at
I would write this as:
SELECT SUM(1 - result) as fail,
SUM(result as pass)
created_at
FROM call_history
GROUP BY created_at;

SQL- Count number of 'similar' rows and place results in another table

I have a table called of 'orders' that records an order id for a meal, a person id for the person who ordered the meal and the meal (which can be 1, 2, or 3)
orders
oid | pid | meal
________________
1 | 1 | 2
2 | 1 | 3
3 | 3 | 1
4 | 5 | 2
5 | 5 | 2
6 | 5 | 1
I want to generate a result that will allow me to view the number of orders for each meal for each pid:
pid | meal1 | meal2 | meal3
____________________________
1 | 0 | 1 | 1
3 | 1 | 0 | 0
5 | 0 | 2 | 1
I am not an SQL expert, but I was thinking that I would first group the list by pid, then by meal. But how would I do the counting? I am truly lost.
Basically you need to first create multiple columns for the different meals using case when, then you can group by pid and sum it up
Select pid, sum(case when meal =1 then 1 else 0 end) as meal1,
sum(case when meal =2 then 1 else 0 end) as meal2,
sum(case when meal =3 then 1 else 0 end) as meal3
from Table
group by pid

MySQL Crosstab aggregation with 2 conditions

I have a query which creates a crosstab. The results are a count of the txn_id for branda, and the count of txn_id for brandb.
The txn_id is NOT UNIQUE. This is an example of the transactions table.:
txn_id | nationality_id | sku | sales | units
1 | 1 | 1 | 20 | 2
1 | 1 | 2 | 15 | 1
2 | 4 | 1 | 20 | 2
3 | 2 | 1 | 10 | 1
4 | 3 | 2 | 15 | 1
5 | 4 | 1 | 10 | 1
There are 2 other tables (products) - (sku, brand, product name), and (nationalities) - (nationality_id, nationality).
I would like to add a third column which gets me the count of txn_id where BOTH brands are purchased
The output should be
nationality | branda | brandb | combined
1 | 1 | 1 | 1
2 | 1 | 0 | 0
3 | 0 | 1 | 0
4 | 2 | 0 | 0
Current query.
SELECT
nationalities.nationality,
COUNT((CASE brand WHEN 'branda' THEN txn_id ELSE NULL END)) AS branda,
COUNT((CASE brand WHEN 'brandb' THEN txn_id ELSE NULL END)) AS brandb
<I want my 3rd column here>
FROM
transaction_data
INNER JOIN
products USING (sku)
INNER JOIN
nationalities USING (nationality_id)
GROUP BY nationality
ORDER BY branda DESC
LIMIT 20;
I have tried using:
COUNT((CASE brand WHEN 'brandb' OR 'brandb' THEN txn_id ELSE NULL END)) AS combined - however this obviously returns too many (returns branda or brandb regardless of whether they were purchased together). I know I can't use AND, because obviously no single cell is going to be both branda AND brandb.
I have also tried using:
COUNT((CASE brand WHEN IN('branda', 'brandb') THEN txn_id ELSE NULL END)) AS combined - However this isn't valid syntax.
I feel that I should be using a HAVING clause, but I'm not sure how this would work in the column list.
I think you are going to need two levels of aggregation:
SELECT n.nationality,
sum(branda), sum(brandb), sum(branda * brandb)
FROM (SELECT t.txn_id, n.nationality,
MAX(CASE brand WHEN 'branda' THEN 1 ELSE 0 END) AS branda,
MAX(CASE brand WHEN 'brandb' THEN 1 ELSE 0 END) AS brandb
FROM transaction_data t INNER JOIN
products p
USING (sku) INNER JOIN
nationalities n
USING (nationality_id)
GROUP BY t.txn_id, n.nationality
) tn
GROUP BY n.nationality
ORDER BY max(txn_id) DESC
LIMIT 20;

How to do one big select from table in MySQL?

I need to show the data from DB into a table of report file.
my_table looks like:
+----+-------+------+------+-------------------+-----------+-------+----+-------------------+
| id |entryID|userID|active| dateCreated |affiliateId|premium|free| endDate |
| 1 | 69856 | 1 | N |2014-03-22 13:54:49| 1 | N | N |2014-03-22 13:54:49|
| 2 | 63254 | 2 | Y |2014-03-21 13:35:15| 2 | Y | N | |
| 3 | 56324 | 3 | N |2014-03-21 11:11:22| 2 | Y | N |2014-02-22 16:44:46|
| 4 | 41256 | 4 | Y |2014-03-21 08:10:46| 1 | N | Y | |
| .. | ... | ... | ... | ... | ... | ... | .. | ... |
+----+-------+------+------+-------------------+-----------+-------+----+-------------------+
I need to create the table with data from my_table
| Date | № of Entries (in that date) | Total № of Entries | Premium | Free | Afiiliate |
The final table in file should looks like:
Report 17-07-2013:
+----------+--------------+-------+---------+------+-----------+
| Date | № of Entries | Total | Premium | Free | Afilliate |
|2013-07-17| 2 | 99845 | 2 | 0 | 0 |
|2013-07-18| 1 | 99843 | 0 | 1 | 0 |
|2013-07-22| 1 | 99842 | 1 | 0 | 1 |
|2013-07-23| 3 | 99841 | 2 | 1 | 2 |
|2013-07-24| 298 | 99838 | 32 | 273 | 25 |
|2013-07-25| 5526 | 99540 | 474 | 5058 | 126 |
|2013-07-26| 1686 | 94014 | 157 | 1532 | 56 |
|2013-07-27| 1673 | 92328 | 156 | 1517 | 97 |
|2013-07-28| 1461 | 90655 | 155 | 1310 | 83 |
| ... | ... | ... | ... | ... | ... |
+----------+--------------+-------+---------+------+-----------+
Should I for each column do a SELECT or I should do only 1 select?
If it possible to do 1 select how to do it?
It should be by analogy with this report:
report
Some fields differ (like 'Number of Entries in that date').
Total number of Entries means: all entries from beginning to the that specific date.
Number of Entries in that date means: all entries in that date.
In a final table the date from column Date will not repeat, that's why Column 'Number of Entries (in that date)' will calculate all entries for that date.
Your result is not so clear for the total is a count or sum and affiliate is sum or count also
but assuming total will be count and affiliate will be sum
here a query you might use to give you a result ( using ms-sql )
select DateCreated,count(EntryId) as Total,
sum(case when Premium='Y' then 1 else 0 end) as Premium,
sum(case when Premium='N' then 1 else 0 end) as Free,
sum(AffiliateId) as Affiliate
from sample
group by DateCreated
here a working demo
if I didn't understood you correctly, kindly advise
hope it will help you
SQLFiddle Demo: http://sqlfiddle.com/#!9/20cc0/5
The added column entryID does not matter for us.
I don't really understand what you want for Total, or the criteria for affiliateID. This query should get you started.
SELECT
DATE(dateCreated) as "Date",
count(dateCreated) as "No of Entries",
99845 as Total,
sum( case when premium='Y' then 1 else 0 end ) as Premium,
sum( case when premium='N' then 1 else 0 end ) as Free,
sum( case when affiliateID IS NOT NULL then 1 else 0 end) as Affiliate
FROM MyTable
GROUP BY DATE(dateCreated)
ORDER BY Date ASC
The final table in file should looks like:
... This new table can be in a file or in the web page. But it is not a new table in DB. –
It sounds like you may be new to this area so I just wanted to inform you that spitting out a report into a file for a website is highly unusual and typically only done when your data is completely separate from the website. Putting data from a database onto a website (like the query we made here) is very common and it's very likely you don't need to mess with any files.
select date(DateCreated),count(entryId) as Total,
sum(case when Premium='Y' then 1 else 0 end) as Premium,
sum(case when Premium='N' then 1 else 0 end) as Free,
sum( case when affiliateID IS NOT NULL then 1 else 0 end) as Affiliate
INTO OUTFILE '/tmp/myfile.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
from my_table
group by date(DateCreated) order by date(DateCreated);

SQL Increment Column

I am trying to show one semesters aggregates in one column, the next semester's aggregates in the second column, and the third semesters aggregates in the third column. Also the real tables, I don't know how many status codes there are...
I have a semester table:
Id Semester
+----+----------+
| 1 Current |
| 2 Next |
| 3 2 Ahead |
+----+----------+
I have a simple project table:
Id Title Status termId
+----+--------+---------+--------+
| 1 A OK 1 |
| 2 B Bad 1 |
| 3 C OK 1 |
| 4 D Bad 2 |
| 5 E OK 2 |
| 6 F Bad 3 |
| 7 G OK 2 |
+----+--------+---------+--------+
This is the desired Output:
Status CurrentCount NextCount 2AheadCount
+---------+--------------+-----------+-------------+
| OK 2 1 0 |
| Bad 1 1 1 |
+---------+--------------+-----------+-------------+
What would you recommend I do to be able to achieve this?
You can use conditional aggregation with group by:
select status,
sum(case when termId = 1 then 1 else 0 end) CurrentCount,
sum(case when termId = 2 then 1 else 0 end) NextCount,
sum(case when termId = 3 then 1 else 0 end) 2AheadCount
from project
group by status