How to calculate ratio using sql query? - mysql

I have a table like below:
ID Name Department Gender
1 Crib MA MALE
2 Lucy Bsc FEMALE
3 Phil Bcom MALE
4 Ane MA FEMALE
I have 1000 row of records like this. I want to find the ratio from column Gender( MALE & FEMALE) of all students.
I need a query to perform this.

SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE table1
(`ID` int, `Name` varchar(4), `Department` varchar(4), `Gender` varchar(6))
;
INSERT INTO table1
(`ID`, `Name`, `Department`, `Gender`)
VALUES
(1, 'Crib', 'MA', 'MALE'),
(2, 'Lucy', 'Bsc', 'FEMALE'),
(3, 'Phil', 'Bcom', 'MALE'),
(4, 'Ane', 'MA', 'FEMALE')
;
Query 1:
SELECT sum(case when `Gender` = 'MALE' then 1 else 0 end)/count(*) as male_ratio,
sum(case when `Gender` = 'FEMALE' then 1 else 0 end)/count(*) as female_ratio
FROM table1
Results:
| MALE_RATIO | FEMALE_RATIO |
|------------|--------------|
| 0.5 | 0.5 |

Try something like this
select sum(case when gender = 'MALE' then 1 else 0 end) / count(*) * 100 as perc_male,
sum(case when gender = 'FEMALE' then 1 else 0 end) / count(*) * 100 as perc_female
from students

This should give you the actual ratio, and should work with little or no modifcation in MySQL and SQL Server. You may have to modify the cast statement a little - my MySQL is rusty, and I think it may handle that slightly differently.
SELECT
(CAST((SELECT COUNT(*) FROM tblName WHERE Gender='MALE') AS FLOAT) /
CAST((SELECT COUNT(*) FROM tblName WHERE Gender='FEMALE') AS FLOAT))
AS ratioMaleFemale;

You're pretty close:
select (select count(*)
from table where gender='MALE' )/count(*)*100 as percentage_male,
(select count(*)
from table where gender='FEMALE' )/count(*)*100 as percentage_female
from table;

How about
select gender, count(*)
from table
group by gender
then it's very simple to calculate the ratio yourself.

Related

Maintain multiple row data in single row mysql [duplicate]

This question already has answers here:
How can I return pivot table output in MySQL?
(10 answers)
Closed 9 days ago.
There is my table look like
id
name
deduction
amount
01
teat
Home Rent
1000
01
test
GPF
500
i want show my data in deduction report like below table
id
name
home_rent
gpf
01
teat
1000
500
mysql code
SELECT a.* , a.amount as home_rent ,b.amount as gpf FROM my_table as a ,my_table as b where a.deduction = Home Rent and b.deduction = GPF
what i have done wrong please let me know ? what can i do for my report to it look like my second table thank you ...
We can use conditional aggregation and pivoting here:
SELECT
id,
name,
MAX(CASE WHEN deduction = 'Home Rent' THEN amount END) AS home_rent,
MAX(CASE WHEN deduction = 'GPF' THEN amount END) AS gpf
FROM my_table
GROUP BY 1, 2;
use conditional aggregation
Schema (MySQL v5.7)
CREATE TABLE my_table (
`id` INTEGER,
`name` VARCHAR(4),
`deduction` VARCHAR(9),
`amount` INTEGER
);
INSERT INTO my_table
(`id`, `name`, `deduction`, `amount`)
VALUES
('01', 'test', 'Home Rent', 1000),
('01', 'test', 'GPF', 500);
Query #1
SELECT
id,
name,
SUM(CASE WHEN deduction = 'Home Rent' THEN amount ELSE 0 END) AS home_rent,
SUM(CASE WHEN deduction = 'GPF' THEN amount ELSE 0 END) AS gpt
FROM my_table
GROUP BY 1, 2;
id
name
home_rent
gpt
1
test
1000
500
View on DB Fiddle

Displayed values are not what they should be

There are 2 tables ost_ticket and ost_ticket_action_history.
create table ost_ticket(
ticket_id int not null PRIMARY KEY,
created timestamp,
staff bool,
status varchar(50),
city_id int
);
create table ost_ticket_action_history(
ticket_id int not null,
action_id int not null PRIMARY KEY,
action_name varchar(50),
started timestamp,
FOREIGN KEY(ticket_id) REFERENCES ost_ticket(ticket_id)
);
In the ost_ticket_action_history table the data is:
INSERT INTO newdb.ost_ticket_action_history (ticket_id, action_id, action_name, started) VALUES (1, 1, 'Consultation', '2022-01-06 18:30:29');
INSERT INTO newdb.ost_ticket_action_history (ticket_id, action_id, action_name, started) VALUES (2, 2, 'Bank Application', '2022-02-06 18:30:45');
INSERT INTO newdb.ost_ticket_action_history (ticket_id, action_id, action_name, started) VALUES (3, 3, 'Consultation', '2022-05-06 18:42:48');
In the ost_ticket table the data is:
INSERT INTO newdb.ost_ticket (ticket_id, created, staff, status, city_id) VALUES (1, '2022-04-04 18:26:41', 1, 'open', 2);
INSERT INTO newdb.ost_ticket (ticket_id, created, staff, status, city_id) VALUES (2, '2022-05-05 18:30:48', 0, 'open', 3);
INSERT INTO newdb.ost_ticket (ticket_id, created, staff, status, city_id) VALUES (3, '2022-04-06 18:42:53', 1, 'open', 4);
My task is to get the conversion from the “Consultation” stage to the “Bank Application” stage broken down by months (based on the start date of the “Bank Application” stage).Conversion is calculated according to the following formula: (number of applications with the “Bank Application” stage / number of applications with the “Consultation” stage) * 100%.
My request is like this:
select SUM(action_name='Bank Application')/SUM(action_name='Consultation') * 2 as 'Conversion' from ost_ticket_action_history JOIN ost_ticket ot on ot.ticket_id = ost_ticket_action_history.ticket_id where status = 'open' and created > '2020 -01-01 00:00:00' group by action_name,started having action_name = 'Bank Application';
As a result I get:
Another query:
SELECT
SUM(CASE
WHEN b.ticket_id IS NOT NULL THEN 1
ELSE 0
END) / COUNT(*) conversion,
YEAR(a.started) AS 'year',
MONTH(a.started) AS 'month'
FROM
ost_ticket_action_history a
LEFT JOIN
ost_ticket_action_history b ON a.ticket_id = b.ticket_id
AND b.action_name = 'Bank Application'
WHERE
a.action_name = 'Consultation'
AND a.status = 'open'
AND a.created > '2020-01-01 00:00:00'
GROUP BY YEAR(a.started) , MONTH(a.started)
I apologize if I didn't write very clearly. Please explain what to do.
Like I explained in my comment, you exclude rows with your having clause.
I will show you in the next how to debug.
First check what the raw result of the select query is.
As you see, when you remove the GROUP BY and see what you actually get is only 1 row with bank application, because the having clause excludes all other rows
SELECT
*
FROM
ost_ticket_action_history
JOIN
ost_ticket ot ON ot.ticket_id = ost_ticket_action_history.ticket_id
WHERE
status = 'open'
AND created > '2020-01-01 00:00:00'
GROUP BY
action_name, started
HAVING
action_name = 'Bank Application';
Output:
ticket_id
action_id
action_name
started
ticket_id
created
staff
status
city_id
2
2
Bank Application
2022-02-06 18:30:45
2
2022-05-05 18:30:48
0
open
3
Second step, see what the result set is without calculating anything.
As you can see you make a division with 0, what you have learned in school, is forbidden, hat is why you have as result set NULL
SELECT
SUM(action_name = 'Bank Application')
#/
,SUM(action_name = 'Consultation') * 2 AS 'Conversion'
FROM
ost_ticket_action_history
JOIN
ost_ticket ot ON ot.ticket_id = ost_ticket_action_history.ticket_id
WHERE
status = 'open'
AND created > '2020-01-01 00:00:00'
GROUP BY action_name , started
HAVING action_name = 'Bank Application';
SUM(action_name = 'Bank Application') | Conversion
------------------------------------: | ---------:
1 | 0
db<>fiddle here
#Third what you can do exclude a division with 0, here i didn't remove all othe rows as this is only for emphasis
SELECT
SUM(action_name = 'Bank Application')
/
SUM(action_name = 'Consultation') * 2 AS 'Conversion'
FROM
ost_ticket_action_history
JOIN
ost_ticket ot ON ot.ticket_id = ost_ticket_action_history.ticket_id
WHERE
status = 'open'
AND created > '2020-01-01 00:00:00'
GROUP BY action_name , started
HAVING SUM(action_name = 'Consultation') > 0;
| Conversion |
| ---------: |
| 0.0000 |
| 0.0000 |
db<>fiddle here
Final words,
If you get a strange result, simply go back remove everything that doesn't matter and try to get all values, so hat you can check your math

How will I fix this table using MySQL?

I am new to MySQL. I am using MySQL 8.0.
My schema and sample data is as follows:
CREATE TABLE AA (
A int
);
insert into AA (A) values (1);
insert into AA (A) values (1);
insert into AA (A) values (2);
insert into AA (A) values (2);
insert into AA (A) values (1);
insert into AA (A) values (3);
CREATE TABLE BB (
code int,
description varchar(30)
);
insert into BB (code, description) values (1, 'Male');
insert into BB (code, description) values (2, 'Female');
Here's my code
with totalcount as (
select code as 'CODE',
description as 'SEX',
count(A) AS 'TOTAL',
ROUND((COUNT(A) * 100.0) / (SELECT COUNT(A) FROM AA),2) AS 'PERCENT',
sum(count(A)) over (order by CODE asc) AS 'CUMULATIVE',
ROUND((SUM(COUNT(A)) OVER (ORDER BY CODE ) / (SELECT COUNT(A) FROM AA) *100 ),2) AS 'CUMPERCENT'
from AA, BB
where AA.A= BB.code
group by AA.A
)
select *
from totalcount
UNION ALL
SELECT '0' CODE, 'TOTAL' SEX, SUM(TOTAL), SUM(PERCENT), '0' CUMULATIVE, '0.00' CUMPERCENT
from totalcount
ORDER BY CODE;
The output was this
CODE | SEX | TOTAL | PERCENT | CUMULATIVE | CUMPERCENT
0 TOTAL 5 100.00 0 0.00
1 MALE 3 60.00 3 60.00
2 FEMALE 2 40.00 5 100.00
I used UNION since I want the total of these items. In this case, I inserted 0 in TOTAL of SEX column to put it in the first row. Is there another way aside from using UNION and inserting code 0?
As you can see from my table BB, there are only code 1 and 2 for male and female, respectively. I want to show that the value not in this table should be in NOT VALID.
CODE | SEX | TOTAL | PERCENT | CUMULATIVE | CUMPERCENT
0 TOTAL 6 100.00 0 0.00
1 MALE 3 50.00 3 50.00
2 FEMALE 2 33.33 5 83.33
3 NOT VALID 1 16.67 6 100.00
Can you help me with this? Thank you.
This is a very tricky reporting question. One approach uses GROUP BY ROLLUP to generate the total row, along with judicious use of COALESCE to fill in the missing values per your requirements.
SELECT
COALESCE(t1.A, 0) AS CODE,
CASE WHEN t1.A IS NOT NULL THEN COALESCE(t2.DESCRIPTION, 'NOT VALID') ELSE 'TOTAL' END AS SEX,
t1.TOTAL,
ROUND(100.0 * t1.TOTAL / SUM(CASE WHEN t1.A IS NOT NULL THEN t1.TOTAL ELSE 0 END) OVER (), 2) AS PERCENT,
SUM(CASE WHEN t1.A IS NOT NULL THEN t1.TOTAL ELSE 0 END) OVER (ORDER BY t1.A) AS CUMULATIVE,
ROUND(100.0 * SUM(CASE WHEN t1.A IS NOT NULL THEN t1.TOTAL ELSE 0 END) OVER (ORDER BY t1.A) /
SUM(CASE WHEN t1.A IS NOT NULL THEN t1.TOTAL ELSE 0 END) OVER (), 2) AS CUMPERCENT
FROM
(
SELECT
A,
COUNT(*) AS TOTAL
FROM AA
GROUP BY A WITH ROLLUP
) t1
LEFT JOIN BB t2
ON t2.CODE = t1.A
ORDER BY
CODE;
Demo

SQL query - credit , debit , balance

DISCLAIMER : I Know this has been asked numerous times, but all I want is an alternative.
The table is as below :
create table
Account
(Name varchar(20),
TType varchar(5),
Amount int);
insert into Account Values
('abc' ,'c', 500),
('abc', 'c', 700),
('abc', 'd', 100),
('abc', 'd', 200),
('ab' ,'c', 300),
('ab', 'c', 700),
('ab', 'd', 200),
('ab', 'd', 200);
Expected result is simple:
Name Balance
------ -----------
ab 600
abc 900
The query that worked is :
select Name, sum(case TType when 'c' then Amount
when 'd' then Amount * -1 end) as balance
from Account a1
group by Name.
All I want is, is there any query sans the 'case' statement (like subquery or self join ) for the same result?
Sure. You can use a second query with a where clause and a union all:
select name
, sum(Amount) balance
from Account a1
where TType when 'c'
group
by Name
union
all
select name
, sum(Amount * -1) balance
from Account a1
where TType when 'd'
group
by Name
Or this, using a join with an inline view:
select name
, sum(Amount * o.mult) balance
from Account a1
join ( select 'c' cd
, 1 mult
from dual
union all
select 'd'
, -1
from dual
) o
on o.cd = a1.TType
group
by Name
To be honest, I would suggest to use case...
Use the ASCII code of the char and try to go from there. It is 100 for 'd' and 99 for 'c'. Untested example:
select Name, sum((ASCII(TType) - 100) * Amount * (-1)) + sum((ASCII(TType) - 99) * Amount * (-1)))) as balance from Account a1 group by Name.
I would not recommend using this method but it is a way of achieving what you want.
select t.Name, sum(t.cr) - sum(t.dr) as balance from (select Name, case TType when 'c' then sum(Amount) else 0 end as cr, case TType when 'd' then sum(Amount) else 0 end as dr from Account group by Name, TType) t group by t.Name;
This will surely help you!!
The following worked for me on Microsoft SQL server. It has the Brought Forward balance as well
WITH tempDebitCredit AS (
Select 0 As Details_ID, null As Creation_Date, null As Reference_ID, 'Brought
Forward' As Transaction_Kind, null As Amount_Debit, null As Amount_Credit,
isNull(Sum(Amount_Debit - Amount_Credit), 0) 'diff'
From _YourTable_Name
where Account_ID = #Account_ID
And Creation_Date < #Query_Start_Date
Union All
SELECT a.Details_ID, a.Creation_Date, a.Reference_ID, a.Transaction_Kind,
a.Amount_Debit, a.Amount_Credit, a.Amount_Debit - a.Amount_Credit 'diff'
FROM _YourTable_Name a
where Account_ID = #Account_ID
And Creation_Date >= #Query_Start_Date And Creation_Date <= #Query_End_Date
)
SELECT a.Details_ID, a.Creation_Date, a.Reference_ID, a.Transaction_Kind,
a.Amount_Debit, a.Amount_Credit, SUM(b.diff) 'Balance'
FROM tempDebitCredit a, tempDebitCredit b
WHERE b.Details_ID <= a.Details_ID
GROUP BY a.Details_ID, a.Creation_Date, a.Reference_ID, a.Transaction_Kind,
a.Amount_Debit, a.Amount_Credit
Order By a.Details_ID Desc

Table column to row mysql query

I have 2 tables i need the result table almost converted from column to row converted
Table 1 : master_table
master_id user_name
1 name1
2 name2
3 name3
4 name4
Table 2 : master_meta_table
id master_id meta_key meta_value
1 1 f_name fname1
2 2 f_name fname2
3 2 l_name lname2
4 2 age age2
5 3 l_name lnam3
6 3 age age3
7 4 sex male
I would like to get the result like this
master_id user_name f_name l_name age sex
1 name1 fname1
2 name2 fname2 lname2 age2
3 name3 lname3 age3
4 name4 fname4 male
Please some one help me with this...
Try:
select
mt1.master_id,
mt1.user_name,
max(case when mt2.meta_key = 'f_name' then mt2.meta_value end) as fname,
max(case when mt2.meta_key = 'l_name' then mt2.meta_value end) as lname,
max(case when mt2.meta_key = 'age' then mt2.meta_value end) as age,
max(case when mt2.meta_key = 'sex' then mt2.meta_value end) as sex
from
master_table mt1
join master_meta_table mt2 on mt1.master_id = mt2.master_id
group by
mt1.master_id,
mt1.user_name
Fiddle: http://sqlfiddle.com/#!2/af277e/3/0
Here is your DDL
create table master_table
(
master_id int,
user_name varchar(20)
);
create table master_meta_table
(
id int,
master_id int,
meta_key varchar(20),
meta_value varchar(20)
);
insert into master_table
values (
1,'name1');
insert into master_table
values (
2,'name2');
insert into master_table
values (
3,'name3');
insert into master_table
values (
4,'name4');
insert into master_meta_table
values (
1,1,'f_name','fname1');
insert into master_meta_table
values (
2,2,'f_name','fname2');
insert into master_meta_table
values (
3,2,'l_name','lname2');
insert into master_meta_table
values (
4,2,'age','age2');
insert into master_meta_table
values (
5,3,'l_name','lname3');
insert into master_meta_table
values (
6,3,'age','age3');
insert into master_meta_table
values (
7,4,'sex','male');
your query
select
mt.master_id,
mt.user_name,
max (case when mmt.meta_key = 'f_name' then mmt.meta_value end) as fname,
max (case when mmt.meta_key = 'l_name' then mmt.meta_value end) as lname,
max (case when mmt.meta_key = 'age' then mmt.meta_value end) as age,
max (case when mmt.meta_key = 'sex' then mmt.meta_value end) as sex
from
master_table mt,master_meta_table mmt
where mt.master_id = mmt.master_id
group by mt.master_id,mt.user_name
http://sqlfiddle.com/#!4/55845/8