sum values of a column over distinct values of other column - sql

I'm using sybase database, an extraction of my table would be :
ClientNumber|ArticlesBought|TotalAllowed
2223 |2 |20
2223 |1 |20
2226 |3 |25
2226 |2 |25
2227 |1 |20
What I need is to calculate the sum of all the articlesBought and devide it by the sum of the total allowed for the distinct clients.
sum(ArticlesBought) = 9 and sum(TotalAllowed)= 65 and not 110
My first question is can I do this in one query?
I tried using:
select sum(TotalAllowed)
from myTable
group by ClientNumber
but it returns 40, 45 and 20, which is wrong.
Could you please help me ?
Thank you

Select my.ClientNumber , my2.TotalArticlesBought/ClientData.TotalAllowedperClient from tblFabSource my
inner join (select sum(Distinct TotalAllowed)as TotalAllowedperClient,ClientNumber from myTable group by ClientNumber)
ClientData on ClientData .ClientNumber=my.ClientNumber
inner join (select sum(ArticlesBought)as TotalArticlesBought from myTable ) my2
on my2.TotalArticlesBought>0

select SUM(articlesbought), SUM(DISTINCT totalallowed) from tablename
you can use a distinct on the sum of totalallowed

Related

Looking for Postgres query which can provide output like MongoDB group by function

Product table
|_id|name |
|---|------|
|3 |Laptop|
Size table
|_id|product_id|size|
|---|----------|----|
|5 |3 |15 |
|6 |3 |17 |
Query:
select tp._id, tp.name, ts.size from test_product tp
left join test_size ts on tp._id = ts.product_id
group by tp._id, tp.name, ts.size
where tp._id = 3 limit 10 offset 0
Current output:
|_id|name |size|
|---|------|----|
|3 |Laptop|15 |
|3 |Laptop|17 |
Expected output
|_id|name |size |
|---|------|-------|
|3 |Laptop|[15,17]|
Note:
Due to current query I'm getting 2 record for the same product and my limit and offset query logic is getting false and not getting proper count. I'm not well aware of Postgres queries for this kind of situation. So I need solution for this so my limit and offset logic will be correct for fetching data and for this query my count of product will be 1.
Use array_agg():
SELECT
tp._id,
tp.name,
ARRAY_AGG(ts.size ORDER BY ts.size) -- ORDER BY to get consistent results
FROM
test_product tp
LEFT JOIN test_size ts ON tp._id = ts.product_id
GROUP BY
tp._id,
tp.name
WHERE
tp._id = 3
LIMIT 10
OFFSET 0;
The ORDER BY within the aggregation is optional, but it's always nice to get consistent results over and over again.

How to Group by with sum of multi row in another table

I have two tables. Ticket and TicketBasket as following image.
I want to select somthings like this:
|tId|tDate|customerName|expDate|tax|total|
|1 |xxx |xxx      |xxx  |2 |25 |
|2 |xxx |xxx      |xxx  |2 |20 |
|3 |xxx |xxx      |xxx  |2 |15 |
because of my sql command, the result has iteration with tId because each Ticket can have multi Items in it's basket.
my sql code is :
SELECT distinct Ticket.tId,dbo.ToCustomeDate(Ticket.tDate) 'tDate',
Ticket.customerName,dbo.ToCustomeDate(isnull(Ticket.expDate,Ticket.tDate)) 'expDate',
Ticket.tax,
(
(((TicketBasket.gamePrice*TicketBasket.gameCount)-
(((TicketBasket.gamePrice * TicketBasket.gameCount)*TicketBasket.offPrice)/100))+
(((TicketBasket.gamePrice * TicketBasket.gameCount)-
(((TicketBasket.gamePrice * TicketBasket.gameCount)*TicketBasket.offPrice)/100))* (Ticket.tax)/100))
) AS total
FROM Ticket right JOIN TicketBasket
ON Ticket.tId = TicketBasket.tId
but the result is
|tId|tDate|customerName|expDate|tax|total|
|1 |xxx |xxx      |xxx  |2 |10 |
|1 |xxx |xxx      |xxx  |2 |10 |
|1 |xxx |xxx      |xxx  |2 |5  |
|2 |xxx |xxx      |xxx  |2 |10 |
|2 |xxx |xxx      |xxx  |2 |10 |
|3 |xxx |xxx      |xxx  |2 |10 |
|3 |xxx |xxx      |xxx  |2 |5  |
I can handle this with cursor but I know it's a heavy load to execute the select query, so thanks for other solutions.
This should work..based on your query's output:
Select
iq.tld, iq.tDate, iq.customerName, iq.expDate,iq.tax,
SUM(total) as newTotal
from
(
SELECT distinct Ticket.tId,dbo.ToCustomeDate(Ticket.tDate) 'tDate',
Ticket.customerName,dbo.ToCustomeDate(isnull(Ticket.expDate,Ticket.tDate)) 'expDate',
Ticket.tax,
(
(((TicketBasket.gamePrice*TicketBasket.gameCount)-
(((TicketBasket.gamePrice * TicketBasket.gameCount)*TicketBasket.offPrice)/100))+
(((TicketBasket.gamePrice * TicketBasket.gameCount)-
(((TicketBasket.gamePrice * TicketBasket.gameCount)*TicketBasket.offPrice)/100))* (Ticket.tax)/100))
) AS total
FROM Ticket right JOIN TicketBasket
ON Ticket.tId = TicketBasket.tId
)iq
group by iq.tld, iq.tDate, iq.customerName, iq.expDate,iq.tax

Iterating over groups in table

I have the following data:
cte1
===========================
m_ids |p_id |level
---------|-----------|-----
{123} |98 |1
{123} |111 |2
{432,222}|215 |1
{432,222}|215 |1
{432,222}|240 |2
{432,222}|240 |2
{432,222}|437 |3
{432,222}|275 |3
I have to perform the following operation:
Extract p_id by the following algorithm
For every row with same m_ids
In each group:
2.I. Group records by p_id
2.II. Order desc records by level
2.III. Select p_id with exact count as the m_ids length and with the biggest level
So far I fail to write this algorithm completely, but I wrote (probably wrong where I'm getting array_length) this for the last part of it:
SELECT id
FROM grouped_cte1
GROUP BY id,
level
HAVING Count(*) = array_length(grouped_cte1.m_ids, 1)
ORDER BY level DESC
LIMIT 1
where grouped_cte1 for m_ids={123} is
m_ids |p_id |level
---------|-----------|-----
{123} |98 |1
{123} |111 |2
and for m_ids={432,222} is
m_ids |p_id |level
---------|-----------|-----
{432,222}|215 |1
{432,222}|215 |1
{432,222}|240 |2
{432,222}|240 |2
{432,222}|437 |3
{432,222}|275 |3
etc.
2) Combine query from p.1 with the following. The following extracts p_id with level=1 for each m_ids:
select m_ids, p_id from cte1 where level=1 --also selecting m_ids for joining later`
which results in the following:
m_ids |p_id
---------|----
{123} |98
{432,222}|215
Desirable result:
m_ids |result_1 |result_2
---------|-----------|--------
{123} |111 |98
{432,222}|240 |215
So could anyone please help me solve the first part of algorithm and (optionally) combine it in a single query with the second part?
EDIT: So far I fail at:
1. Breaking the presented table into subtables by m_ids while iterating over it.
2. Performing computation of array_length(grouped_cte1.m_ids, 1) for corresponding rows in query.
For the first part of the query you're on the right track, but you need to change the grouping logic and then join again to the table to filter it out by highest level per m_ids for which you could use DISTINCT ON clause combined with proper sorting:
select
distinct on (t.m_ids)
t.m_ids, t.p_id, t.level
from cte1 t
join (
select
m_ids,
p_id
from cte1
group by m_ids, p_id
having count(*) = array_length(m_ids, 1)
) as g using (m_ids, p_id)
order by t.m_ids, t.level DESC;
This would give you:
m_ids | p_id | level
-----------+------+-------
{123} | 111 | 2
{432,222} | 240 | 2
And then when combined with second query (using FULL JOIN for displaying purposes, when the first query is missing such conditions) which I modified by adding distinct since there can be (and in fact is) more than one record for m_ids, p_id pair with first level it would look like:
select
coalesce(r1.m_ids, r2.m_ids) as m_ids,
r1.p_id AS result_1,
r2.p_id AS result_2
from (
select
distinct on (t.m_ids)
t.m_ids, t.p_id, t.level
from cte1 t
join (
select
m_ids,
p_id
from cte1
group by m_ids, p_id
having count(*) = array_length(m_ids, 1)
) as g using (m_ids, p_id)
order by t.m_ids, t.level DESC
) r1
full join (
select distinct m_ids, p_id
from cte1
where level = 1
) r2 on r1.m_ids = r2.m_ids
giving you result:
m_ids | result_1 | result_2
-----------+----------+----------
{123} | 111 | 98
{432,222} | 240 | 215
that looks different from what you've expected but from my understanding of the logic it is the correct one. If I misunderstood anything, please let me know.
Just for the sake of logic explanation, one point:
Why m_ids with {123} returns 111 for result_1?
for group of m_ids = {123} we have two distinct p_id values
both 98 and 111 account for the condition of equality count with the m_ids length
p_id = 111 has a higher level, thus is chosen for the result_1

Select rows that are duplicates on two columns

I have data in a table. There are 3 columns (ID, Interval, ContactInfo). This table lists all phone contacts. I'm attempting to get a count of phone numbers that called twice on the same day and have no idea how to go about this. I can get duplicate entries for the same number but it does not match on date. The code I have so far is below.
SELECT ContactInfo, COUNT(Interval) AS NumCalls
FROM AllCalls
GROUP BY ContactInfo
HAVING COUNT(AllCalls.ContactInfo) > 1
I'd like to have it return the date, the number of calls on that date if more than 1, and the phone number.
Sample data:
|ID |Interval |ContactInfo|
|--------|------------|-----------|
|1 |3/1/2017 |8009999999 |
|2 |3/1/2017 |8009999999 |
|3 |3/2/2017 |8001234567 |
|4 |3/2/2017 |8009999999 |
|5 |3/3/2017 |8007771111 |
|6 |3/3/2017 |8007771111 |
|--------|------------|-----------|
Expected result:
|Interval |ContactInfo|NumCalls|
|------------|-----------|--------|
|3/1/2017 |8009999999 |2 |
|3/3/2017 |8007771111 |2 |
|------------|-----------|--------|
Just as juergen d suggested, you should try to add Interval in your GROUP BY. Like so:
SELECT AC.ContactInfo
, AC.Interval
, COUNT(*) AS qnty
FROM AllCalls AS AC
GROUP BY AC.ContactInfo
, AC.Interval
HAVING COUNT(*) > 1
The code should like this :
select Interval , ContactInfo, count(ID) AS NumCalls from AllCalls group by Interval, ContactInfo having count(ID)>1;

Count and max aggregate function in same table in one query

I have to do count and max aggregate function in same query. For example I have history table contains date column. I need to retrieve the latest date as well as count () with some criteria. Criteria is applicable for only count() . I am able to retrieve the latest date using max and rank function.But could not merge both. Could you please assist?
Update:
Scenario : Customer buys/sells Shares.
Input: Table Share_history and Table Customer and Table Share and Table Share_Status
Customer :
Cust_id |Cust_name
1 |A
2 |B
Share :
Share_id|Share_Name|Owner|
10 |ABC |XYZ |
20 |BCD |MNC |
Share_Status :
Share_Status_Id|Share_Status_Name
1 |Buy
2 |Sell
Share_history :
Share_history _id|Share_id|Trans_date|Share_status_Id|Cust_id
100 |10 |12/12/14 | 1 |1
101 |10 |24/12/14 | 2 |1
102 |10 |14/01/15 | 1 |1
103 |10 |28/02/15 | 2 |1
103 |10 |16/03/15 | 1 |1
Output: latest Trans_date and count(no of times specific share was bought(1)) and Cust_id=1.
Query:
select share1.Share_id,SHAREHIST.Latest_Date,SHAREHIST.buycount
from Share share1 left outer join
(select share_id,max(Trans_date) keep(dense_rank last order by share_id) as Latest_Date,
(select count(*) as buycount from Share_history where Share_status_id=1 and Share_id=share1.Share_id)
from Share_history
group by Share_id
) SHAREHIST
on SHAREHIST.share_id=share1.share_id
EXPECTED :
Share_id|Latest_Date|buycount
10 |16/03/15 | 3
Try using this:
SELECT
Share_id
,Trans_Date
,COUNT(Share_id) buycount
FROM
(
SELECT
*
FROM Share_history SH
WHERE Trans_Date = (SELECT MAX(Trans_Date) FROM Share_history)
) SH
GROUP BY Share_id, Trans_Date
Rest of the joins I think you can add.
I think you just want aggregation:
select sh.share_id, max(trans_date) as trans_date, count(*) as buy_count,
from share_history sh
where cust_id = 1
group by sh.share_id;