Customers with 75% of orders- SQL - sql

I have a file that contains customers with orders and I need to find the top 75%. It needs to be at least 75% and orders with the same number will be included. Need to figure out the where statement to select the records.
Cust | Orders | Accum Orders | Accum %
c1 10 10 29%
c2 7 17 45%
c3 5 22 63%
c4 4 26 74%
c5 3 29 83%
c6 3 32 89%
c7 2 34 94%
c8 1 35 100%
I would like to only extract c1-c6. C4 is only 74% and it needs to be 75%. c5-c6 are the same number of orders so they both need to be extracted.
Thanks

You can solve this by writing two queries and then make them union:
SELECT * FROM TABLE1
WHERE
TO_NUMBER(REPLACE(ACCUMP,'%','')) < 75
UNION
SELECT * FROM TABLE1
WHERE ORDERS IN
(
SELECT ORDERS FROM TABLE1
GROUP BY ORDERS
HAVING COUNT(*) > 1
);

Use window functions:
select t.*
from (select t.*,
sum(orders) over (order by orders desc range between unbounded preceding and current row) as running_orders,
sum(orders) over (partition by orders) as all_with_this_order,
sum(orders) over () as total_orders
from t
) t
where (running_orders - all_with_this_order) < 0.75 * total_orders;

You need a subquery with a group by Orders
select Cust
from tab
where Orders =
(
select Orders
from tab
where replace(accum,'%','') >= 75
group by Orders
having count(AccumOrders) > 1
);
Rextester Demo

Related

How to use this in sql -- > max(sum (paid * quantity )) to solve a query

How to get the max value order of each customer ?
select num, max(sum(paid*quantity))
from orders join
pizza
using (order#)
group by customer#;
table
num orderN price
-------- --- -------
1 109 30
1 118 25
3 101 30
3 115 27
4 107 23
5 100 17
5 129 16
output req-
num Pnum price
-------- --- -------
1 109 30
3 101 30
4 107 23
5 100 17
You want to select the record having the highest price in each group of nums.
If your RDBMS supports window functions, that's straight forward with ROW_NUMBER() :
SELECT num, pnum, price
FROM (
SELECT t.*, ROW_NUMBER OVER(PARTITION BY num ORDER BY price DESC) rn
FROM mytable t
) x
WHERE rn = 1
Else, you can take the following approach, that uses a NOT EXISTS condition with a correlated subquery to ensure that the record being joined in the one with the highest price for the current num :
SELECT num, pnum, price
FROM mytable t
WHERE NOT EXISTS (
SELECT 1 FROM mytable t1 WHERE t1.num = t.num AND t1.price > t.price
)

How can I select top 3 for each group based on another column in sqlite?

I'm trying to get top 3 most profitable UserIDs in each country in one table using sqlite. I'm not sure where to use LIMIT 3.
Here is the table I have:
Country | UserID | Profit
US 1 100
US 12 98
US 13 10
US 5 8
US 2 5
IR 9 95
IR 3 90
IR 8 70
IR 4 56
IR 15 40
the result should look like this:
Country | UserID | Profit
US 1 100
US 12 98
US 13 10
IR 9 95
IR 3 90
IR 8 70
One pretty simple method is:
select t.*
from t
where t.profit >= (select t2.profit
from t t2
where t2.country = t.country
order by t2.profit desc
limit 1 offset 2
);
This assumes at least three records for each country. You can get around that with coalesce():
select t.*
from t
where t.profit >= coalesce((select t2.profit
from t t2
where t2.country = t.country
order by t2.profit desc
limit 1 offset 2
), t.profit
);
Since SQLite doesn't support windows function, so you can write a subquery be a seqnum by Country, then get top 3
You can try this query.
select t.Country,t.UserID,t.Profit
from(
select t.*,
(select count(*)
from T t2
where t2.Country = t.Country and t2.Profit >= t.Profit
) as seqnum
from T t
)t
where t.seqnum <=3
sqlfiddle:https://www.db-fiddle.com/f/tmNhRLGG2oKqCKXJEDsjfe/0
LIMIT won't be usefull as it applies to a whole result set.
I would create an auxiliary column "CountryRank" like this:
SELECT *, (SELECT COUNT() FROM Data AS d WHERE d.Country=Data.Country AND d.Profit>Data.Country)+1 AS CountryRank
FROM Data;
And query on that result:
SELECT Country, UserID, Profit
FROM (
SELECT *, (SELECT COUNT() FROM Data AS d WHERE d.Country=Data.Country AND d.Profit>Data.Profit)+1 AS CountryRank FROM Data)
WHERE CountryRank<=3
ORDER BY Country, CountryRank;

Removing pairs of transactions

I am attempting to remove transactions that have been reversed from a table. the table has Account, Date, Amount and Row. If a transaction has been reversed Account will match and Amount will be inverse of each other.
Example Table
Account Date Amount Row
12 1/1/18 45 72 -- Case 1
12 1/2/18 50 73
12 1/2/18 -50 74
12 1/3/18 52 75
15 1/1/18 51 76 -- Case 2
15 1/2/18 51 77
15 1/2/18 -51 78
15 1/2/18 51 79
18 1/2/18 50 80 -- Case 3
18 1/2/18 50 81
18 1/2/18 -50 82
18 1/2/18 -50 83
18 1/3/18 50 84
18 1/3/18 50 85
20 1/1/18 57 88 -- Case 4
20 1/2/18 57 89
20 1/4/18 -57 90
20 1/5/18 57 91
Desired Results Table
Account Date Amount Row
12 1/1/18 45 72 -- Case 1
12 1/3/18 52 75
15 1/1/18 51 76 -- Case 2
15 1/2/18 51 79
18 1/3/18 50 84 -- Case 3
18 1/3/18 50 85
20 1/1/18 57 88 -- Case 4
20 1/5/18 57 91
Removing all instances of inverse transactions does not work when there are multiple transactions when all other columns are the same. My attempt was to count all duplicate transactions, count of all inverse duplicate transactions, subtracting those to get the number of rows I needed from each transactions group. I was going to pull the first X rows but found in most cases I want the last X rows of each group, or even a mix (the first and last in Case 2).
I either need a method of removing pairs from the original table, or working from what I have so far, a method of distinguishing which transactions to pull.
Code so far:
--adding row Numbers
with a as (
select
account a,
date d,
amount f,
row_number() over(order by account, date) r
from table),
--counting Duplicates
b as (
select a.a, a.f, Dups
from a join (
select a, f, count(*) Dups
from a
group by a.a, a.f
having count(*)>1
) b
on a.a=b.a and
b.f=a.f
where a.f>0
),
--counting inverse duplicates
c as (
select a.a, a.f, InvDups
from a join (
select a, f, count(*) InvDups
from a
group by a.a, a.f
having count(*)>1
) b
on a.a=b.a and
-b.f=a.f
where a.f>0
),
--combining c and d to get desired number of rows of each transaction group
d as (
select
b.a, b.f, dups, InvDups, Dups-InvDups TotalDups
from b join c
on b.a=c.a and
b.f=c.f
),
--getting the number of rows from the beginning of each transaction group
select d.a, d.d, d.f
from
(select
a, d, f, row_number() over (group by a, d, f) r2
from a) e
join d
on e.a=d.a and
TotalDups<=r2
You can try this.
SELECT T_P.* FROM
( SELECT *, ROW_NUMBER() OVER(PARTITION BY Account, Amount ORDER BY [Row] ) RN from #MyTable WHere Amount > 0 ) T_P
LEFT JOIN
( SELECT *, ROW_NUMBER() OVER(PARTITION BY Account, Amount ORDER BY [Row] ) RN from #MyTable WHere Amount < 0 ) T_N
ON T_P.Account = T_N.Account
AND T_P.Amount = ABS(T_N.Amount)
AND T_P.RN = T_N.RN
WHERE
T_N.Account IS NULL
The following handles your three cases:
with t as (
select t.*,
row_number() over (partition by account, date, amount order by row) as seqnum
from table t
)
select t.*
from t
where not exists (select 1
from t t2
where t2.account = t.account and t2.date = t.date and
t2.amount = -t.amount and t2.seqnum = t.seqnum
);
Use This
;WITH CTE
AS
(
SELECT
[Row]
FROM YourTable YT
WHERE Amount > 0
AND EXISTS
(
SELECT 1 FROM YourTable WHERE Account = YT.Account
AND [Date] = YT.[Date]
AND (Amount+YT.Amount)=0
)
UNION ALL
SELECT
[Row]
FROM YourTable YT
WHERE Amount < 0
AND EXISTS
(
SELECT 1 FROM YourTable WHERE Account = YT.Account
AND [Date] = YT.[Date]
AND (Amount+YT.Amount)>0
)
)
SELECT * FROM YourTable
WHERE EXISTS
(
SELECT 1 FROM CTE WHERE [Row] = YourTable.[Row]
)

Fetch row with max occurrence in Oracle

I have a table like:
SALES
PROD_CODE SALE_ID
321 30
123 67
321 46
321 82
123 48
321 91
For the code:
SELECT PROD_CODE, COUNT(SALE_ID) AS TOTAL_SALES
FROM SALES
GROUP BY PROD_CODE
ORDER BY COUNT(SALE_ID) DESC;
The output is:
PROD_CODE TOTAL_SALES
321 4
123 2
But, when I am expecting only the prod_code with the maximum number of sales as the output,
like:
PROD_CODE
321
For the code:
SELECT PROD_CODE
FROM (SELECT MAX(COUNT(SALE_ID)) FROM SALES
GROUP BY SALE_ID);
The code isn't working!
In Oracle 12c+, you can do:
select s.prod_code
from sales s
order by count(*) desc
fetch first 1 row only;
In earlier versions, either
select s.*
from (select s.prod_code
from sales s
order by count(*) desc
) s
where rownum = 1;
Or:
select max(prod_code) over (dense_rank first order by cnt desc)
from (select s.prod_code, count(*) as cnt
from sales s
group by s.prod_code
) s
The first two versions fetch the entire row. You can limit it to one or more columns is that is all you want.
You could use stats_mode function to fetch row/column with maximum occurrence.
Here is detailed doc for this function https://docs.oracle.com/database/121/SQLRF/functions188.htm#SQLRF06320

SUM not showing expected value in SQL

I have a table as
ID TOTAL SUM(TOTAL)
1 62 62
1 53 53
2 62 62
2 47 47
I thought the SUM(TOTAL) should look like
ID TOTAL SUM(TOTAL)
1 62 115
1 53 115
2 62 109
2 47 109
This is the query I used
select ID, TOTAL, SUM(TOTAL)
from tablename
GROUP BY TOTAL, ID
You could do a windowed SUM instead:
Select ID, TOTAL, SUM(TOTAL) OVER(PARTITION BY ID)
From tablename
This will give you the results you expected. It will display the ID and TOTAL for each row, along with the SUM of the ID grouping.
A GROUP BY is not necessary for this type of summation.
You'll need to remove the TOTAL column from the group by, and therefore the select list. Because TOTAL is in your select list and group by it can't properly aggregate how you're expecting.
SELECT ID, SUM(TOTAL)
FROM tablename
GROUP BY ID
To get your exact output:
SELECT tablename.ID,
TOTAL,
TOTALSUM
FROM (SELECT ID,
SUM(TOTAL) AS TOTALSUM
FROM tablename
GROUP BY ID) AS t
INNER JOIN
tablename
ON tablename.ID = t.ID;