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;
Related
My first question here.
I got 2 tables with one to many relationship:
policies
id
issue_date
user_id
insurance_type
1
1-2-2021
100
apartment
2
1-2-2021
200
car
policy_details
id
policy_id
type
1
1
type A
1
1
type A
2
1
type B
3
1
type C
1 policy record can have many policy_details records.
I need to count the policies rows with some case,
and I need to join the policy_details as well because I count them also.
Example to simple query:
SELECT
user_id,
COUNT(CASE WHEN `insurance_type` = 'apartment' THEN 1 ELSE NULL END) as totalApartmentType,
COUNT(CASE WHEN policy_details.type = 'typeA' THEN 1 ELSE NULL END) as totalTypeA
FROM `policies`
JOIN `policy_details` ON policy_details.policy_id = policies.id
AND MONTH(`issue_date`) = 2
GROUP BY (`user_id`)
The problem here is that if 1 policy connected to 2 policy_details records for example,
the count will be 2 and it should be 1, cause I need to count the policy record, not the policy_details joined records.
And if policy_details has 5 records connected to policy, the count will be 5. (should be 1).
The result I need for the query above:
user_id
totalApartmentType
totalTypeA
100
1
2
Can it be done guys?
You can use COUNT(DISTINCT) making sure you generate the id instead of 1 in case the condition is fulfilled:
COUNT(DISTINCT CASE WHEN insurance_type = 'apartment'
THEN policies.id
ELSE NULL
END) AS totalApartmentType,
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
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;
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.
How can I count the total number of records, the number of unique of users and number of records on which the status is 2 from the table participants in one query?
I know how to accomplish this using 3 separate queries:
SELECT COUNT() FROM participants
SELECT COUNT() FROM participants GROUP BY user
SELECT COUNT(*) FROM participants WHERE status = 2
But this doesn't really seem efficient?
Table participants
id user status
10 john#example.com 1
11 john#example.com 1
12 john#example.com 1
13 sally#mailing.com 1
14 sally#mailing.com 2
15 edward#halloworld.com 1
16 edward#halloworld.com 1
17 edward#halloworld.com 2
18 mike#bestmail.net 2
19 mike#bestmail.net 1
29 nat#worldcom.com 0
Just use conditional aggregation:
select count(*) as numrecords, count(distinct user) as numusers,
sum(status = 2) as numstatus_2
from participants p;
Since you want just one result (per requirement), you don't need a group by clause at all, and all of these requirements can be created as arguments for the count function:
SELECT COUNT(*) AS total_records,
COUNT(DISTINCT user) AS distinct_users_count,
COUNT(CASE status WHEN 2 ELSE NULL END) AS status_2_count
FROM participants