MySQL show proportion - mysql

I am trying to show a proportion of customers that signed up because he/she was being referred by other customers and customers with no referral. So far I only able to show it as numerical but I wanted to show it in percentage. Null is when the customer signs up without being referred.
The original data as follows:
CustomerID ReferralID
1000004 1000003
1000015 1000010
1000007 1000004
1000011 Null
1000026 1000004
The query that I have and return data as follows:
select customerID, COUNT(*) as proportion
from company123.customertable
group by (customerID)
order by customerID asc;
CustomerID proportion
1000004 1
1000015 1
1000007 1
1000011 1
1000026 1
Expected result
CustomerID referred non-referred
1000004 1 0
1000015 1 0
1000007 1 0
1000011 0 1
1000026 1 0
Any suggestion to show it as a percentage? Thank you in advance

Use aggregate function AVG():
select avg(ReferralID is not null) referred,
avg(ReferralID is null) non_referred
from customertable
See the demo.
Results:
> referred | non_referred
> -------: | -----------:
> 0.8000 | 0.2000

you can use an aggregate function on a case statement like this
SELECT
COUNT(*) customers,
SUM(CASE WHEN referral_id IS NOT NULL THEN 1 ELSE 0 END) / COUNT(*) AS referred,
SUM(CASE WHEN referral_id IS NULL THEN 1 ELSE 0 END) / COUNT(*) AS non_referred
FROM company123.customertable
should give you something like this (numbers are made up)
customers referred non_referred
12301 0.7128 0.2872

Here's one way which will give a percentage to 2 decimal places:
EDIT: Added % sign to output using CONCAT
SELECT customerid,
CONCAT(CAST(COUNT(ReferralID) * 100.0 / Count(*) as decimal(9,2)),'%') AS proportion
FROM company123.customertable
GROUP BY customerid
ORDER BY customerid ASC;

Related

MySQL Where-clause with select

I have a table that has three columns: visitations, country and user_id. I have a query to retrieve amount of all visitors per country and re-visitors per country. Now, I would like to alter my query so, that I get both amounts and a ratio of re-visitors per country (re-visitors / all visitors). I'm just learning MySQL and I feel that I don't know the tools to select all visitors and re-visitors and then use them in the ratio. Is there a way to do this in one query? Could someone help me with this? Thanks!
Here is my query for all visitors (and re-visitors if the # is removed)
SELECT sum(Visitations) AS "Amount", country
FROM E91
#WHERE Visitations > 1
GROUP BY Country
ORDER BY `Amount` DESC
Sample of the data, user is a revisitor if visitations is above 1:
user_id | country | visitations
---------|--------------|---------------
beth123 | Germany | 4
david78 | USA | 2
matt23 | UK | 1
...
The where clause starts to filter records, leaving out records you do want to count for your total. To count the revisitors you can use CASE WHEN... END:
SELECT
sum(Visitations) AS "Amount",
sum(CASE WHEN Visitations > 1 THEN 1 ELSE 0 END) as "Re-Visitors",
country
FROM E91
GROUP BY Country
ORDER BY `Amount` DESC
For further use you could do something like this:
SELECT
sum(Visitations) AS "Amount",
sum(CASE WHEN Visitations > 1 THEN 1 ELSE 0 END) as "Re-Visitors",
sum(CASE WHEN Visitations > 1 THEN 1 ELSE 0 END) / sum(Visitations) as "X",
country
FROM E91
GROUP BY Country
ORDER BY `Amount` DESC
or:
SELECT Amount, Re-visitors, "Re-visitors"/Amount, country
FROM (
SELECT
sum(Visitations) AS "Amount",
sum(CASE WHEN Visitations > 1 THEN 1 ELSE 0 END) as "Re-Visitors",
country
FROM E91
GROUP BY Country
ORDER BY `Amount` DESC
) x
The amount of visitors and re-visitors has nothing to do with the sum of the column visitations.
You can get the number of visitors (all user_ids who visited a country) by counting the number of user_ids for each country and the number of re-visitors by counting the number of user_ids for each country when the column visitations is greater than 1:
SELECT country,
SUM(visitations > 1) AS revisitors,
COUNT(*) AS visitors,
AVG(visitations > 1) AS ratio
FROM E91
GROUP BY Country

group by is messing up my counts mysql

I have a basic table:
id client trans_date returned
1 bob 20180301 0
2 frank 20180301 0
3 bob 20180401 1
id like to get a result that groups by the client and counts how many items bought and how many returned. Like this
name bought returned
bob 1 1
frank 1 0
i tried this but it didnt work
SELECT
soldto AS name,
IF(return=0,count(id),'0') AS bought,
IF(return=1,count(id),'0') AS returned
FROM sales
WHERE sdate BETWEEN '20180201000000' AND '20180501000000'
group by soldto;
Use conditional aggregation
SELECT
soldto AS name,
COUNT(*) AS bought,
-- or maybe COUNT( CASE WHEN return = 0 THEN 1 END) AS bought,
COUNT( CASE WHEN return = 1 THEN 1 END) AS returned
FROM sales
WHERE sdate BETWEEN '20180201000000' AND '20180501000000'
GROUP BY soldto;

MySQL duplicate entries search with selective date criteria

Having trouble wrapping my head around having an efficient "duplicate entries" select in a single query.
In the below example, duplicate StockNo can exist spanning multiple Date. I want to search StockNo for duplicate entries, and if at least 1 StockNo record is found within the Date current YEAR-MONTH, then I also need to select its partner that could exist in any other YEAR-MONTH. Is this possible?
Example Query:
SELECT * FROM `sales`
WHERE `StockNo` IN
(SELECT `StockNo` FROM `sales` GROUP BY `StockNo` HAVING COUNT(*) > 1)
AND `Date` LIKE '2016-11-%'
ORDER BY `StockNo`, `TransactionID`;
Example Data:
ID | StockNo | Date
1 | 1 | 2016-11-01
2 | 1 | 2016-11-10
3 | 2 | 2016-11-05
4 | 2 | 2016-10-29
5 | 3 | 2016-10-25
6 | 3 | 2016-10-15
With my example query and data, I have 3 pairs of duplicate entries. It's pretty obvious that I will only return 3 records (ID's 1, 2 & 3) due to AND Date LIKE '2016-11-%', however I need to return ID's 1, 2, 3, 4. I want to ignore ID's 5 & 6 because neither of them fall within the current month.
Hope that makes sense. Thanks for any help you can provide.
SELECT StockNo
FROM sales
GROUP BY StockNo
HAVING SUM(CASE WHEN DATE_FORMAT(Date, '%Y-%m') = '2016-11' THEN 1 ELSE 0 END) > 0
If you also want to retrieve the full records for those matching stock numbers in the above query, you can just add a join:
SELECT s1.*
FROM sales s1
INNER JOIN
(
SELECT StockNo
FROM sales
GROUP BY StockNo
HAVING SUM(CASE WHEN DATE_FORMAT(Date, '%Y-%m') = '2016-11' THEN 1 ELSE 0 END) > 0
) s2
ON s1.StockNo = s2.StockNo
Demo here:
SQLFiddle
Thank you very much Tim for pointing me in the right direction. Your answer was close but it still only returned records from the current month and in the end I used the following query:
SELECT s1.* FROM `sales` s1
INNER JOIN
(
SELECT * FROM `sales` GROUP BY `StockNo` HAVING COUNT(`StockNo`) > 1
AND SUM(CASE WHEN DATE_FORMAT(`Date`, '%Y-%m')='2016-11' THEN 1 ELSE 0 END) > 0
) s2
ON s1.StockNo=s2.StockNo
This one had been eluding me for some time.

SQL Query - How to get difference of sum of multiple of cells of rows

I need to get the difference of the sums of two fields which are in single table (really sorry if this is confusing), please read on for an example
Id type account_id stock_id volume price value
==========================================================
1 BUY 1 1 5 500 2500
2 BUY 1 4 30 200 6000
6 BUY 1 1 10 500 5000
7 SELL 1 1 3 500 1500
8 SELL 1 1 2 500 1000
9 SELL 1 4 20 120 2400
Above is my sample data and I would my SQL query result to be something like,
account_id stock_id volume totalAmount
============================================
1 1 10 5000
1 4 10 3600
basically here I am trying to get the total buy value of unique account & stock combination and subtract with the total sell value
Any help here would be highly appreciated.
Thanks in advance
Fiddle Test:
http://sqlfiddle.com/#!2/53035/1/0
select account_id,
stock_id,
sum(case when type = 'BUY' then volume else -volume end) as volume,
sum(case when type = 'BUY' then value else -value end) as totalamount
from tbl
group by account_id,
stock_id
having sum(case when type = 'BUY' then volume else -volume end) <> 0
I added the HAVING clause based on your comment.
Just to reduce duplication I would change Brian's code to this:
SELECT
account_id,
stock_id,
SUM(volume * type_sign) as total_volume,
SUM(value * type_sign) as total_value
FROM
(select t.*, case when type = 'BUY' then 1 else -1 end as type_sign
from tbl) t
GROUP BY account_id,
stock_id
select buy.account_id,buy.stock_id,(buy.volume-sell.volume) volume,(buy.totalAmount-sell.totalAmount) totalAmount from
(select account_id,stock_id,sum(volume) volume,sum(value) totalAmount from stock
where type = 'BUY'
group by account_id,stock_id) buy
inner join
(select account_id,stock_id,sum(volume) volume,sum(value) totalAmount from stock
where type = 'SELL'
group by account_id,stock_id) sell
on buy.account_id = sell.account_id and buy.stock_id = sell.stock_id

Query with multiple subqueries required in Mysql

I am looking for some query help
here is the following table data
Name Runs Status
Ram 50 out
Ram 103 not out
Krish 51 out
Sam 15 out
Ram 15 out
Krish 78 not out
I am expecting a single query to give the folllowing results
Name Total >100 >50&<100 TotalTimes Notout
Ram 168 1 1 3 1
Sam 15 0 0 1 0
Krish 129 0 2 2 1
I am able to write the query to get the total, Totaltimes with the help of Group By functionalities, I am stuck with the rest
Here is the query I have come up
select Name, sum(Runs) as total, count(*) as totalTimes
from tempTable
where classID IN (Select classID from upcoming_Clases where classes_id=175)
group by Name order by total desc
I am using the Mysql Database
You can do this using case:
select Name,
sum(Runs) as total,
count(case when Runs>100 then 1 end) `>100`,
count(case when Runs>50 and Runs<100 then 1 end) `>50&<100`,
count(*) as totalTimes,
count(case when Status='not out' then 1 end) `Not Out`
from tempTable
where classID IN (Select classID from upcoming_Clases where classes_id=175)
group by Name order by total desc
You can use SUM() together with IF() to test your criteria:
SELECT
Name,
SUM(Runs) AS Total,
SUM(IF(Runs>100, 1, 0)) AS `>100`,
SUM(IF(Runs>50 AND Runs<100), 1, 0) AS `>50&<100`,
COUNT(*) AS TotalTimes,
SUM(IF(Status='not out', 1, 0)) AS Notout
FROM tempTable
WHERE classID IN (SELECT classID FROM upcoming_Clases WHERE classes_id = 175)
GROUP BY Name
ORDER BY Total DESC