Trying to make a single query out of these 2 queries - sql

I am trying to get the percentage of calls that fit the allowed time-frame to get answered. But due to one condition, having the call less than 30 seconds, I am having an issue getting it to work. I tried working out the 30 seconds condition in the Select statement but it did not work ( I kept getting 100% every time and after looking at the numbers individually, it was not possible.
Select date, count("speed of answer" < '00:00:30')/ count(calls) as SLA
From five9_data.calllog
Where "call type" = 'Inbound' and campaign in ('Eves Addiction', 'Brook and York') and "service level" = '1' and skill = 'Eves Sales V'
Group By date
Order By date desc
Limit 5000
Here are the 2 queries in full:
Select date, count(calls) as Total
From five9_data.calllog
Where
"call type" = 'Inbound'
and campaign in ('Eves Addiction', 'Brook and York')
and "service level" = '1'
and skill = 'Eves Sales V'
Group By date
Order By date desc
AND
Select date, count("speed of answer") as AnsweredInTime
From five9_data.calllog
Where
"call type" = 'Inbound'
and campaign in ('Eves Addiction', 'Brook and York')
and "service level" = '1'
and skill = 'Eves Sales V'
and "speed of answer" < '00:00:30'
Group By date
Order By date desc
It has the same data source so union did not work, and did not think Join would work.
End game I want to be able to make a query that allows the 2 queries above to work and finally divide AnsweredInTime by Total.

I would recommend writing the query as:
Select date,
count(*) as total_count,
sum( ("speed of answer" < '00:00:30')::int ) as num_AnsweredInTime,
avg( ("speed of answer" < '00:00:30')::int ) as ratio_AnsweredInTime
from five9_data.calllog
where "call type" = 'Inbound' and
campaign in ('Eves Addiction', 'Brook and York') and
"service level" = '1' and
skill = 'Eves Sales V'
Group By date
Order By date desc

The COUNT(exp) function will count the number of rows for which exp is not null -- it doesn't care about true or false. You can verify this by executing the command select count(false) (evaluates to 1) and select count(NULL) (evaluates to 0). So instead of
count("speed of answer" < '00:00:30')
you could try either
count(nullif("speed of answer" < '00:00:30', FALSE))
(if speed is < 00:30 this will NOT be null, and thus will be counted) or
sum(case when "speed of answer" < '00:00:30' then 1 else 0 end)

Select date,
count(*) as total_count,
sum( ("speed of answer" < '00:00:30')::int ) as num_AnsweredInTime,
avg( ("speed of answer" < '00:00:30')::int ) as ratio_AnsweredInTime
from five9_data.calllog
where "call type" = 'Inbound' and
campaign in ('Eves Addiction', 'Brook and York') and
"service level" = '1' and
skill = 'Eves Sales V'
Group By date
Order By date desc

Related

Getting a record set that has two or more different users

I want to find all calls in a given range that have been handled by more than one customer care agent. Using a "HAVING COUNT" gets me half way there but I also get results that have the same person in multiple legs of the same call. I need to filter out only those with to different names. Here my query.
SELECT *
FROM call_legs
WHERE call_id IN (
SELECT DISTINCT(call_id)
FROM call_legs
WHERE call_id IN (
SELECT
call_id
FROM call_legs
WHERE
from_name IN (SELECT name FROM directory WHERE include = 'Yes' AND discription = 'Customer Care')
AND call_legs.start_time >= '10/09/2022 12:00 AM' AND call_legs.start_time <= '10/16/2022 11:59 PM'
AND result = 'Call connected'
GROUP BY call_id
HAVING COUNT (from_name) > 1
)
)
AND from_name IN (SELECT name FROM directory WHERE include = 'Yes' AND discription = 'Customer Care')
AND result = 'Call connected'
ORDER BY start_time ASC

How to solve a nested aggregate function in SQL?

I'm trying to use a nested aggregate function. I know that SQL does not support it, but I really need to do something like the below query. Basically, I want to count the number of users for each day. But I want to only count the users that haven't completed an order within a 15 days window (relative to a specific day) and that have completed any order within a 30 days window (relative to a specific day). I already know that it is not possible to solve this problem using a regular subquery (it does not allow to change subquery values for each date). The "id" and the "state" attributes are related to the orders. Also, I'm using Fivetran with Snowflake.
SELECT
db.created_at::date as Date,
count(case when
(count(case when (db.state = 'finished')
and (db.created_at::date between dateadd(day,-15,Date) and dateadd(day,-1,Date)) then db.id end)
= 0) and
(count(case when (db.state = 'finished')
and (db.created_at::date between dateadd(day,-30,Date) and dateadd(day,-16,Date)) then db.id end)
> 0) then db.user end)
FROM
data_base as db
WHERE
db.created_at::date between '2020-01-01' and dateadd(day,-1,current_date)
GROUP BY Date
In other words, I want to transform the below query in a way that the "current_date" changes for each date.
WITH completed_15_days_before AS (
select
db.user as User,
count(case when db.state = 'finished' then db.id end) as Completed
from
data_base as db
where
db.created_at::date between dateadd(day,-15,current_date) and dateadd(day,-1,current_date)
group by User
),
completed_16_days_before AS (
select
db.user as User,
count(case when db.state = 'finished' then db.id end) as Completed
from
data_base as db
where
db.created_at::date between dateadd(day,-30,current_date) and dateadd(day,-16,current_date)
group by User
)
SELECT
date(db.created_at) as Date,
count(distinct case when comp_15.completadas = 0 and comp_16.completadas > 0 then comp_15.user end) as "Total Users Churn",
count(distinct case when comp_15.completadas > 0 then comp_15.user end) as "Total Users Active",
week(Date) as Week
FROM
data_base as db
left join completadas_15_days_before as comp_15 on comp_15.user = db.user
left join completadas_16_days_before as comp_16 on comp_16.user = db.user
WHERE
db.created_at::date between '2020-01-01' and dateadd(day,-1,current_date)
GROUP BY Date
Does anyone have a clue on how to solve this puzzle? Thank you very much!
The following should give you roughly what you want - difficult to test without sample data but should be a good enough starting point for you to then amend it to give you exactly what you want.
I've commented to the code to hopefully explain what each section is doing.
-- set parameter for the first date you want to generate the resultset for
set start_date = TO_DATE('2020-01-01','YYYY-MM-DD');
-- calculate the number of days between the start_date and the current date
set num_days = (Select datediff(day, $start_date , current_date()+1));
--generate a list of all the dates from the start date to the current date
-- i.e. every date that needs to appear in the resultset
WITH date_list as (
select
dateadd(
day,
'-' || row_number() over (order by null),
dateadd(day, '+1', current_date())
) as date_item
from table (generator(rowcount => ($num_days)))
)
--Create a list of all the orders that are in scope
-- i.e. 30 days before the start_date up to the current date
-- amend WHERE clause to in/exclude records as appropriate
,order_list as (
SELECT created_at, rt_id
from data_base
where created_at between dateadd(day,-30,$start_date) and current_date()
and state = 'finished'
)
SELECT dl.date_item
,COUNT (DISTINCT ol30.RT_ID) AS USER_COUNT
,COUNT (ol30.RT_ID) as ORDER_COUNT
FROM date_list dl
-- get all orders between -30 and -16 days of each date in date_list
left outer join order_list ol30 on ol30.created_at between dateadd(day,-30,dl.date_item) and dateadd(day,-16,dl.date_item)
-- exclude records that have the same RT_ID as in the ol30 dataset but have a date between 0 amd -15 of the date in date_list
WHERE NOT EXISTS (SELECT ol15.RT_ID
FROM order_list ol15
WHERE ol30.RT_ID = ol15.RT_ID
AND ol15.created_at between dateadd(day,-15,dl.date_item) and dl.date_item)
GROUP BY dl.date_item
ORDER BY dl.date_item;

Multiple Sub Queries with Multiple JOINS Oracle

I have a large ORACLE SQL file with multi joins and multiple sub queries. I am having issues joining two of the sub queries. I have tried many different methods but the closest that I have gotten is below. The piece that is giving me trouble is the first portion of the join with the multiple subqueries (the Address Eff Date and the Employee Eff Date. The error message that I am receiving is ORA-00907: missing right parenthesis 00907. 00000 - "missing right parenthesis". I can't find where the right parenthesis is missing and I suspect it is more than that or some other type of syntax issue. The two tables that I have had trouble joinging are the EMPLOYEE_EFF_DATE table and the ADDRESS_EFF_DATE table. Both of these tables have an EFF_DATE field, and for both tables I need to pull the record with the most recent effective date (by SSN field). I believe I have accounted for that with the ROW_NUMBER() OVER (PARTITION method but if there is a more efficient or easier way to to this I am absolutely open to suggestions.
/*Subscriber Code*/
eed.P_COMPANY_ID_I as "Client Company ID"
,cs.REAL_SSN as "Employee SSN"
,cs.REAL_SSN as "Member SSN"
,'Subscriber' as "Person Type"
,eed.LAST_NAME as "Last Name"
,eed.FIRST_NAME as "First Name"
,eed.BIRTHDATE as "Date of Birth"
,eed.SEX as "Gender"
,aed.Address_1 as "Address 1"
,aed.Address_2 as "Address 2"
,aed.City
,aed.State
,aed.Zip
,aed.Country as "Country Code"
,aed.Telephone as "Employee Home Phone"
,eed.EMAIL_ADDRESS as "Employee Email Address"
,CASE
WHEN eed.controlled_group_status = 'L'
OR eed.controlled_group_status = 'P'
then eed.EFF_DATE
ELSE NULL
END
as "Date Last Actively At Work"
/*Remove line below*/
,eed.CONTROLLED_GROUP_STATUS
,CASE
WHEN eed.controlled_group_status = 'L'
OR eed.controlled_group_status = 'P'
then 'LEAVE'
ELSE NULL
END
as "Leave Status"
,CASE
WHEN eed.controlled_group_status = 'L'
OR eed.controlled_group_status = 'P'
then eed.EFF_DATE + 1
ELSE NULL
END
as "Leave Begin Date"
,eed.LATEST_HIRE_DATE as "Employee Date of Hire"
,eed.LAST_TERM_DATE as "Employee Date of Termination"
,mcemd.RATE_1 as "Employee Salary"
,ele.LIFE_EVENT_ID as "Life Event ID"
,ele.LIFE_EVENT_DATE as "Loss of Coverage Date"
FROM
/*Employee_Eff_Date*/
(SELECT *
FROM
(SELECT *
FROM
(SELECT eed1.*,
ROW_NUMBER() OVER (PARTITION BY eed1.SSN ORDER BY EFF_DATE DESC) as seqnum
FROM EMPLOYEE_EFF_DATE eed1)
WHERE seqnum = 1) eed)
JOIN
/*Address_Eff_Date*/
(SELECT *
FROM
(SELECT *
FROM
(SELECT aed1.*,
ROW_NUMBER() OVER (PARTITION BY aed1.SSN ORDER BY EFF_DATE DESC) as seqnum
FROM ADDRESS_EFF_DATE aed1
) aed1
ON aed1.SSN = eed.SSN
WHERE aed1.seqnum = 1) aed)
INNER JOIN COMPANY_EMPLOYMENT_DATA ced
ON eed.SSN = ced.SSN
INNER JOIN MV_COMB_EMP_MAX_DTS mcemd
ON eed.SSN = mcemd.SSN
INNER JOIN EMPLOYEE_LIFE_EVENTS ele
ON ele.SSN = eed.SSN
WHERE eed.P_COMPANY_ID_I = 1234
/*Address_Eff_Date qualifying statement*/
AND aed.ADDRESS_KEY = 0
/*EMPLOYEE_LIFE_EVENTS qualifying statement*/
/*Below line indicates the Life Event Dates (set to the past week)*/
AND ele.LIFE_EVENT_DATE >= sysdate-7
AND ele.LIFE_EVENT_DATE <= sysdate
I think you actually want this. Note you have more level of query nesting than you actually need and I have removed the extra ones:
/*Employee_Eff_Date*/
(SELECT *
FROM
(SELECT eed1.*,
ROW_NUMBER() OVER (PARTITION BY eed1.SSN ORDER BY EFF_DATE DESC) as seqnum
FROM EMPLOYEE_EFF_DATE eed1) eed1
WHERE seqnum = 1) eed
JOIN
/*Address_Eff_Date*/
(SELECT *
FROM
(SELECT aed1.*,
ROW_NUMBER() OVER (PARTITION BY aed1.SSN ORDER BY EFF_DATE DESC) as seqnum
FROM ADDRESS_EFF_DATE aed1
) aed1
WHERE aed1.seqnum = 1) aed ON aed.SSN = eed.SSN

Combine 2 SQL query (PostgreSQL)

I'm trying to find out the bounce rate of the top 10 UTM source. There is no column for bounces in the table so I have to query it. I've created a query to find the TOP 10 UTM source and another query to find bounce rate. I just can't seem to figure out how to combine both of this queries together.
The database table contains:
1) cuuid -cookie ID
2) session - session
3) duration
4) Each row represents a page view
SELECT
TOP 10 regexp_replace(regexp_substr(url, 'utm_source\\=[^\\&]*'), 'utm_source='),
COUNT(DISTINCT(cuuid)) as "Total Unique Visitors",
COUNT(DISTINCT(session)) as "Total Unique Sessions",
COUNT(*) as "Total Page Views",
CAST(COUNT(DISTINCT(session)) AS FLOAT)/CAST(COUNT(DISTINCT(cuuid)) AS FLOAT) AS "Average Sessions per Visitor",
CAST(COUNT(*) AS FLOAT)/CAST(COUNT(DISTINCT(session)) AS FLOAT) AS "Average Pageview per Session",
ROUND(SUM(CASE WHEN duration < 0 THEN 0 ELSE duration END)::FLOAT/COUNT(DISTINCT(session))) AS "Average Duration per Session"
FROM table1
WHERE url ILIKE '%%utm_source%%'
AND ts>='2018-05-01'
AND ts < '2018-06-01'
GROUP BY 1
ORDER BY 2 DESC;
--add bounce rate query into first--
SELECT
CAST((CAST((SUM(bounces)*100) AS FLOAT)/CAST(COUNT(*) AS FLOAT)) AS VARCHAR(5)) + '%' as "Bounce rate"
FROM (
SELECT
MIN(ts) AS "time_first_viewed",
cuuid,
session,
COUNT(*) as "number_of_events",
CASE WHEN count(*) = 1 THEN 1 ELSE 0 END AS bounces
FROM table1
WHERE ts>='2018-05-01'
AND ts < '2018-06-01'
GROUP BY cuuid, session)
For the final result, I need it to be in the same table. And the columns are:
1)UTM Source
2)Unique Visitor
3)Unique Sessions
4)Page View
5)Session/Visitor
6)Pageview/session
7)Avg Duration
8)Bounce Rate
you just do like the below with comma :
hope this works
Select * from
(SELECT
TOP 10 regexp_replace(regexp_substr(url, 'utm_source\\=[^\\&]*'), 'utm_source='),
COUNT(DISTINCT(cuuid)) as "Total Unique Visitors",
COUNT(DISTINCT(session)) as "Total Unique Sessions",
COUNT(*) as "Total Page Views",
CAST(COUNT(DISTINCT(session)) AS FLOAT)/CAST(COUNT(DISTINCT(cuuid)) AS FLOAT) AS "Average Sessions per Visitor",
CAST(COUNT(*) AS FLOAT)/CAST(COUNT(DISTINCT(session)) AS FLOAT) AS "Average Pageview per Session",
ROUND(SUM(CASE WHEN duration < 0 THEN 0 ELSE duration END)::FLOAT/COUNT(DISTINCT(session))) AS "Average Duration per Session"
FROM table1
WHERE url ILIKE '%%utm_source%%'
AND ts>='2018-05-01'
AND ts < '2018-06-01'
GROUP BY 1
ORDER BY 2 DESC)table1
,
(SELECT
CAST((CAST((SUM(bounces)*100) AS FLOAT)/CAST(COUNT(*) AS FLOAT)) AS VARCHAR(5)) + '%' as "Bounce rate"
FROM (
SELECT
MIN(ts) AS "time_first_viewed",
cuuid,
session,
COUNT(*) as "number_of_events",
CASE WHEN count(*) = 1 THEN 1 ELSE 0 END AS bounces
FROM table1
WHERE ts>='2018-05-01'
AND ts < '2018-06-01'
GROUP BY cuuid, session))table2
you defines alias names to your columns and its done.

Work Around for SQL Query 'NOT IN' that takes forever?

I am trying to run a query on an Oracle 10g DB to try and view 2 groups of transactions. I want to view basically anyone who has a transaction this year (2014) that also had a transaction in the previous 5 years. I then want to run a query for anyone who has a transaction this year (2014) that hasn't ordered from us in the last 5 years. I assumed I could do this with the 'IN' and 'NOT IN' features. The 'IN' query runs fine but the 'NOT IN' never completes. DB is fairly large which is probably why. Would love any suggestions from the experts!
*Notes, [TEXT] is a description of our Customer's Company name, sometimes the accounting department didn't tie this to our customer ID which left NULL values, so using TEXT as my primary grouping seemed to work although the name is obscure. CODE_D is a product line just to bring context to the name.
Below is my code:
SELECT CODE_D, sum(coalesce(credit_amount, 0) - coalesce(debet_amount,0)) as TOTAL
FROM
gen_led_voucher_row_tab
WHERE ACCOUNTING_YEAR like '2014'
and TEXT NOT IN
(select TEXT
from gen_led_voucher_row_tab
and voucher_date >= '01-JUN-09'
and voucher_date < '01-JUN-14'
and (credit_amount > '1' or debet_amount > '1')
)
GROUP BY CODE_D
ORDER BY TOTAL DESC
Try using a LEFT JOIN instead of NOT IN:
SELECT t1.CODE_D, sum(coalesce(t1.credit_amount, 0) - coalesce(t1.debet_amount,0)) as TOTAL
FROM gen_led_voucher_row_tab AS t1
LEFT JOIN gen_led_voucher_row_tab AS t2
ON t1.TEXT = t2.TEXT
AND t2.voucher_date >= '01-JUN-09'
AND t2.voucher_date < '01-JUN-14'
AND (credit_amount > '1' or debet_amount > '1')
WHERE t2.TEXT IS NULL
AND t1.ACCOUNTING_YEAR = '2014'
GROUP BY CODE_D
ORDER BY TOTAL DESC
ALso, make sure you have an index on the TEXT column.
You can increase your performance by changing the Not In clause to a Where Not Exists like as follows:
Where Not Exists
(
Select 1
From gen_led_voucher_row_tab b
Where voucher_date >= '01-JUN-09'
and voucher_date < '01-JUN-14'
and (credit_amount > '1' or debet_amount > '1')
And a.Text = b.Text
)
You'll need to alias the first table as well to a for this to work. Essentially, you're pulling back a ton of data to just discard it. Exists invokes a Semi Join which does not pull back any data at all, so you should see significant improvement.
Edit
Your query, as of the current update to the question should be this:
SELECT CODE_D,
sum(coalesce(credit_amount, 0) - coalesce(debet_amount,0)) as TOTAL
FROM gen_led_voucher_row_tab a
Where ACCOUNTING_YEAR like '2014'
And Not Exists
(
Select 1
From gen_led_voucher_row_tab b
Where voucher_date >= '01-JUN-09'
and voucher_date < '01-JUN-14'
and (credit_amount > '1' or debet_amount > '1')
And a.Text = b.Text
)
GROUP BY CODE_D
ORDER BY TOTAL DESC