Number of Sundays in a list of dates - sql

I have a list of members of a club together with dates that they attended the club. I need to know how many Sundays did each member attend over a given period. I have a table that lists each attendance, made up of member number and the attendance date.
Eg In this example 13/1 and 20/1 are Sundays
MEMBER ATTENDANCE
12345 13/1/13
12345 14/1/13
56789 13/1/13
56789 14/1/13
56789 20/1/13
24680 14/1/13
24680 15/1/13
Ideally I would like to see this returned:
MEMBER # OF SUNDAYS
12345 1
56789 2
24680 0

select MEMBER,
sum(case when datename(weekday,ATTENDANCE)='Sunday' then 1 else 0 end) as no_of_sundays
from table
group by MEMBER
EDIT : To handle duplicate dates, use
select MEMBER,
sum(case when datename(weekday,ATTENDANCE)='Sunday' then 1 else 0 end) as no_of_sundays
from (select distinct MEMBER,ATTENDANCE from table ) as t
group by MEMBER

Related

Exclude an item only when there are multiple entries

I have a table of data with policy information:
Row PolicyNumber Member ID PolicyName
1 1234 789 Main
2 1265 789 Travel
3 1523 541 Travel
4 6778 374 Main
5 5821 123 Main
6 8763 123 Travel
I want to count the number of distinct MEMBERID's within each policynumber. However, some members have more than one policynumber because some members have a travel policy and a main policy.
So I want SQL to check for a count of POLICYNUMBER by MEMBERID first, and where the POLICYNUMBER count is greater than one, to bring only the policy numbers where the POLICYNAME is not like '%travel%'
But, if the member ONLY has one policy, I want SQL to include that policy even if it's travel.
So in my sample data:
Member 789 would be counted against policy 1234 but not 1265
Member 541 would be counted against policy 541
Member 374 would be counted against policy 6778
Member 123 would be counted against policy 5821 but not 8763
Desired result would be a table of two columns, PolicyNumber and the distinct count of MemberId associated to that policy.
How do I write the syntax?
You can achieve this using multiple having conditions -
SELECT Member_ID, COUNT(*)
FROM YOUR_TABLE
GROUP BY Member_ID
HAVING COUNT(PolicyName) = 1
OR COUNT(CASE WHEN PolicyName NOT LIKE '%travel%' THEN 1 ELSE 0 END) >= 1;

sum positive and negative values separately

I have a table:
NAME MONEY
Jane 100
Chris -100
Jane 50
Ann -10
Jane -25
Ann 17
And i want to write a query to sum data, in one column should be only positive amount od money in another column only negative. Output should look like this:
NAME SUM_POSITIVE SUM_NEGATIVE
Jane 150 -25
Chris 0 -100
Ann 17 -10
query:
select name, sum(money) from TABLE where money>0 group by name
union
select name, sum(money) from TABLE where money<0 group by name;
shows nearly what i want, but result has duplicate names and two columns instead of three:
NAME SUM
Ann -10
Ann 17
Jane -25
Jane 150
Chris -100
Please help me rewrite my query to correct output.
use case when
select name, sum(case when money>0 then money end) SUM_POSITIVE
,sum(case when money<0 then money end) SUM_NEGATIVE
from TABLE group by name
You are getting duplicate name becase union operator merge only those rows where all column values are same, as Ann contain -10 and 17 which is distinct so its make duplicate
You can do conditional aggregation instead :
select name,
sum(case when money > 0 then money end) as SUM_POSITIVE,
sum(case when money < 0 then money end) as SUM_NEGATIVE
from TABLE
group by name;

Find the monthly count, for every month from the start date till member is cancelled

Problem: Monthly distinct count of members from the first date of the gene reading, till the member is cancelled.
Members can have more than one reading per month. They can continue to have as many readings as they want.
Example:
member_id date gene_a_measurement_done gene_b_measurement_done
5557153 1/1/2010 y
5557153 2/1/2010 y
222458 2/1/2010 y y
222458 1/1/2011 y
707222 1/1/2011 y
Another table has members cancellation date:
member_id status date
5557153 Cancelled 5/1/2011
222458 Cancelled 12/1/9999
707222 Cancelled 12/1/9999
Expected result :
month distinct_count_of_member_with_gene_a_measurement distinct_count_of_member_with_gene_b_measurement
1/1/10 1 0
2/1/10 2 2
3/1/10 2 2
4/1/10 2 2
5/1/10 1 1
6/1/10 1 1
7/1/10 1 1
8/1/10 1 1
9/1/10 1 1
10/1/10 1 1
11/1/10 1 1
12/1/10 1 1
1/1/11 2 1
Query tried:
SELECT
sub.last_day,
sum(sub.distinct_count_of_member_with_gene_a_measurement) as distinct_count_of_member_with_gene_a_measurement,
sum(sub.distinct_count_of_member_with_gene_b_measurement) as distinct_count_of_member_with_gene_b_measurement,
FROM
(SELECT last_day(date),
COUNT(DISTINCT member_id) as distinct_count_of_member_with_gene_a_measurement,
null as distinct_count_of_member_with_gene_b_measurement,
FROM measurement
WHERE gene_a_measurement_done is not null
GROUP BY last_day(date)
UNION ALL
SELECT last_day(date),
null as distinct_count_of_member_with_gene_a_measurement,
COUNT(DISTINCT member_id) as distinct_count_of_member_with_gene_b_measurement,
FROM measurement
WHERE gene_b_measurement_done is not null
GROUP BY last_day(date)) as sub
GROUP BY sub.last_day(date)
Above query only gives distinct count of member for the month for which measurement was done and I am not sure how to best consider cancellation date? (inner join with member_status table on member_id and have condition to filter out cancelled member?)

Isolating the date a value turns 0 and aggregating another value from that date back

I'm looking to see two things:
When a customer closed all of their accounts with us (date when
accounts goes to 0)
The total interactions a customer had with us up
until that point (sum of interactions from when accounts was a
number greater than one).
The total interactions a customer had with us up
until that point (sum of interactions from when accounts was a
number greater than one).
Basically I'm trying to get from the top table to the bottom table in the attached image.
Customer month Accounts Interactions
12345 Jan-15 3 5
12345 Feb-15 3 1
12345 Mar-15 2 7
12345 Apr-15 1 3
12345 May-15 1 9
12345 Jun-15 1 2
12345 Jul-15 0 3
67890 Feb-15 1 4
67890 Mar-15 1 4
67890 Apr-15 1 9
67890 May-15 0 5
Customer Month close date Interactions
12345 Jul-15 30
67890 May-15 23
When I first read the question it sounded like there would be a neat solution with window functions, but after re-reading it, I don't think that's necessary. Assuming that closing his last account would be the last interaction a customer would have with you, you just need the last interaction date per customer, which means this problem can be solved with simple aggregate functions:
SELECT customer, MAX(month), SUM(interactions)
FROM mytable
GROUP BY customer
To get the last three months you need an OLAP-function:
SELECT Customer, MAX(months), SUM(Interactions)
FROM
(
SELECT Customer, month, Interactions
FROM mytable
QUALIFY
-- only closed accounts
MIN(Accounts) OVER (PARTITION BY Customer) = 0
-- last three months
AND month >= oADD_MONTHS(MAX(month) OVER (PARTITION BY Customer), -3)
) AS dt
GROUP BY customer

Count day of week occurances

I have a list of members of a club together with datetime that they attended the club. They can attend the club several times in a single day. I need to know how many Sundays did each member attend over a given period (regardless how many times within a single Sunday). I have a table that lists each attendance, made up of member number and the attendance datetime.
Eg In this example 13/1 and 20/1 are Sundays
MEMBER ATTENDANCE
12345 13/1/13 09:00
12345 13/1/13 15:00
12345 14/1/13 08:00
56789 13/1/13 10:00
56789 13/1/13 15:00
56789 13/1/13 21:00
56789 14/1/13 10:00
56789 20/1/13 09:00
24680 14/1/13 08:00
24680 15/1/13 07:00
Ideally I would like to see this returned:
MEMBER # OF SUNDAYS
12345 1
56789 2
24680 0
I think you need this:
select Member,
count(distinct dateadd(day, datediff(day, 0, Attendance), 0)) as NumberOfSundays
from t
where datepart(dw, Attendance) = 6
group by Member ;
The complicated count is really doing:
count(distinct cast(Attendance as date))
but the date data type is not supported in SQL Server 2005.
EDIT:
Instead of datepart(dw, Attendance) = 6, you can use datename(dw, Attendance) = 'Sunday'.
Try this
SELECT MEMBER,
SUM(CASE DATENAME(dw,ATTENDANCE) WHEN 'Sunday' THEN 1 ELSE 0 END) As [# OF SUNDAYS]
FROM MemberTable
WHERE ATTENDANCE between [YourStartDateAndTime] AND [YourEndDateAndTime] -- replace [YourStartDateAndTime] AND [YourEndDateAndTime] with your value or variable
GROUP BY MEMBER
Take a look into this example, it may work also:
select Member
, count( case when datepart( dw, Attendance ) = 6 then 1 else 0 end ) NumberOfSundays
from YourTable
where Attendance between '2013-01-13' and '2013-01-20'
group by Member
Avoid use functions on your where clause that'll modify the original value of the field. By doing this, SQL Server will create an execution plan using a Table Scan, ignoring any index that would speed up your query!