I have a table called phonecalls which stores records of phone calls history from a company looks like this
ID Number Duration Cost
-------------------------------------
1 123456 13 1
2 222222 39 1
3 333333 69 2
4 222222 36 1
What I want to do is get sum of duration and cost for each number.
SELECT
Number,
SUM(Duration) as [Total_Duration],
SUM(Cost) as [Total_Cost]
FROM
phonecalls
GROUP BY
Number;
Now the catch is I also need which id did i included in each group by for auditing purpose so that others will know which rows are processed. So my question is how to you include ids when you do a group by?
Almighty Stackoverflow please help me.
Thanks in advance.
--EDIT:
Is it possible to get all ids with same number in one cell? something like
ID Number Total_Duration Total_Cost
---------------------------------------------------
1 123456 13 1
2,4 222222 75 2
3 333333 69 2
Hope im not asking for too much.
You're looking for the SUM OVER() function:
SQL Fiddle
SELECT
ID,
Number,
Total_Duration = SUM(Duration) OVER(PARTITION BY Number),
Total_Cost = SUM(Cost) OVER(PARTITION BY Number)
FROM phonecalls
If you want to concatenate the IDs, you can use FOR XML PATH(''):
SQL Fiddle
SELECT
ID = STUFF((
SELECT ',' + CONVERT(VARCHAR(10), ID)
FROM phonecalls
WHERE Number = p.Number
FOR XML PATH('')
), 1, 1, ''),
Number,
Total_Duration = SUM(Duration),
Total_Cost = SUM(Cost)
FROM phonecalls p
GROUP BY Number
Related
We have 2 tables called tbl1 and tbl2. It contains columns such as Visit_ID, Customer ID, and so on. There are instances where a Visit_ID will be associated with multiple Customer IDs.
For example, if customer logs into a website, a unique Visit_ID will be generated for each time he visits the website.
In one visit, multiple customers can login to their accounts and make individual purchases.
There are instances where a visit will be associated to multiple customer IDs. If there are more than 2 instances, append any other retail customer ID instances in this column.
For instances there are visit, which had 200 Customer IDs attached to that visit.
For example, if there are 7 Customer IDs in 1 visit, for Customer 1,
it should have the first customer 1. For Customer 2, we will need to display the 2nd customer ID.
For 3rd to 7, all those 5 will be comma separated.
Can someone help how to frame a SQL query using this logic?
with CTE as (
SELECT
visit_id,
B.visitpg_nbr::INT AS visitpg_nbr,
CUSTOMER_ID,
dense_rank()over( PARTITION BY VISIT_ID order by CUSTOMER_ID) as rank
from
db_name.schema_name.tbl_1 A
JOIN db_name.schema_name.tbl_2 B
ON B.id_column = A.id_column
JOIN db_name.schema_name.tbl_3 C
ON CAST(C.xid as VARCHAR)= A.CUSTOMER_ID
WHERE flg_col = '0'
AND so_cd NOT IN ('0','1','2','3')
AND DATE_COL = '2022-01-17'
and visit_id='12345'
ORDER BY visitpg_nbr
)
select VISIT_ID, arr[0], arr[1], array_to_string( array_slice(arr, 2, 99999), ', ')
from (
select VISIT_ID, array_agg(distinct CUSTOMER_ID) within group(order by CUSTOMER_ID) arr
from CTE
group by 1
);
Thanks for those who have responded. I really appreciate their guidance. The logic worked fine. When I'm joining 3 tables inside CTE, I'm getting lot of duplicates. I want to eliminate the duplicate values.
When I run the below query that I have included inside CTE, I'm getting records which are duplicates.
SELECT
visit_id,
B.visitpg_nbr::INT AS visitpg_nbr,
CUSTOMER_ID,
dense_rank()over( PARTITION BY VISIT_ID order by CUSTOMER_ID) as rank
from
db_name.schema_name.tbl_1 A
JOIN db_name.schema_name.tbl_2 B
ON B.id_column = A.id_column
JOIN db_name.schema_name.tbl_3 C
ON CAST(C.xid as VARCHAR)= A.CUSTOMER_ID
WHERE flg_col = '0'
AND so_cd NOT IN ('0','1','2','3')
AND DATE_COL = '2022-01-17'
and visit_id='12345'
ORDER BY visitpg_nbr
Row VISIT_ID CUSTOMER_ID VISITPG_NBR RANK
**1 12345 100 1 1**
2 12345 100 2 1
3 12345 100 3 1
4 12345 100 4 1
5 12345 100 5 1
**6 67891 101 6 2**
7 67891 101 7 2
8 67891 101 8 2
9 67891 101 9 2
10 67891 101 10 2
**11 78910 102 11 3**
12 78910 102 12 3
13 78910 102 13 3
14 78910 102 14 3
Is there any logic to display the distinct results in the CTE temp table?
The final result should be populated as below.
VISIT_ID First_Customer Second_Customer Other_Customers
1 100 101 102,103,104,105,106
2 200 201 202,203,204,205
First Customer_ID should get displayed in the First_Customer column, Second_Customer_Id should get displayed in Second_Customer column.. All the other customer_ids should be displayed in the final column and it should be comma separated.
Also, I wanted the results to be ordered by visitpg_nbr
You should be able to get this with array_agg(), and then choosing the first, second, and subsequent (array_slice()) elements:
with data as (
select *
from snowflake_sample_data.tpch_sf100.orders
where o_custkey between 5411266 and 5411290
)
select o_custkey, arr[0], arr[1], array_to_string(array_slice(arr, 2, 99999), ', ')
from (
select o_custkey, array_agg(o_orderkey) within group(order by o_orderdate) arr
from data
group by 1
);
You might need to get unique ids in case there are many, you can solve that with a subquery before array_agg().
slightly different to Felipe's answer, not sure which would be more performant. I suspect his, but anyways here is another way to try it.
SELECT visit_id, first_customer, second_customer
,array_agg(other_ids) within group (order by order_id) as other_customer
FROM(
SELECT visit_id,
order_id,
first_value(customer_id) over (partition by visit_id order by order_id) as first_customer,
first_value(customer_id) over (partition by visit_id order by order_id) as second_customer,
IFF(row_number() over (partition by visit_id order by order_id) > 2, customer_id, null) as other_ids
FROM VALUES
(1,100, 1),
(1,101, 2),
(1,102, 3),
(1,103, 5),
(1,104, 6),
(1,105, 6),
(1,106, 7),
(2,200, 1),
(2,201, 2),
(2,202, 3),
(2,203, 4)
v(visit_id, customer_id, order_id)
)
GROUP BY 1,2,3
ORDER BY 1,2,3;
VISIT_ID
FIRST_CUSTOMER
SECOND_CUSTOMER
OTHER_CUSTOMER
1
100
100
[ 102, 103, 104, 105, 106 ]
2
200
200
[ 202, 203 ]
every customer has different first-time purchase date, I want to COUNT the number of purchases they have between the following 10 months after the first purchase?
sample table
TransactionID Client_name PurchaseDate Revenue
11 John Lee 10/13/2014 327
12 John Lee 9/15/2015 873
13 John Lee 11/29/2015 1,938
14 Rebort Jo 8/18/2013 722
15 Rebort Jo 5/21/2014 525
16 Rebort Jo 2/4/2015 455
17 Rebort Jo 3/20/2016 599
18 Tina Pe 10/8/2014 213
19 Tina Pe 6/10/2016 3,494
20 Tina Pe 8/9/2016 411
my code below just use ROW_NUM function to identify the first purchase, but I don't know how to do the calculations or there's a better way to do it?
SELECT client_name,
purchasedate,
Dateadd(month, 10, purchasedate) TenMonth,
Row_number()
OVER (
partition BY client_name
ORDER BY client_name) RM
FROM mytable
You might try something like this - I assume you're using SQL Server from the presence of DATEADD() and the fact that you're using a window function (ROW_NUMBER()):
WITH myCTE AS (
SELECT TransactionID, Client_name, PurchaseDate, Revenue
, MIN(PurchaseDate) OVER ( PARTITION BY Client_name ) AS min_PurchaseDate
FROM myTable
)
SELECT Client_name, COUNT(*)
FROM myCTE
WHERE PurchaseDate <= DATEADD(month, 10, min_PurchaseDate)
GROUP BY Client_name
Here I'm creating a common table expression (CTE) with all the data, including the date of first purchase, then I grab a count of all the purchases within a 10-month timeframe.
Hope this helps.
Give this a whirl ... Subquery to get the min purchase date, then LEFT JOIN to the main table to have a WHERE clause for the ten month date range, then count.
SELECT Client_name, COUNT(mt.PurchaseDate) as PurchaseCountFirstTenMonths
FROM myTable mt
LEFT JOIN (
SELECT Client_name, MIN(PurchaseDate) as MinPurchaseDate GROUP BY Client_name) mtmin
ON mt.Client_name = mtmin.Client_name AND mt.PurchaseDate = mtmin.MinPurchaseDate
WHERE mt.PurchaseDate >= mtmin.MinPurchaseDate AND mt.PurchaseDate <= DATEADD(month, 10, mtmin.MinPurchaseDate)
GROUP BY Client_name
ORDER BY Client_name
btw I'm guessing there's some kind of ClientID involved, as nine character full name runs the risk of duplicates.
I have a table that consists of a customer ID, and the number of hours it took to place an order since they first registered.
An example would be:
UserId | TimeToPay
---------------------------------------------------
2DD6ABBB-C9A4-4373-B188-312DB8222859 | 0
C7438620-6431-4C13-B335-AA1A3E314C58 | 55
6AG22103-62B0-47A0-BE3F-7AE1A7A4C3B7 | 30
300A2E02-0799-47BB-BF36-070706F98149 | 8
43382839-E897-4E5F-A955-C9DDAF9B424B | 0
In the above example, 2 customers have placed an order within an hour of ordering something, and after 55 hours, all customers have placed an order. This table does not contain customers that have not placed an order yet. I am trying to create a query that shows cumulative percentages of how many customers have placed an order in what timespan. So my prefered output would be:
Hours | PercentageOfCustomers
-------------------------------
0 | 40
8 | 60
30 | 80
55 | 100
However, when I use answers like this or this one, I don't get cumulative percentages. How do I get my desired output?
You can use a windowed COUNT(*) to get a rolling total, and divide that by the number of total customers:
Select Distinct TimeToPay As Hours,
((Count(*) Over (Order By TimeToPay Asc) * 1.0) /
(Count(*) Over (Order By (Select Null)) * 1.0))
* 100 As PercentageOfCustomers
From Test
Order by Hours
Try This:
DECLARE #main_table TABLE ( UserId INT, TimeToPay INT)
INSERT INTO #main_table VALUES(1,0),(2,55),(3,30),(4,8),(5,0),(6,30),(7,30)
DECLARE #total INT = ( SELECT COUNT(col) FROM
( SELECT 'Z' col FROM #main_table GROUP BY TimeToPay )A GROUP BY col )
SELECT TimeToPay, (COUNT(TimeToPay)*100)/#total Percentage FROM #main_table
GROUP BY TimeToPay
Hope it helps. :)
I have data set of call customer, I want to make count () to know:
Total number of calls for each customer
Total duration of call for each customer
Total of locations the customer he where in
This my data:
Phone no. - Duration In minutes - Location
1111 3 88
2222 4 33
3333 4 4
1111 7 55
3333 9 4
3333 7 3
the result of query:
phone no- Total number of records -Total duration of calls- Total of location
1111 2 10 2
2222 1 4 1
3333 3 20 2
This is almost similar to fthiella answer. Try like this
select PhoneNo,
count(*) as TotalNumberOfRecords,
sum(DurationInMinutes) as TotalDurationOfCalls,
count(distinct location) as TotalOfLocations from yourtablename
group by PhoneNo
You can use a GROUP BY query with basic aggregated functions, like COUNT(), SUM() and COUNT(DISTINCT) like this:
select phone_no, count(*), sum(duration), count(distinct location)
from tablename
group by phone_no
answer for your question is
select Phone no,count(Duration In minutes),sum(Duration In minutes),count(distinct Location) from Tablename group by Phone no order by Phone no;
I have made temporary table for testing and it gives same output as you mention. look following query :
declare #TEMP table (phone_no int, duration int, location int)
insert into #temp values(1111,3,88),(2222,4,33),(3333,4,4),(1111,7,55),(3333,9,4),(3333,7,3)
select phone_no, count(*), sum(duration), count(distinct location)
from #TEMP
group by phone_no
you just can consider this query :
select phone_no, count(*), sum(duration), count(distinct location)
from #TEMP
group by phone_no
In the following example SQL Fiddle
How should I proceed to obtain the cumulative price for each 'Phone' instead of obtaining the last value?
In the example given below, I would need the following table to be produced:
Phone Price Purchases
50 35 3
51 50 2
52 99 3
55 21 2
53 16 2
54 21 1
56 16 1
58 22 1
57 10 2
This is to be done in SQL-Server 2012
Thanks in advance.
You should be able to use the following:
select c1.phone,
c2.TotalPrice,
c1.purchases
from supportContacts c1
inner join
(
select
max(Fecha) maxFecha,
sum(price) TotalPrice,
phone
from supportContacts
group by phone
) c2
on c1.phone = c2.phone
and c1.Fecha = c2.maxFecha
order by c1.phone;
See SQL Fiddle with Demo.
The subquery gets the Total sum for each phone along with the the max fecha associated with the phone. You then use this and join back to your table on both the phone and the fecha to get the result.
I don't have a SQL Server 2012 handy, but give this a shot:
select
phone,
purchases,
price,
sum(price) over (partition by phone order by phone, price) as running_sum_purchases
FROM
supportContacts
Isn't it just...
SELECT Phone, Sum(Price), Count(Purchases)
FROM supportContacts
GROUP BY Phone
ORDER BY 1
.. or have I missed something?
http://sqlfiddle.com/#!6/7b36f/41
50 35 3
51 50 4
52 99 3
53 16 2
54 21 2
55 21 1
56 16 1
57 10 1
58 22 2
If you need more details per phone, you can add a subquery :
SELECT
Phone,
Sum(Price) as Total,
Count(Purchases) as Purchase_Count,
(SELECT TOP 1 Price
FROM supportContacts sc2
WHERE sc2.phone=sc1.phone
ORDER BY fecha DESC
) as Most_Recent
FROM supportContacts sc1
GROUP BY Phone
ORDER BY Phone
or, for the actual requirement which I've finally worked out :)
SELECT
Phone,
Sum(Price) as Total,
Count(Purchases) as Purchase_Count,
(SELECT Purchases
FROM supportContacts sc2
WHERE sc2.phone=sc1.phone
AND sc2.Fecha=
(SELECT Max(Fecha)
FROM supportContacts sc3
WHERE sc3.phone=sc1.phone
)
) as Last_Purchase
FROM supportContacts sc1
GROUP BY Phone
ORDER BY Phone
.. which is starting to get quite unwieldy, there's probably an optimisation possible, but I'm losing the will to play... LOL
But thanks for the cerebral exercise of trying to do it this way :)
EDIT
I would probably have done it like this, if it had been me...
http://sqlfiddle.com/#!6/7b36f/98
With PhoneGroup as
( SELECT
Phone,
Sum(Price) as Total_Price,
Max(Fecha) as Last_Fecha
FROM supportContacts
GROUP BY Phone
)
SELECT
Phone, Total_Price,
(SELECT Purchases
FROM supportContacts sc2
WHERE sc2.phone=PhoneGroup.phone
AND sc2.Fecha=PhoneGroup.Last_Fecha
) as Last_Purchase
FROM PhoneGroup
ORDER BY Phone