Count and divide in select statement - sql

I need to display number of contacts per month.
I have the below query which is giving me incorrect results.
SELECT
a.DATE_YYYYMM,
CONVERT(DECIMAL, COUNT(a.id)) / COUNT(DISTINCT a.id) Average_contacts_per_member_per_month,
COUNT(a.id) Count_Total_Contacts_Per_Month,
a.id
--INTO #temp_Contacts
FROM
(SELECT DISTINCT
*,
ISNULL(CONVERT(NVARCHAR(6), l.SERVICE_DATE, 112),'') AS SERVICE_DATE_YYYYMM
FROM l) a
WHERE
1=1
AND a.IS_V = 1
GROUP BY
id, a.DATE_YYYYMM
My results for average and counts are the same and I know they should differ.
Any thoughts?

You are grouping by a.id, so the count is always going to be 1.
You want something more like:
SELECT a.DATE_YYYYMM,
CONVERT(DECIMAL, COUNT(a.id))/COUNT(DISTINCT a.id) as Average_contacts_per_member_per_month,
COUNT(a.id) as Count_Total_Contacts_Per_Month
FROM (SELECT DISTINCT *,
COALESCE(CONVERT(NVARCHAR(6), l.SERVICE_DATE, 112), '') AS SERVICE_DATE_YYYYMM
FROM [MCS].[JXM1563].[LTIH_SSIS] l
) a
WHERE a.IS_V = 1
GROUP BY a.DATE_YYYYMM

Related

How to assign 0 to summation of a field if no entry exists for the group by field in teradata SQL query result

I have below query which is used for getting summation of an amount column but as you can see also in the attached screenshot that, there's no entry for NATURAL PERSON for Corporates as there aren't any entry in the table for NATURAL PERSON for CUST_TYPE=Corporates. Please suggest how to get NATURAL PERSON row also for Coporates with 0 assigned against it. Searched for similar questions but didn't get the result with provided suggestions
SELECT CUST_TYPE,FINAL_SME_CATEGORY, SUM(CUST_COMPENSATABLE_AMT) AS TOTAL_SUM FROM ddewd10s.FSCS_LIMIT_UTIL_SCV WHERE FINAL_SME_CATEGORY IN ('SMALL','NATURAL PERSON') GROUP BY 1,2 ORDER BY 1,2;
I tried few queries with ZEROIFNULL, NVL, COALESCE but all of them also gave the same result. Even tried writing CASE statements still didn't get the desired result.
SELECT CUST_TYPE,FINAL_SME_CATEGORY, COALESCE(SUM(CUST_COMPENSATABLE_AMT), 0) AS TOTAL_SUM FROM ddewd10s.FSCS_LIMIT_UTIL_SCV WHERE FINAL_SME_CATEGORY IN ('SMALL','NATURAL PERSON') GROUP BY 1,2 ORDER BY 1,2;
SELECT CUST_TYPE,FINAL_SME_CATEGORY, ZEROIFNULL(SUM(CUST_COMPENSATABLE_AMT)) AS TOTAL_SUM FROM ddewd10s.FSCS_LIMIT_UTIL_SCV WHERE FINAL_SME_CATEGORY IN ('SMALL','NATURAL PERSON') GROUP BY 1,2 ORDER BY 1,2;
SELECT CUST_TYPE,FINAL_SME_CATEGORY, NVL(SUM(CUST_COMPENSATABLE_AMT),0) AS TOTAL_SUM FROM ddewd10s.FSCS_LIMIT_UTIL_SCV WHERE FINAL_SME_CATEGORY IN ('SMALL','NATURAL PERSON') GROUP BY 1,2 ORDER BY 1,2;
SELECT CUST_TYPE, FINAL_SME_CATEGORY, CASE WHEN SUM(CUST_COMPENSATABLE_AMT)=0 THEN 0 ELSE SUM(CUST_COMPENSATABLE_AMT) END AS TOTAL_SUM FROM ddewd10s.FSCS_LIMIT_UTIL_SCV WHERE FINAL_SME_CATEGORY IN ('SMALL','NATURAL PERSON') GROUP BY 1,2 ORDER BY 1,2;
first do cross join cust_type and final_sme_catgory.
select distinct cust_type from table cross join
(select distinct final_sme_catgory from table) temp.
After that left join with your group by query and join with cust_type and final_sme_catgory . use nvl function to display total_sum or 0 value.
sample query:
with cte cross_table (
select distinct cust_type from table cross join
(select distinct final_sme_catgory from table) temp.
),
group_by_result(
--
select cust_type ,final_sme_catgory,sum(value) as total from table group by ust_type ,final_sme_catgory),
select cte.cust_type ,cte.final_sme_catgory,nvl(r.total ,0) as total
from cross_table cte left join group_by_result r on cte.cust_type =r.cust_type
and cte.final_sme_catgory=r.final_sme_catgory

SQL query when joining two tables

I need to join two tables in SQL and I need to find the counts of how many customer id's in table A are also found in table B, extracting how many Customer id in A's also purchased in table B by year. My query is as follows:
SELECT
a.year, count(distinct(a.id),
count (distinct(b.id)
FROM
purchase as A,
purchase2 as B
WHERE
(a.id=b.id)
AND
a.year>2010
GROUP BY a.year
Is this correct? do I need to include count(distinct(b.id) in the select statement? do I also need to group by b.year?
thanks in advance for any assistance
Change your distinct, and you can do an inner join to be sure :
SELECT
A.year,
count(DISTINCT A.id),
count (DISTINCT B.id)
FROM
purchase as A
INNER JOIN purchase2 B ON B.id = A.id
WHERE
A.year>2010
GROUP BY
A.year,
B.year
I think union all and aggregation is the best approach. Start with the information per id/year:
select id, year, max(in_a), max(in_b)
from ((select distinct id, year, 1 as in_a, 0 as in_b
from purchase
) union all
(select distinct id, year, 0 as in_a, 1 as in_b
from purchase2
)
) ab
group by id, year;
Then aggregate this by year:
select year,
sum(in_a) as total_a,
sum(in_b) as total_b,
sum(in_a * in_b) as in_both
from (select id, year, max(in_a), max(in_b)
from ((select distinct id, year, 1 as in_a, 0 as in_b
from purchase
) union all
(select distinct id, year, 0 as in_a, 1 as in_b
from purchase2
)
) ab
group by id, year
) iy
group by year;

Put together two selects into one

Could you help me put the second select into first one? I need calculate rate of type in first select. Second select works good.
First select:
WITH "global" AS (
SELECT
m.id
,json_build_array(
ce.payload->>'Name',
ce.payload->>'Date',
ce.payload->>’Type,
ce.payload->>’Rate’,
row_number() over (partition by m.id order by ce.payload->>’Date’ desc)) as "value"
FROM public."events" ce
LEFT OUTER JOIN "external"."mapping" m
ON ce.id=m.id
WHERE ce.type IN ('cs_calls','pc_calls')
AND coalesce(ce.payload ->> 'Name', '')!=''
AND m.id IS NOT NULL
)
SELECT
id,
value
FROM “global”
Second select:
select
id,
cast(issue as float)/cast(total_count as float) as Rate
from (select
id,
sum(case when type='Issue' then 1 else 0 end) as issue,
count(*) total_count
from events
GROUP BY id)
If Id is the way to join this tables then you can try the following
select
g.id,
g.value,
((issue * 1.0) / total_count) as Rate
from
(
select
id,
sum(case when type='Issue' then 1 else 0 end) as issue,
count(*) total_count
from events
group by
id
) e
join global g
on e.id = g.id

Rank displaying for all user fine. But how do I display rank for one user?

I have this SQL query:
SELECT
DENSE_RANK() OVER (ORDER BY s.rows DESC) AS Ranks,
Territory, TM_Name,
COALESCE(g.rows, 0) AS RXCount,
COALESCE(s.rows, 0) AS DelCounts,
COALESCE(nd.rows, 0) AS NotDeliveredCount,
COALESCE(trgt.rows, 0) AS Target,
e.TM_Emp_Id
FROM
tblEmployee e
LEFT JOIN
(SELECT EmpCode, SUM(RxGenerate) AS rows
FROM tbl_RX
GROUP BY EmpCode) g ON g.EmpCode = e.TM_Emp_Id
LEFT JOIN
(SELECT EmpCode, SUM(MedToPCount) AS rows
FROM tbl_MedicinToPatient
WHERE Status = 'Delivered'
GROUP BY EmpCode) s ON s.EmpCode = e.TM_Emp_Id
LEFT JOIN
(SELECT EmpCode, COUNT(*) AS rows
FROM tbl_MedicinToPatient
WHERE Status != 'Delivered'
GROUP BY EmpCode) nd ON nd.EmpCode = e.TM_Emp_Id
LEFT JOIN
(SELECT
EmpCode, CurrentTarget AS rows,
CreatedDate, RankOrder, T.PreviousTarget
FROM
(SELECT
EmpCode, CurrentTarget, CreatedDate,PreviousTarget,
RANK() OVER (PARTITION BY EmpCode ORDER BY CreatedDate DESC) RankOrder
FROM
tbl_Target) T
WHERE
RankOrder = 1) trgt ON trgt.EmpCode = e.TM_Emp_Id
It returns the desired output. That is for every user it calculates rank perfectly. But when I add where condition in the end of query such as:
e.TM_Emp_Id = 101
It display a rank of 1. And for every user I get the same result (i.e. Rank 1).
But I want to display original rank. How do I achieve this? Thanks in advance!
You have at least 3 easy options for this.
Encapsulate the whole query into a subquery so that it looks like
select *
from (current code)
where TM_Emp_ID = 101
Same as above except make it a CTE:
WITH MY_QUERY AS
(current code)
SELECT *
FROM MY_QUERY
WHERE TM_EMP_ID = 101
same as both the 2 above except use a temp table
You must rank all users in order to know the rank of a particaular user. So select from your query:
select *
from ( your query here ) q
where tm_emp_id = 101;

How to output results by order of year and count of records?

I'm trying to write a query that gives me the count of records where execoffice_status=1
(could equal =0 too).
I want to output the results by using a different table employee which gives me their
names.
The query I wrote seems to give me some results but gives me all the records in the table
even where execoffice_status=0 (not sure how I would add that to the query).
What I'm trying to get out off the query is the count of records that execoffice_status=1
and from what year (execoffice_date), what eventually i would like from the query is the top 10
from each year (order by year).
With the query below I get all the record and even where execoffice_status=0
query:
SELECT *
FROM (
select ROW_NUMBER() OVER(PARTITION BY e.emp_namelast order by year(c.execoffice_date) desc ) as RowNum,
year(c.execoffice_date) as year, e.emp_nameFirst + ' ' + e.emp_namelast as fullname, count(c.execoffice_status) as stars
from phonelist.dbo.employee e
join intranet.dbo.CSEReduxResponses c on c.employee = e.emp_id
group by emp_namelast, emp_namefirst, year(c.execoffice_date)
) a
order by year
Here is a http://sqlfiddle.com/#!3/79f253/1 that I made with some dummy data.
For the first bit of your question you can simply add a where clause.
where c.execoffice_status=1
To get the top values for each year, Rank can accomplish this:
SELECT *
FROM (
select RANK() OVER(PARTITION BY year(c.execoffice_date) order by e.emp_namelast desc ) as Rank,
year(c.execoffice_date) as year, e.emp_nameFirst + ' ' + e.emp_namelast as lastName, sum(c.execoffice_status) as stars
from employee e
join CSEReduxResponses c on c.employeee = e.emp_id
where c.execoffice_status=1
group by emp_namelast, emp_namefirst, year(c.execoffice_date)
) a
where rank <= 2
order by year
fiddle
This numbers the users by their stars and gives you the top 2 for each year. (for 10 just <= 10)
SELECT * FROM (
select ROW_NUMBER() OVER(PARTITION BY e.emp_namelast order by year(c.execoffice_date) desc ) as RowNum,
year(c.execoffice_date) as year, e.emp_nameFirst + ' ' + e.emp_namelast as lastName, sum(c.execoffice_status) as stars
from employee e
join CSEReduxResponses c on c.employeee = e.emp_id
where c.execoffice_status <> 0
group by emp_namelast, emp_namefirst, year(c.execoffice_date)
) a WHERE RowNum<=10 order by year
Here is how I understood your requirements.
Get count of records for each employee per year where execoffice_status is 1
execoffice_status can be one or zero
in this case, you can use sum and group by, if execoffice_status can be another number other than one or zero, then we would need to use rownum and count, instead of sum and group by
let me know if this does what you want.
select * from(
select a.employeEe,a.execoffice_date, SUM(a.execoffice_status) execoffice_status_count
from CSEReduxResponses a
group by a.employeEe,execoffice_date
) a
left outer join employee b
on b.emp_id = a.employeee
where EXECOFFICE_STATUS_COUNT > 0
order by execoffice_date desc;
also if you want to get the top 10 rows, I think with sql server you do Select TOP 10 field1, field2, field3 from table