Remove duplicates records from sum statement using SQL server - sql

Hi i have a table in which it has some duplicate records i want to remove all duplicate records and get the total count for that condition . I have tried following query here in first query it will include duplicate records also .
1> select count(fd.FarmerRegNo) as TotalRecord,
sum(case when fd.TSStatus='Approved' and Status!=0 then 1 else 0 end) Approved,
sum(case when fd.TSStatus='Pending' and fd.Status=0 then 1 else 0 end) Pending,
from FarmerDetail as fd
2> select count(distinct FarmerRegNo) as [Approved] from FarmerDetail where TSStatus='Approved'
see the image i want to get the 2nd table value in first table approved column how to remove duplicates for this condition

Is this what you want?
select
count(distinct fd.FarmerRegNo) as TotalRecord,
count(distinct case when fd.TSStatus = 'Approved' and Status != 0 then fd.FarmerRegNo end) Approved,
count(distinct case when fd.TSStatus = 'Pending' and Status = 0 then fd.FarmerRegNoend) Pending,
from FarmerDetail as fd

Use a conditional count(distinct):
select count(fd.FarmerRegNo) as TotalRecord,
count(distinct case when fd.TSStatus = 'Approved' and fd.Status <> 0 then fd.FarmerRegNo end) as Approved,
count(distinct case when fd.TSStatus = 'Pending' and fd.Status = 0 then fd.FarmerRegNo end) as Pending,
from FarmerDetail fd ;

Use the below query with sub query
select count(fd.FarmerRegNo) as TotalRecord,
(select count(distinct FarmerRegNo) from FarmerDetail where TSStatus='Approved') as Approved,
sum(case when fd.TSStatus='Pending' and fd.Status=0 then 1 else 0 end) Pending,
from FarmerDetail as fd

Related

How to count multiple columns in SQL (Oracle) with criteria?

I'm working on SMS-Gateway that holds multiple charged SMS-services with different numbers,
each SMS sent to the customer has 4 status as below (forwarded, delivered, expired,delivery failed)
Now I have the below first_table for the charging-system with the below details (TABLE-A)
and below (TABLE-B) which contain the status of each sent SMS with its ID
Below is my expected final result to forecast the details for each sms-service :
At first I thought it was easy all I need is just to use COUNT(Case when ...)
but in my case I have thousands of SMS-numbers(services) so if I use this approach it will be like that:-
COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='forwarded' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='delivered' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='expired' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='1111' AND B.STATUS='delivery failed' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='forwarded' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='delivered' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='expired' )
COUNT(CASE WHEN a.SMS_SHORT_CODE='5000' AND B.STATUS='delivery failed' )
...
...
...
...
...
...
...
The above approach not practical when you have many services also noting that CASE can handle only 250 conditions?
So what is the best approach to do left outer join for (Table A) on (Table B) using the SMS-ID and count each SMS-status and forecast it as below?
I would suggest conditional aggregation:
select b.SMS_SHORT_CODE,
sum(case when status = 'forwaded' then 1 else 0 end) as count_of_forwaded,
sum(case when status = 'delivered' then 1 else 0 end) as count_of_status,
sum(case when status = 'expired' then 1 else 0 end) as count_of_expired,
sum(case when status = 'delivery failed' then 1 else 0 end) as count_of_delivery_failed
from TABLEB b
group by b.SMS_SHORT_CODE ;
Note that no JOIN is necessary. All the data you want to aggregate is in TABLEB.
Please use below query,
select
A.SMS_SHORT_CODE,
case when status = 'forwaded' then count(status ) end as count_of_forwaded,
case when status = 'delivered' then count(status ) end as count_of_status,
case when status = 'expired' then count(status ) end as count_of_expired,
case when status = 'delivery failed' then count(status ) end as count_of_delivery_failed
from TABLEA A
inner join TABLEB B
on (A.SMS_ID = B.SMS_ID)
group by A.SMS_SHORT_CODE, status ;
You can use PIVOT clause (introduced in Oracle 11g version) for those status columns :
SELECT sms_short_code,
COUNT_OF_forwarded,
COUNT_OF_delivered,
COUNT_OF_expired,
COUNT_OF_delivery_failed
FROM tableB
PIVOT
(
COUNT(*) FOR status IN ( 'forwarded' AS COUNT_OF_forwarded,
'delivered' AS COUNT_OF_delivered,
'expired' AS COUNT_OF_expired,
'delivery failed' AS COUNT_OF_delivery_failed )
)
e.g. only using TableB is enough.
Demo

Use EXISTS in SQL for multiple select

I have a table STATUSES which contain columns NAME and ACTIVE_FLAG.The column value of NAME may have new, pending, cancel. I want to generate a new output for the count of each NAME with ACTIVE_FLAG=Y
By thinking to use EXISTS to select records for single NAME,
SELECT COUNT(*) AS PENDING
FROM STATUSES
WHERE EXISTS (select NAME from STATUSES where NAME='Pending' and ACTIVE_FLAG = 'Y')
Anyway if I can join other statuses count in a single SQL?
Seems like count and group by
SELECT
name
, count(*)
FROM statuses
WHERE active_flag = 'Y'
GROUP BY name
You can use something like this as i don't see any need to use EXISTS :
SELECT sum(case when name='Pending' then 1 else 0 end) AS PENDING,
sum(case when name='new' then 1 else 0 end) AS NEW,
sum(case when name='cancel' then 1 else 0 end) AS CANCEL
FROM STATUSES
WHERE ACTIVE_FLAG = 'Y'
SQL HERE

SQL Multiple Rows to Single Row Multiple Columns

I am including a SQLFiddle to show as an example of where I am currently at. In the example image you can see that simply grouping you get up to two lines per user depending on their status and how many of those statuses they have.
http://sqlfiddle.com/#!3/9aa649/2
The way I want it to come out is to look like the image below. Having a single line per user with two totaling columns one for Fail Total and one for Pass Total. I have been able to come close but since BOB only has Fails and not Passes this query leaves BOB out of the results. which I want to show BOB as well with his 6 Fail and 0 Pass
select a.PersonID,a.Name,a.Totals as FailTotal,b.Totals as PassTotals from (
select PersonID,Name,Status, COUNT(*) as Totals from UserReport
where Status = 'Fail'
group by PersonID,Name,Status) a
join
(
select PersonID,Name,Status, COUNT(*) as Totals from UserReport
where Status = 'Pass'
group by PersonID,Name,Status) b
on a.PersonID=b.PersonID
The below picture is what I want it to look like. Here is another SQL Fiddle that shows the above query in action
http://sqlfiddle.com/#!3/9aa649/13
Use conditional aggregation if the number of values for status column is fixed.
Fiddle
select PersonID,Name,
sum(case when "status" = 'Fail' then 1 else 0 end) as failedtotal,
sum(case when "status" = 'Pass' then 1 else 0 end) as passedtotals
from UserReport
group by PersonID,Name
Use conditional aggregation:
select PersonID, Name,
sum(case when Status = 'Fail' then 1 else 0 end) as FailedTotal,
sum(case when Status = 'Pass' then 1 else 0 end) as PassedTotal
from UserReport
group by PersonID, Name;
With conditional aggregation:
select PersonID,
Name,
sum(case when Status = 'Fail' then 1 end) as Failed,
sum(case when Status = 'Passed' then 1 end) as Passed
from UserReport
group by PersonID, Name

case statement doesn't go to else

I am wondering why the following query doesn't give 'N/A' when there are no rows for ENVIRON='Dev/Int'. It is returning null in the result of the query. I tried doing NVL(COUNT(*)) but that does't work either.
Any thoughts?
Thanks in advance.
SELECT G1.NAME,
(SELECT CASE
WHEN COUNT(*) > 0 AND ticket IS NOT NULL THEN 'Solved'
WHEN COUNT(*) > 0 AND ticket IS NULL THEN 'Done'
ELSE 'N/A'
END
FROM TABLE1
WHERE ENVIRON='Dev/Int' AND G1.NAME=NAME GROUP BY ENVIRON, ticket ) "Dev/Int"
FROM TABLE1 G1 group by G1.NAME
It doesn't give any rows because you are filtering them all out. The case is inside the query. When there are no rows to process, it returns NULL.
I think you just want conditional aggregation. The subqueries don't seem necessary:
SELECT G1.NAME,
(CASE WHEN SUM(CASE WHEN ENVIRON = 'Dev/Int' then 1 else 0 END) > 0 AND ticket IS NOT NULL
THEN 'Solved'
WHEN SUM(CASE WHEN ENVIRON = 'Dev/Int' then 1 else 0 END) > 0 AND ticket IS NULL
THEN 'Done'
ELSE 'N/A'
END) as "Dev/Int"
FROM TABLE1
group by G1.NAME;
EDIT:
Oops, the above left ticket out of the sum(). I think the logic you want has ticket in the sum() condition:
SELECT G1.NAME,
(CASE WHEN SUM(CASE WHEN ENVIRON = 'Dev/Int' AND ticket IS NOT NULL then 1 else 0 END) > 0
THEN 'Solved'
WHEN SUM(CASE WHEN ENVIRON = 'Dev/Int' AND ticket IS NULL then 1 else 0 END) > 0
THEN 'Done'
ELSE 'N/A'
END) as "Dev/Int"
FROM TABLE1
group by G1.NAME;
I'm surprised your original query worked at all and didn't get an error of the sort that subquery returned more than one row.

efficiently compute percentages in hive or sql

SELECT
(CASE WHEN tag=FRAUD THEN 0
ELSE 1 END) fraud_tag,
COUNT(DISTINCT account_id) AS distinct_account_count
FROM fraud_tags a
GROUP BY
(CASE WHEN c.name='riskclass_NotFraud' THEN 0
ELSE 1 END)
RESULT
fraud_tag distinct_account_count
0 100
1 500
Now I want to compute fraud_percentages, number of distinct accounts with fraud_tag=0 over total number of accounts. I have to do it two steps. Any suggestions to make it more efficient?
The easiest way is to do this with the values in one row:
SELECT COUNT(DISTINCT case when tag = FRAUD then account_id end) as distinct_fraud,
COUNT(DISTINCT case when tag = FRAUD then NULL else account_id end) as distinct_notfraud,
(COUNT(DISTINCT case when tag = FRAUD then account_id end)*1.0/count(distinct account_id)
) as fraud_rate
FROM fraud_tags ft;