MySQL sorting distinct/unique values - mysql

Decided to break my query in to bits, to help communicate what I am trying to achieve.
I have some information about a Customer and the Coupon Code they've used, in this format
Customer
Coupon Code
1
FreeDel
1
FreeDel
1
FreeDel
1
1562733
1
8842939
1
847hr64
1
83jd63j
1
FreeDel
1
8eh33jr
1
AA-2637
1
AA-9837
1
Save200
1
Save200
I want to sort it so that: If a known coupon-code prefix is available, then using syntax like this:
CASE WHEN Coupon Code LIKE 'AA-%' THEN 'AA-'
CASE WHEN Coupon Code IS UNIQUE THEN 'UNIQUE'
CASE WHEN Coupon Code IS NOT UNIQUE THEN 'NON-UNIQUE'
And so to output
Count
Customer
Coupon Code Type
6
1
Non-Unique
2
1
AA-
5
1
Unique
In this ideal, the known prefixes are added first as cases, and then unknown, unrepeated Coupon Codes are labelled Unique and then repeated Coupon Codes are labelled Non-Unique.
Any help would be super appreciated! :)
Table edits

You could count them separately:
select sum(cnt), customer, 'Non-Unique'
from (
select customer, coupon_code, count(*) as cnt
from ccodes
where coupon_code not like 'AA-%'
group by customer, coupon_code
having cnt>1
) as q
group by customer
union
select count(*), customer, 'AA-'
from ccodes
where coupon_code like 'AA-%'
group by customer
union
select sum(cnt), customer, 'Unique'
from (
select customer, coupon_code, count(*) as cnt
from ccodes
where coupon_code not like 'AA-%'
group by customer, coupon_code
having cnt=1
) as q
group by customer
See db-fiddle

You can use aggregation and conditional logic:
(case when sum( code like 'AA-%' ) > 0 then 'AA-'
when min(code) = max(code) then 'UNIQUE'
else 'NON-UNIQUE'
end)
You can incorporate this into an aggregation query as:
select grp, count(*)
from (select c.customer,
(case when sum( code like 'AA-%' ) > 0 then 'AA-'
when min(code) = max(code) then 'UNIQUE'
else 'NON-UNIQUE'
end) as grp,
count(*)
from c
group by customer
) x
group by grp;

Related

Divide one table by another table created in the same query

I have the following SQL query:
SELECT `NeighbourhoodName`,
count(NAME) as `Number of Parks`,
sum(CASE
WHEN `parks`.`Advisories` = 'Y' THEN 1
ELSE 0
END) as Advisories,
FROM parks
GROUP BY `NeighbourhoodName`;
In the second line of the code, I create a column called "Number of Parks". I would like all the values in the next column (Advisories) to be divided by the values in "Number of parks". However, when I try to insert the division statement after the column like this:
SELECT `NeighbourhoodName`,
count(NAME) as `Number of Parks`,
sum(CASE
WHEN `parks`.`Advisories` = 'Y' THEN 1
ELSE 0
END)/`Number of Parks` as Advisories
FROM parks
GROUP BY `NeighbourhoodName`;
I get the following error:
Unknown column, `Number of Parks` in field list.
How can I perform this division while still keeping it in one query?
You need to use an outer query to do the division.
SELECT `NeighbourhoodName`,
`Number of Parks`,
Advisories/`Number of Parks` as Advisories
FROM ( SELECT `NeighbourhoodName`,
count(NAME) as `Number of Parks`,
sum( CASE WHEN `parks`.`Advisories` = 'Y' THEN 1 ELSE 0 END ) as Advisories
FROM parks
GROUP BY `NeighbourhoodName`
) as tbl;
Problems with Column Aliases
An alias can be used in a query select list to give a column a
different name. You can use the alias in GROUP BY, ORDER BY, or HAVING
clauses to refer to the column.
Or use the expression of count(Name) instead of Number of Parks:
select NeighbourhoodName,
count(Name) as `Number of Parks`,
sum(case when Advisories='Y' then 1 else 0 end)
/count(Name) as Advisories
from parks
group by NeighbourhoodName;

Summing of count result at same level

I'm trying to sum the results of count(id) at the same level, in order to find out the relative portion of the count(id) from the overall count.
The count is grouped by the respective previous number, and I want to stay at the same table and have it all together.
`
select totalattempts, count(totalattempts) allattempts, count(case when success>0 then totalattempts else null end) successfulattempts
from (
select *, case when success> 0 then attemptspresuccess+1 else attemptspresuccess end totalattempts
from (select orderid, count(orderid) attemptspresuccess, count(case when recoveredPaymentId is not null then recoveredPaymentId end ) success from (
select orderid, recoveredPaymentId
from errors
where platform = 'woo'
) alitable
group by orderid) minitable ) finaltable
group by totalattempts
order by totalattempts asc
`
I need to add another column that basically would have, to put it simply, count(totalattempts)/sum(count(totalattempts).
I'm running out of ideas basically.
I can't use windows as this is an app of retool which doesn't support that
Assuming some test data here:
DECLARE #table TABLE (AttemptNumber INT IDENTITY, Success BIT)
INSERT INTO #table (Success) VALUES
(0),(0),(0),(0),(1),(1),(0),(0),(0),(0),(0),(1),(0),(1),(0),(0),
(0),(0),(1),(0),(0),(0),(0),(1),(0),(1),(0),(0),(0),(1),(0),(0)
I sounds like you want to know how many attempts there were, how many were successful and what that is a percentage?
SELECT COUNT(Success) AS TotalCount,
COUNT(CASE WHEN Success = 1 THEN 1 END) AS SuccessCount,
COUNT(CASE WHEN Success = 1.0 THEN 1 END)/(COUNT(Success)+.0) AS SuccessPct
FROM #table
TotalCount SuccessCount SuccessPct
--------------------------------------
32 8 0.2500000000000

Mysql group by and sum two different columns

I have this table called transactions, where agents can give certain amounts to other agents, we have 2 columns, one called agent_from which is the agent that put the amount and agent_to is the one reciving the amount.
An example with the id 1 would be that the agent2 is giving an amount of 300 to the agent8
The report that I would like to do is a sum and a group by agent_from and agent_to
Right now I am able to make the query separatly like this
SELECT agent_from,
SUM(amount) as from_transaccions
FROM `transactions` GROUP BY agent_from;
This would give me this result:
This return a sum of all the amounts made by agent_from.
Now I can repeat this query changing the column name from agent_from to agent_to so I can get the sum of all the amounts recived by agent_to, that will look like this:
An example would be that the agent8 recived 2 transaccions (300 + 450) = 750
Now what I want to do is make this 2 querys into one that will look like this:
Refer query below -
with data_cte as (
(select agent_from agent, amount, 'af' flag from transactions) union all
(select agent_to agent, amount, 'at' flag from transactions)
)
select agent,
sum(case when flag='af' then amount else 0 end) from_sum,
sum(case when flag='at' then amount else 0 end) to_sum
from data_cte
group by agent
union all
select 'total' as col1,
sum(case when flag='af' then amount else 0 end) from_sum,
sum(case when flag='at' then amount else 0 end) to_sum
from data_cte
group by col1
order by agent
fiddle.
Use UNION ALL to split each row of the table to 2 rows so that you separate the 2 agents and aggregate:
SELECT COALESCE(agent, 'total') agent,
SUM(`from`) `from`,
SUM(`to`) `to`
FROM (
SELECT agent_from agent, amount `from`, 0 `to` FROM `transactions`
UNION ALL
SELECT agent_to, 0 `from`, amount `to` FROM `transactions`
) t
GROUP BY agent WITH ROLLUP
ORDER BY GROUPING(agent);
See the demo.

Count Group By and Separate If Included in Both Group

Not sure if this question is duplicated yet or not.
I have a simplified table below
User
Interest
Jason
Art
Jason
Sport
Sam
Sport
Sam
Art
Steve
Sport
Desmond
Sport
Tania
Art
Here's the result that I want to achieve
Interest
Count
Art
2
Sport
2
Both
2
I Managed to make a subquery to achieve the value for the Both data by this query
SELECT COUNT(USER) FROM (
SELECT User, COUNT(DISTINCT Interest) as interest_type FROM table WHERE interest_type = 2)
But for the user that are exclusively have Interest in Art and in Sport it's not separated.
You could use conditional aggregation here:
WITH cte AS (
SELECT User,
CASE WHEN COUNT(CASE WHEN Interest = 'Art' THEN 1 END) > 0 AND
COUNT(CASE WHEN Interest = 'Sport' THEN 1 END) > 0
THEN 'Both'
WHEN COUNT(CASE WHEN Interest = 'Art' THEN 1 END) > 0
THEN 'Art'
ELSE 'Sport' END AS Interest
FROM yourTable
GROUP BY User
)
SELECT Interest, COUNT(*) AS Count
FROM cte
GROUP BY Interest;
On MySQL or BigQuery, we can shorten the above to:
WITH cte AS (
SELECT User,
CASE WHEN SUM(Interest = 'Art') > 0 AND SUM (Interest = 'Sport') > 0
THEN 'Both'
WHEN SUM(Interest = 'Art') > 0
THEN 'Art'
ELSE 'Sport' END AS Interest
FROM yourTable
GROUP BY User
)
SELECT Interest, COUNT(*) AS Count
FROM cte
GROUP BY Interest;
Assuming your database supports the over() clause:
select
case when num_interests = 1 then interest else 'both' end as interest
, count(distinct user) as "Count"
from (
select
interest
, user
, count(*) over(partition by user) as num_interests
from yourTable
) d
group by
case when num_interests = 1 then interest else 'both' end

SQL Query for sorting and getting unique count

I have a table which consists of the following details
Customer
Deal
DealStage
A
D1
Lost
A
D2
Won
A
D3
Contacted
B
D4
Conatcted
B
D5
Lost
C
D6
Lost
D
D7
Lost
I have to develop a query where I should get the unique highest stage for each customer. The Stage priority is Won > Contacted > Lost. For Example, A is having three deals which are Won, Lost, and Contacted. So I should be considering Won. Similarly Contacted for B and Lost for C and D
Is it possible to get an Output like
Customer
Highets Stage
A
Won
B
Contacted
C
Lost
D
Lost
By this, I can generate a pivot table that looks like
Stage
CustomerCount
Won
1
Contacted
1
Lost
2
Thanks in Advance
One option uses aggregation and field():
select customer,
case min(field(deal_stage, 'Won', 'Contacted', 'Lost'))
when 1 then 'Won'
when 2 then 'Contacted'
when 3 then 'Lost'
end as highest_stage
from mytable
group by customer
Actually we could combine this with elt():
select customer,
elt(
min(field(deal_stage, 'Won', 'Contacted', 'Lost')),
'Won', 'Contacted', 'Lost'
) as highest_stage
from mytable
group by customer
You can then generate the final result with another level of aggregation:
select highest_stage, count(*)
from (
select customer,
elt(
min(field(deal_stage, 'Won', 'Contacted', 'Lost')),
'Won', 'Contacted', 'Lost'
) as highest_stage
from mytable
group by customer
) t
group by highest_stage
Use windows function as follows:
select * from
(select t.*,
row_number() over (partition by customer
order by case when dealstage = 'Won' then 1
when dealstage = 'Contacted' then 2
when dealstage = 'Lost' then 3
end
) as rn
from your_table t)
where rn = 1;
These are really two different problems. I would, in fact, recommend different approaches to the two. For the first, conditional aggregation:
select customer,
coalesce(max(case when state = 'Won' then state end),
max(case when state = 'Contacted' then state end),
max(case when state = 'Lost' then state end)
) as biggest_state
from t
group by customer;
However, for your final result, I would recommend a correlated subquery:
select t.state, count(*)
from t
where t.state = (select t2.state
from t2
where t2.customer = t.customer
order by field(state, 'Won', 'Contact', 'Lost')
limit 1
)
group by t.state;
Note: This assumes that the original data does not have duplicate rows. If it does, then count(distinct) is one adjustment.