Get Next Value within Row Groups in SSRS - sql

I have a problem I'm trying to solve with getting the NextRow value but only within the specific RowGroup.
Here's what I'm trying to do:
if Fields!Interventions.Value is not blank and nextrow(Fields!DateOccurred.Value) within the group is within 4 hours then Y else N
and another column:
if Fields!Interventions.Value is not blank compare currentrow(Fields!DateOccurred.Value) to nextrow(Fields!DateOccurred.Value) and display the differences in hours
But I'm stuck as to how i could do this expression from within SSRS.
I saw the following question:
Get previous,current and Next Record in ssrs report in a page
but the issue with this one is that it doesn't work with Row Groups in SSRS.
Upon further advise, it appears as this isn't possible to do in SSRS, but would be possible in the query itself.
This is the query I'm working with:
SELECT
ROW_NUMBER() OVER(PARTITION BY R.PatientID, PL.ChartLocationID ORDER BY P.DateOccurred ASC) As Row#,
R.NameFirst,
R.NameLast,
P.DateOccurred,
CASE P.Interventions
WHEN 1 Then 'Regular Analgesia'
When 2 Then 'Heat Pack'
When 4 Then 'Cold Pack'
When 8 Then 'Massage'
When 16 Then 'Exercise'
When 32 Then 'Other'
END as Interventions
FROM
ChartEntry P
LEFT JOIN ChartLocation PL on
P.ChartLocationId = PL.ChartLocationId
Inner Join Resident R on
PL.ResidentID = R.PatientID
where
P.DateDeleted is null and
P.DateOccurred >= '01 Jul 2017' and
P.DateOccurred < '01 Aug 2017'
Is it possible to achieve?
Here is some sample data showing the results for the extra two columns:

Easiest and better way is to use LAG/LEAD in your SQL to figure this out.

You can do this in SSRS:
Set your detail value to Previous(Fields!DateOccurred.Value) and the detail row visibility to = RowNumber("yourgroup") = 1 which will hide the first row.
Use one row on the group total, in order to display the last value by setting its value to =Last(Fields!DateOccurred.Value)
The date difference expression check for the detail will be
=Iif(
NOT(Fields!Interventions.Value Is Nothing) AND
DateDiff("h", Previous(Fields!DateOccurred.Value),Fields!DateOccurred.Value)>=4,
"Y",
"N"
)
and for the last line
=Iif(
NOT(Fields!Interventions.Value Is Nothing) AND
DateDiff("h", Last(Fields!DateOccurred.Value),Now())>=4,
"Y",
"N"
)
In the images below, the red line will be hidden with the visibility condition.
Your report will contain only the expected date column, I include the current row date for demonstration.

Related

SSRS Report Duplicates Flag

I'm presently making a report on ssrs from a Great Plains Dynamics DB.
It's a pretty simple report with a few columns. Everything works fine but in GP, when creating an Invoice or a Return bill, sometimes GP is gonna give the same Bill ID. It doesn't really shows as a duplicated because for GP, an Invoice and a Return can/could have the same ID because they are not the same type. Don't ask me why..
So for my report, when I start a research from a multiples values parameters with my SopNumber (Bill ID) it gives me the right information. But now I would like to have a flag on those information that equals the bill ID and has Invoice and Return at the same time.
Since it is normal for GP to have 2 different type of document for the same ID, I cannot ask my report to remove the return or the invoice cause in different case, an Invoice could be the important document and in an other case, the return.
In my tablix, I do not show the Bill ID, because I don't need the information except when there is this "duplication".
I would also like after the flag (line highlited), that on the top of my report, a sentence shows something like : "Those documents are in conflict : 000123123". So with this information showing my ID, I can now go in my multiple values parameter and remove this number.
I wanna achieve those 2 flags because I'm making a calcul from my documents amount and if those 2 would be there, it would make my calcul wrong.
I hope you guys can help me. If so, thank you very much in advance!
I worked on a couple of different expressions but never got the result I wanted. Use previous statement and equals but couldn't find how to make it look like is equals to Invoice and Return and SopNumber equals the same.
select CASE SOP10200.SOPTYPE
WHEN 1 THEN 'QUOTE'
WHEN 2 THEN 'ORDER'
WHEN 3 THEN 'INVOICE'
WHEN 4 THEN 'RETURN'
WHEN 5 THEN 'BACK ORDER'
WHEN 6 THEN 'FULLFILLMENT ORDER'
END AS SOPTYPE,
sop10200.SLPRSNID,
sop10200.XTNDPRCE as ExtendedPrice,
sop10200.SOPNUMBE,
iv00101.ITMCLSCD as FAMILYCLASS,
sop10100.DOCDATE
from sop10200
left join iv00101 on sop10200.ITEMNMBR = iv00101.ITEMNMBR
left join sop10100 on sop10200.SOPNUMBE = sop10100.SOPNUMBE
WHERE SOP10100.DOCDATE BETWEEN '2018-01-01 00:00:00.000' AND '2035-01-01 00:00:00.000'
union all
select CASE SOP30300.SOPTYPE
WHEN 1 THEN 'QUOTE'
WHEN 2 THEN 'ORDER'
WHEN 3 THEN 'INVOICE'
WHEN 4 THEN 'RETURN'
WHEN 5 THEN 'BACK ORDER'
WHEN 5 THEN 'FULLFILLMENT ORDER'
END AS SOPTYPE,
sop30300.SLPRSNID,
sop30300.XTNDPRCE as ExtendedPrice,
sop30300.SOPNUMBE,
iv00101.ITMCLSCD as FAMILYCLASS,
sop30200.DOCDATE
from sop30300
left join iv00101 on sop30300.ITEMNMBR = iv00101.ITEMNMBR
left join sop30200 on sop30300.SOPNUMBE = sop30200.SOPNUMBE
WHERE SOP30200.DOCDATE BETWEEN '2018-01-01 00:00:00.000' AND '2035-01-01 00:00:00.000'
ORDER BY SOPNUMBE desc
Correct me if I'm wrong, but it sounds like you want a way to see if there is a duplicate record for the report and use that in a calculation?
You could do a subquery to retrieve a count, and if that is more than 1 than you have a duplicate record
EDIT:
SELECT *, (IF
(SELECT Count(S1.SOPTYPE) FROM sop10200 S1 WHERE T1.BillID = S1.BillID ) > 1 THEN "Duplicate " ELSE "" END) AS DuplicateCheck
FROM sop10200 T1
The above solution will give you a value you can use on each page to report whether or not that it has a duplicate BillID.

GROUP BY is causing blank fields in results

I am working on trying to fix a problem in the below code.
The first 3000 or so records for the ADJ_CARDHOLDER_ID column are coming up blank/empty when running the query.
All other columns seem to be populating correctly.
I believe this is being caused by the group by which is needed for the sum aggregate.
Is there another way I can go about this which prevents the ADJ_CARDHOLDER_ID column from coming up blank?
Select ADJ_CARDHOLDER_ID,
I_SERVICE_DT,
I_PRODUCT_I,
sum(Claim_Count) as 'Total Claim Count'
--into #temp_claims
from reporting.dbo.vcbt
where YEAR (I_SERVICE_DT) = Cast(Datepart(yyyy,GETDATE())as varchar(4))
and O_CLAIM_ITEM_RESP_STATUS_CD <> 'x'
and PLAN_ID not in('PH13-800W', 'PH13-OGBW', 'PH13-800WL', 'PH13-OGBWL', 'PH13-OGBWA', 'PH13-OGBWM', 'PH13-800WM', 'PH13-800WA')
Group by ADJ_CARDHOLDER_ID, I_PRODUCT_I, I_SERVICE_DT
order by ADJ_CARDHOLDER_ID, I_SERVICE_DT, I_PRODUCT_I

Return overlapping date records in SQL

I used the following query to fetch the overlapping records in SQL:
SELECT QUOTE_ID,FUNCTION_ID,FUNCTION_DT,FUNC_SPACE_ID,FN_START_TIME,FN_END_TIME,DATE_AUTH_LEVEL
FROM R_13_ALL_RESERVED A
WHERE
A.FUNC_SPACE_ID = '401-ZFU-52'
AND A.FUNCTION_DT = TO_DATE('09/03/2015','MM/DD/YYYY')
AND EXISTS ( SELECT 'X'
FROM R_13_ALL_RESERVED B
WHERE A.PROPERTY = B.PROPERTY
AND A.FUNCTION_DT = B.FUNCTION_DT
AND A.FUNCTION_ID <> B.FUNCTION_ID
AND ( ( A.FN_START_TIME > B.FN_START_TIME
AND A.FN_START_TIME < B.FN_END_TIME)
OR ( B.FN_START_TIME > A.FN_START_TIME
AND B.FN_START_TIME < A.FN_END_TIME)
OR ( A.FN_START_TIME = B.FN_START_TIME
AND A.FN_END_TIME = B.FN_END_TIME)
)
)
But eventhough the dates are not overlapping it still returns the records as overlapping.
I am missing some thing here?
Also if the date records overlap, I need to compare the count of function_id records with DATE_AUTH_LEVEL, if 2 function_id records overlap and the count of function_id would be 2 and DATE_AUTH_LEVEL is 1, such record should in the result set.
Please find the data set in SQLFiddle
http://sqlfiddle.com/#!9/95874/1
Desired Output : The SQL should return overlapping FN_START_TIME and FN_END_TIME for a function_space_id and it's function_dt
In the provided example, row 5 and 6 overlap for the function space id '401-ZFU-12' and function_dt 'August, 15 2015' and all others are not overlapping
The simplest predicate (where clause condition) for detecting the overlap of two ranges is to compare the start of the first range with the end of the 2nd range, and the start of the 2nd range with the end of the first range:
WHERE R1.Start_Date <= R2.End_Date
AND R2.Start_Date <= R1.End_Date
As you can see each of the two inequalities looks at a start and end value from separate records (R1 and R2 and then R2 and R1 respectively) all that remains is to add the conditions that will correlate the records, and also ensure that you aren't comparing a row to itself So if you want to find all Common_IDs that have Distinct_IDs with over lapping date ranges:
select *
from Your_Table R1
where exists (select 1 from Your_Table R2
where R1.Common_ID = R2.Common_ID
and R1.Distinct_ID <> R2.Distinct_ID
and R1.Start_Date <= R2.End_Date
and R2.Start_Date <= R1.End_Date)
If there is no Distinct_ID to use, you can use R1.rowid <> R2.rowid in place of R1.Distinct_ID <> R2.Distinct_ID
Here is an approach to troubleshooting the issue on your end.
My first suspicion is that the results of your exists clause are too broad and thus returning rows for every record matching in the outer clause unexpectedly. Likely there are rows that do not fall on the desired date or spaceid that share one component of their interval with your inner criteria.
Inspect the results of the inner select statement (the one within the exists clause) for an example row, exchanging all the 'A' aliased values with actual values from one of the rows returned you did not expect to receive.
Additionally, you can inspect what I think would be a semi join in the execution profile to see what the join criteria are. If you expect it to be filtered by a constant for 'FUNC_SPACE_ID' of '401-ZFU-52', you will discover that it is not.

SQL Query - combine 2 rows into 1 row

I have the following query below (view) in SQL Server. The query produces a result set that is needed to populate a grid. However, a new requirement has come up where the users would like to see data on one row in our app. The tblTasks table can produce 1 or 2 rows. The issue becomes when they're is two rows that have the same job_number but different fldProjectContextId (1 or 31). I need to get the MechApprovalOut and ElecApprovalOut columns on one row instead of two.
I've tried restructuring the query using CTE and over partition and haven't been able to get the necessary results I need.
SELECT TOP (100) PERCENT
CAST(dbo.Job_Control.job_number AS int) AS Job_Number,
dbo.tblTasks.fldSalesOrder, dbo.tblTaskCategories.fldTaskCategoryName,
dbo.Job_Control.Dwg_Sent, dbo.Job_Control.Approval_done,
dbo.Job_Control.fldElecDwgSent, dbo.Job_Control.fldElecApprovalDone,
CASE WHEN DATEDIFF(day, dbo.Job_Control.Dwg_Sent, GETDATE()) > 14
AND dbo.Job_Control.Approval_done IS NULL
AND dbo.tblProjectContext.fldProjectContextID = 1
THEN 1 ELSE 0
END AS MechApprovalOut,
CASE WHEN DATEDIFF(day, dbo.Job_Control.fldElecDwgSent, GETDATE()) > 14
AND dbo.Job_Control.fldElecApprovalDone IS NULL
AND dbo.tblProjectContext.fldProjectContextID = 31
THEN 1 ELSE 0
END AS ElecApprovalOut,
dbo.tblProjectContext.fldProjectContextName,
dbo.tblProjectContext.fldProjectContextId, dbo.Job_Control.Drawing_Info,
dbo.Job_Control.fldElectricalAppDwg
FROM dbo.tblTaskCategories
INNER JOIN dbo.tblTasks
ON dbo.tblTaskCategories.fldTaskCategoryId = dbo.tblTasks.fldTaskCategoryId
INNER JOIN dbo.Job_Control
ON dbo.tblTasks.fldSalesOrder = dbo.Job_Control.job_number
INNER JOIN dbo.tblProjectContext
ON dbo.tblTaskCategories.fldProjectContextId = dbo.tblProjectContext.fldProjectContextId
WHERE (dbo.tblTaskCategories.fldTaskCategoryName = N'Approval'
OR dbo.tblTaskCategories.fldTaskCategoryName = N'Re-Approval')
AND (CASE WHEN DATEDIFF(day, dbo.Job_Control.Dwg_Sent, GETDATE()) > 14
AND dbo.Job_Control.Approval_done IS NULL
AND dbo.tblProjectContext.fldProjectContextID = 1
THEN 1 ELSE 0
END = 1)
OR (dbo.tblTaskCategories.fldTaskCategoryName = N'Approval'
OR dbo.tblTaskCategories.fldTaskCategoryName = N'Re-Approval')
AND (CASE WHEN DATEDIFF(day, dbo.Job_Control.fldElecDwgSent, GETDATE()) > 14
AND dbo.Job_Control.fldElecApprovalDone IS NULL
AND dbo.tblProjectContext.fldProjectContextID = 31
THEN 1 ELSE 0
END = 1)
ORDER BY dbo.Job_Control.job_number, dbo.tblTaskCategories.fldProjectContextId
The above query gives me the following result set:
I've created a work around via code (which I don't like but it works for now) where i've used code to populate a "temp" table the way i need it to display the data, that is, one record if duplicate job numbers to get the MechApprovalOut and ElecApprovalOut columns on one row (see first record in following screen shot).
Example:
With the desired result set and one row per job_number, this is how the form looks with the data and how I am using the result set.
Any help restructuring my query to combine duplicate rows with the same job number where MechApprovalOut and ElecApproval out columns are on one row is greatly appreciated! I'd much prefer to use a view on SQL then code in the app to populate a temp table.
Thanks,
Jimmy
What I would do is LEFT JOIN the main table to itself at the beginning of the query, matching on Job Number and Sales Order, such that the left side of the join is only looking at Approval task categories and the right side of the join is only looking at Re-Approval task categories. Then I would make extensive use of the COALESCE() function to select data from the correct side of the join for use later on and in the select clause. This may also be the piece you were missing to make a CTE work.
There is probably also a solution that uses a ranking/windowing function (maybe not RANK itself, but something that category) along with the PARTITION BY clause. However, as those are fairly new to Sql Server I haven't used them enough personally to be comfortable writing an example solution for you without direct access to the data to play with, and it would still take me a little more time to get right than I can devote to this right now. Maybe this paragraph will motivate someone else to do that work.

SQL - 2 table values to be grouped by third unconnected value

I want to create a graph that pulls data from 2 user questions generated from within an SQL database.
The issue is that the user questions are stored in the same table, as are the answers. The only connection is that the question string includes a year value, which I extract using the LEFT command so that I output a column called 'YEAR' with a list of integer values running from 2013 to 2038 (25 year period).
I then want to pull the corresponding answers ('forecast' and 'actual') from each 'YEAR' so that I can plot a graph with a couple of values from each year (sorry if this isn't making any sense). The graph should show a forecast line covering the 25 year period with a second line (or column) showing the actual value as it gets populated over the years. I'll then be able to visualise if our actual value is close to our original forecast figures (long term goal!)
CODE BELOW
SELECT CAST((LEFT(F_TASK_ANS.TA_ANS_QUESTION,4)) AS INTEGER) AS YEAR,
-- first select takes left 4 characters of question and outputs value as string then coverts value to whole number.
CAST((CASE WHEN F_TASK_ANS.TA_ANS_QUESTION LIKE '%forecast' THEN F_TASK_ANS.TA_ANS_ANSWER END) AS NUMERIC(9,2)) AS 'FORECAST',
CAST((CASE WHEN F_TASK_ANS.TA_ANS_QUESTION LIKE '%actual' THEN ISNULL(F_TASK_ANS.TA_ANS_ANSWER,0) END) AS NUMERIC(9,2)) AS 'ACTUAL'
-- actual value will be null until filled in each year therefore ISNULL added to replace null with 0.00.
FROM F_TASK_ANS INNER JOIN F_TASKS ON F_TASK_ANS.TA_ANS_FKEY_TA_SEQ = F_TASKS.TA_SEQ
WHERE TA_ANS_ANSWER <> ''
AND (TA_TASK_ID LIKE '%6051' OR TA_TASK_ID LIKE '%6052')
-- The two numbers above refer to separate PPM questions that the user enters a value into
I tried GROUP BY 'YEAR' but I get an
Error: Each GROUP BY expression must contain at least one column that
is not an outer reference - which I assume is because I haven't linked
the 2 tables in any way...
Should I be adding a UNION so the tables are joined?
What I want to see is something like the following output (which I'll graph up later)
YEAR FORECAST ACTUAL
2013 135000 127331
2014 143000 145102
2015 149000 0
2016 158000 0
2017 161000 0
2018... etc
Any help or guidance would be hugely appreciated.
Thanks
Although the syntax is pretty hairy, this seems like a fairly simple query. You are in fact linking your two tables (with the JOIN statement) and you don't need a UNION.
Try something like this (using a common table expression, or CTE, to make the grouping clearer, and changing the syntax for slightly greater clarity):
WITH data
AS (
SELECT YEAR = CAST((LEFT(A.TA_ANS_QUESTION,4)) AS INTEGER)
, FORECAST = CASE WHEN A.TA_ANS_QUESTION LIKE '%forecast'
THEN CONVERT(NUMERIC(9,2), A.TA_ANS_ANSWER)
ELSE CONVERT(NUMERIC(9,2), 0)
END
, ACTUAL = CASE WHEN A.TA_ANS_QUESTION LIKE '%actual'
THEN CONVERT(NUMERIC(9,2), ISNULL(A.TA_ANS_ANSWER,0) )
ELSE CONVERT(NUMERIC(9,2), 0)
END
FROM F_TASK_ANS A
INNER JOIN F_TASKS T
ON A.TA_ANS_FKEY_TA_SEQ = T.TA_SEQ
-- It sounded like you wanted to include the ones where the answer was null. If
-- that's wrong, get rid of the test for NULL.
WHERE (A.TA_ANS_ANSWER <> '' OR A.TA_ANS_ANSWER IS NULL)
AND (TA_TASK_ID LIKE '%6051' OR TA_TASK_ID LIKE '%6052')
)
SELECT YEAR
, FORECAST = SUM(data.Forecast)
, ACTUAL = SUM(data.Actual)
FROM data
GROUP BY YEAR
ORDER BY YEAR
Try something like this ...
SELECT CAST((LEFT(F_TASK_ANS.TA_ANS_QUESTION,4)) AS INT) AS [YEAR]
,SUM(CAST((CASE WHEN F_TASK_ANS.TA_ANS_QUESTION LIKE '%forecast'
THEN F_TASK_ANS.TA_ANS_ANSWER ELSE 0 END) AS NUMERIC(9,2))) AS [FORECAST]
,SUM(CAST((CASE WHEN F_TASK_ANS.TA_ANS_QUESTION LIKE '%actual'
THEN F_TASK_ANS.TA_ANS_ANSWER ELSE 0 END) AS NUMERIC(9,2))) AS [ACTUAL]
FROM F_TASK_ANS INNER JOIN F_TASKS
ON F_TASK_ANS.TA_ANS_FKEY_TA_SEQ = F_TASKS.TA_SEQ
WHERE TA_ANS_ANSWER <> ''
AND (TA_TASK_ID LIKE '%6051' OR TA_TASK_ID LIKE '%6052')
GROUP BY CAST((LEFT(F_TASK_ANS.TA_ANS_QUESTION,4)) AS INT)