Here's the logic for calculation I am trying to do: I have to calculate members who are continuously been enrolled in membership. For example John membership ended on 1-1-2017 but he joined again before 2-15-2017 then he is counted as a eligible member, but if he joins later than 45 days he is not eligible for membership count. I tried using ranking function as well as tried using DATEDIFF function, seems like doesn't works.
Can anyone help with this? Thanks in advance.
| ID | NAME | TERMINATIONDATE | STARTDATE |
|------------------------------------------|
| 2 | John | 1-1-2017 | 2-16-2017 |
| 3 | Harry | 12-1-2016 | 1-1-2016 |
| 4 | Rob | active | 1-1-2015 |
So I need the count of ID's which are not terminated, and if they are terminated and started with 45 days of termination , count it too as eligible members.
You can just use the dateadd function to compare the start date to the termination date:
select
count(*)
from members
where isnull(termination_date,'') = ''
or dateadd(d,45,termination_date) > start_date
One thing I noticed in your example data is that the value of 'active' is in the termination date column. If that is how your data is, I would recommend against doing that and instead using a value NULL for all members that do not have a termination date.
Edited:
If your termination date is actually "stringly-typed", you can use the following query to scrub out the "active" value:
select
count(*)
from members
where termination_date = 'active'
or dateadd(d,45, replace(termination_date,'active','')) > start_date
Related
I ran into this problem because I'm using grouping sets in a subquery that gives me this results
name | objective | vehicle | count_of_installed
------------------------------------------------------
Antonio | | | 1
Antonio | 40 | 2nd vehicle | 19
Antonio | NULL | NULL | 20
George | | | 10
George | 50 | 2nd vehicle | 20
George | NULL | NULL | 30
And I'm then only searching only for rows where there are nulls, as they are the correct count_of_installed, now I want to have the correct objective and vehicle replacing the NULL values with the correct values, so I thought of something like coalesce(objective, objective), but I'm not sure this works.
For reference, my grouping sets are:
grouping sets (name, (name, objective, vehicle))
Edit 1
In my example above is the result of a query with joining my seller and sales tables, it shouldn't show neither blank nor null values, so when I say coalesce(objective, objective), I mean replace the null results from the result table with the correct values from my seller table.
I have following BigQuery table, which has nested structure, i.e. example below is one record in my table.
Id | Date | Time | Code
AQ5ME | 120520 | 0950 | 123
---------- | 150520 | 1530 | 456
My goal is to unnest the array to achieve the following structure (given that 123 is the Start Date code and 456 is End Date code):
Id | Start Date | Start Time | End Date | End Time
AQ5ME | 120520 | 0950 | 150520 | 1530
I tried basic UNNEST in BigQuery and my results are as follows:
Id | Start Date | Start Time | End Date | End Time
AQ5ME | 120520 | 0950 | NULL | NULL
AQ5ME | NULL | NULL | 150520 | 1530
Could you please support me how to unnest it in a correct way as described above?
You can calculate mins and max within the row, and extract them as a new column.
Since you didn't show the full schema, I assume Date and Time are separate arrays.
For that case, you can use that query:
SELECT Id,
(SELECT MIN(D) from UNNEST(Date) as d) as StartDate,
(SELECT MIN(t) from UNNEST(Time) as t) as StartTime,
(SELECT MAX(D) from UNNEST(Date) as d) as EndDate,
(SELECT MAX(t) from UNNEST(Time) as t) as EndTime
FROM table
As in Sabri's response - using aggregation functions while unnesting works perfectly. To use this fields later on for sorting purposes (in ORDER BY statement) SAFE_OFFSET[0] can be used, like for example below:
...
ORDER BY StartDate[SAFE_OFFSET(0)] ASC
I have two tables one is the customer_service table with dates of service and the other is the membership table where the member can exist multiple times if they have had lapses in their membership effective and expiration dates. Below is a basic example of how these table might layout.
How might I find dates of service that fall outside or in between membership date ranges. A simple join will not work with this due to the member possibly having multiple date ranges for their membership under the same ID. Would this require some form of iteration here? I am unsure as to the best way to approach this kind of issue.
Customer_Service Table
id | customers | Dos
-------------------------
1 | Rodney | 01/18/2018
2 | Jim | 02/15/2018
3 | Tom | 01/01/2018
1 | Rodney | 02/15/2018
3 | Tom | 03/01/2018
Membership Table
id | Effective_date | End_date
-------------------------
1 | 01/01/2017 | 12/31/2017
1 | 02/15/2018 | 05/20/2018
2 | 06/20/2016 | 01/25/2018
2 | 02/25/2018 | 12/31/2099
3 | 01/01/2018 | 06/01/2018
A simple approach is below. The query will identify rows in CUSTOMER_SERVICE where DOS does not fall between any periods in the membership table for that customer.
SELECT * FROM CUSTOMER_SERVICE CS
WHERE NOT EXISTS (
SELECT * FROM MEMBERSHIP M
WHERE CS.ID = M.ID
AND DOS BETWEEN EFFECTIVE_DATE AND END_DATE
)
Or alternatively:
SELECT CS.* FROM CUSTOMER_SERVICE CS
LEFT JOIN MEMBERSHIP M ON M.ID = CS.ID
AND DOS BETWEEN EFFECTIVE_DATE AND END_DATE
WHERE M.ID IS NULL
I'm trying to get a list of data whose last update date is older than the current date minus x month.
As an example, here is a sample table :
| DataGUID | UpdateDate |
|------------|---------------|
| AAA | 12-05-2017 |
| BBB | 22-06-2017 |
| AAA | 14-02-2017 |
| BBB | 16-05-2017 |
Currently, I have a SQL request looking somewhat like the following :
SELECT
DataGUID,
MAX(UpdateDate)
FROM
Table
GROUP BY
DataGUID
HAVING
MAX(UpdateDate) <= DATEADD(mm, CAST('-'+#LastUpdatedXMonthAgo AS INT), GETDATE())
ORDER BY
MAX(UpdateDate) DESC;
Expected result is the following (with #LastUpdatedXMonthAgo = 1, and current date 13-07-2017) :
| DataGUID | UpdateDate |
|------------|---------------|
| AAA | 12-05-2017 |
It works on SSMS, but SSRS seems to ignore the "having" clause, and gives me this result :
| DataGUID | UpdateDate |
|------------|---------------|
| BBB | 22-06-2017 |
| AAA | 12-05-2017 |
Seem like SSRS just ignore the "having" clause, is there a way to make it work without using SSRS filters?
The problem appears to be that you are trying to prepend concatenate a hyphen to a session variable which is a number. This is resulting in the minus sign being ignored/dropped. Hence, your HAVING clause is working, but it is comparing each max date against one month in the future from now, instead of one month behind.
The following query will show you one way to fix this problem:
DECLARE #LastUpdatedXMonthAgo INT;
SET #LastUpdatedXMonthAgo = 1;
SELECT
DATEADD(mm, CAST('-'+CAST(#LastUpdatedXMonthAgo AS VARCHAR(55)) AS INT), GETDATE());
This approach is to cast #LastUpdatedXMonthAgo to text before trying to "negate" the string. Another approach would be to just make #LastUpdatedXMonthAgo text, but maybe this would be inconvenient for the rest of your script.
Update:
In SSMS, we could simplify this even further to:
DATEADD(mm, -#LastUpdatedXMonthAgo, GETDATE());
Demo here:
Rextester
I feel like this isn't too bad of a problem but I've been looking for a solution for the greater part of the day to no avail. Other solutions I've seen plenty of that don't seem to help me have been for getting columns that aren't unique values along with a group by and aggregate function.
The problem
I have a table of historical data as follows:
ID | source | value | date
---+--------+-------+-----------
1 | 12 | 10 | 2016-11-16
2 | 12 | 20 | 2015-11-16
3 | 12 | 30 | 2014-11-16
4 | 13 | 40 | 2016-11-16
5 | 13 | 50 | 2015-11-16
6 | 13 | 60 | 2014-11-16
I'm trying to get data before a certain date(within a loop to go different ranges), then getting the sum of the values grouped by source. So as an example "get all records before 30 days ago, and get the sum of the values of the unique sources, using the most recent dated entry for each".
So the first step was to remove entries with dates not in the range, an easy where date < getdate()-30 for example to get:
ID | source | value | date
---+--------+-------+-----------
2 | 12 | 20 | 2015-11-16
3 | 12 | 30 | 2014-11-16
5 | 13 | 50 | 2015-11-16
6 | 13 | 60 | 2014-11-16
Now my issue is finding a way to group by source and take the max date, and then sum up the result across all sources. The idea hear is that we don't know when the last entry is, so before the specified date we get all records, then take the newest entry for each unique source, and sum those up to get the total value at that time.
So the next step would be to group by source using the max of date, resulting in :
ID | source | value | date
---+--------+-------+-----------
2 | 12 | 20 | 2015-11-16
5 | 13 | 50 | 2015-11-16
And then the final step would be to sum the values, and then this process is repeated to get the sum value for multiple dates, so this would result in the row
value | date
-------+-----------
70 | getdate() - 30
to use for the rest.
Where I'm stuck
I'm trying to group by source and use the max of date to get the most recent entry for each unique source, but if I use the aggregate function or group by, then I can't preserve the ID or value columns to stick with the chosen max row. It's totally possible I'm just misunderstanding how aggregate functions work.
Progress so far
The best place I've gotten to yet is something like
with dataInDateRange as (
select *
from #historicalData hd
where hd.date < getdate() - 30
)
select ???, max(date)
from dataInDateRange
group by source
But I'm not seeing how I can do this without somehow preserving a unique ID for the row that has the max date for each source so then I can go back and sum up the numbers.
Thank you great people for any help/guidance/lessons
USE row_number()
with dataInDateRange as (
select *
from #historicalData hd
where hd.date < getdate() - 30
), rows as (
select *,
row_number() over (partition by source
order by date desc) as rn
from dataInDateRange
)
SELECT *
FROM rows
WHERE rn = 1