SSRS and ignored "having" clause - sql-server

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

Related

UNNEST array and assign to new columns with CASE WHEN

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

Sql Server - Invalid query because of no aggregate function or group by clause for comparing difference between 2 dates

Given a table:
-------------------------------------
| Id | DateField_A | DateField_B |
-------------------------------------
| 1 | 2017-01-01 | 2018-06-01 |
-------------------------------------
| 2 | 2018-02-01 | 2018-06-01 |
-------------------------------------
| 3 | 2018-04-01 | 2018-04-03 |
-------------------------------------
I am trying to write a query that takes the sum of rows between a date range where two date fields are less than 5 days apart.
SELECT Count(*) FROM TABLE
WHERE
DateField_A >= '2018-01-01'
AND DateField_A < '2019-01-01'
HAVING (DateField_B - DateField_A) <= 5
This would return count 1 given the table above.
However I'm getting the following error:
How can I fix the query?
You can only use having and select on fields that are included in a group by clause or included in an aggregate function such as count. In your case, you just want to move that to your where criteria:
SELECT Count(*)
FROM TABLE
WHERE DateField_A >= '2018-01-01'
AND DateField_A < '2019-01-01'
AND (DateField_B - DateField_A) <= 5
As commented below, please be careful when using subtraction or addition for comparing dates. While it might work for this instance, you would be safer using date comparison functions such as dateadd, or in this case, datediff:
...
AND datediff(day, datefield_a, datefield_b) <= 5

SQL Server - calculating continuous membership

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

SQL - carry previous Application's value onto next Application

I have a table in SQL server, returning the results below, I am having trouble carrying over my SQNCarriedOver Value into the ThisAppOFFICIAL column on the next application.
I cannot do it based on the row number because the Project Names do not list in that order:
I was wondering if there was a way to carry the QSNCarried over value to the ThisAppOFFICIAL column in the next application with that Project Name,
So for Example:
The thisAppOfficial value on "12/06/2016" would be "10" (from in the QSCarriedOver on "12/05/2016")
I may have overlooked something, I have searched the web but I feel my question is quite specific.
Any help or advice is appreciated, Thank you in advance.
ps:
the next application is the next Application Date with the Same Project Name
Query:
SQLFIDDLEExample
SELECT t.Project,
t.AppDate,
t.thisAppOfficial,
COALESCE((SELECT TOP 1 t2.QSCarriedOver
FROM X t2
WHERE t2.Project = t.Project
AND t2.AppDate < t.AppDate
ORDER BY t2.AppDate desc), 0) as NewColumn,
t.QSCarriedOver
FROM X t
Result:
| Project | AppDate | thisAppOfficial | NewColumn | QSCarriedOver |
|---------|------------|-----------------|-----------|---------------|
| A | 2016-04-13 | 30 | 0 | 0 |
| A | 2016-05-12 | 30 | 0 | 10 |
| A | 2016-06-12 | 30 | 10 | 0 |
| A | 2016-07-12 | 30 | 0 | 0 |
I think I've got what you want and I'm sure that there is a better way of doing it. I've created a simpler version of your table for my needs. I then use ROW_NUMBER to put the rows into a sequence so I can do a sort of self-join to the previous row to get the carry forward figure
CREATE TABLE X (Project varchar(50), AppDate date, thisAppOfficial int, QSCarriedOver int)
inserT INTO X VALUES('A', '13 Apr 2016', 30,0)
inserT INTO X VALUES('A', '12 May 2016', 30,10)
inserT INTO X VALUES('A', '12 Jun 2016', 30,0)
inserT INTO X VALUES('A', '12 Jul 2016', 30,0)
SELECT X0.Project, X0.AppDate, X0.thisAppOfficial, X0.QSCarriedOver, ISNULL(X2.QSCarriedOver,0) as 'Brought forward from previous row' FROM X X0
JOIN (select ROW_NUMBER () OVER (ORDER BY Project, AppDate) as MainRow, * from X) X1 ON X1.Project = X0.Project AND X1.AppDate = X0.AppDate
LEFT OUTER JOIN (select ROW_NUMBER () OVER (ORDER BY Project, AppDate) as PrevRow, * FROM X) X2 ON X2.Project = X1.Project and X2.PrevRow = MainRow -1
order by Project, AppDate
Have a try with this and see if it is doing what you need, I'm not 100% sure I've understood your requirements so no problem if it isn't what you want.

SQL SERVER - CHANGE COLUMN NAME TO VALUE

I have a table like this:
ID | Date 1 | Date 2 | Date 3
1 | 2014-08-01 | 2014-08-02 | 2014-08-03
And I need to output it like this:
ID | Date Field Name | Date Value
1 | Date 1 | 2014-08-01
1 | Date 2 | 2014-08-02
1 | Date 3 | 2014-08-03
Have tried dynamic unpivoting with unions but seems messy. Is there a best practice way of doing this?
I think UNPIVOT is the best practice here. I don't find it messy so much as confusing, maybe because I don't reach for it that often. This will give the results you're looking for:
SELECT ID, [Date Field Name], [Date Value]
FROM myTable
UNPIVOT ([Date Value] FOR [Date Field Name] IN ([date 1], [date 2], [date 3])) AS x

Resources