I have a table called rx_claims with columns epi, drugname, gpi. The table rx_claim is have historical saved data and I need to report if any changes in the gpi which is 16 digit number. The logic which I need is if the first 10 number of gpi changes from the historical data then report as new med and if 12 digits change then report as dose change with new and old column data.
for example : epi is 100 and drug name is ibrofine and gpi for this drug is 0123456789012300 ( historical data ) . Now we have a incoming record of 100 and drugname is still ibrofine but dosage change so it changes the gpi code to 0123456789000000 i.e the last 4 digits has changed so i want to show the resulted out as drugname : ibrofine and oldgpi is 0123456789012300 and new gpi is0123456789000000
you could use a query to compare the historical data with the current data
SELECT
epi,
drugname,
gpi AS current_gpi,
CASE
WHEN SUBSTR(gpi, 1, 10) != SUBSTR(hist.gpi, 1, 10) THEN 'New Med'
WHEN SUBSTR(gpi, 1, 10) = SUBSTR(hist.gpi, 1, 10) AND SUBSTR(gpi, 12, 5) != SUBSTR(hist.gpi, 12, 5) THEN CONCAT('Dose Change (Old GPI: ', hist.gpi, ')')
END AS change_description
FROM
rx_claims
LEFT JOIN
(
SELECT
epi,
gpi
FROM
rx_claims
WHERE
-- add condition to filter for historical data
date < '2023-02-15'
) hist
ON
rx_claims.epi = hist.epi
This query compares the current GPI value with the historical GPI value for each epi number. If the first 10 digits of the GPI value have changed, it reports the change as a "New Med". If only the 12th to 16th digits have changed, it reports the change as a "Dose Change" with the old GPI value included in the change description.
Related
I have the following tables:
Episodes:
Clients:
My DAX calculation sums up [Days_epi] unique values, from Episodes tbl, grouping them by [ProgramID_epi], [EpisodeID_epi], [ClientID_epi].
So, the SUM of [Days_epi] = 3 + 5 + 31 + 8 + 15 + 20 + 10 = 92
Here is my working code for this:
DaysSUM =
CALCULATE (
SUMX (
SUMMARIZE (
'Episodes',
'Episodes'[EpisodeID_epi],
'Episodes'[ProgramID_epi],
'Episodes'[ClientID_epi],
'Episodes'[Days_epi]
),
'Episodes'[Days_epi]
),
FILTER (
'Episodes',
'Episodes'[Category_epi] = "Homeless"
)
)
I need to add two advanced filters to the calculation above:
Filter 1 should ONLY KEEP records in Episodes, if the records in the Clients have the difference between [DischDate_clnt] and [AdmDate_clnt] >= 365.
Filter 1 in SQL statement is
DATEDIFF(DAY, [AdmDate_clnt], [DischDate_clnt]) >= 365)
After that, Filter 2 should ONLY KEEP records in Episodes, if the records in the Clients have
[Date_clnt] >= [AdmDate_clnt] + 12 months. (12 month after the Admission Date)
Filter 2 in SQL statement is
[Date_clnt] <= DATEADD(MONTH, 12, [[AdmDate_clnt])
So, after applying those two filters I expect the records 6 and 10 of the Episodes tbl must be excluded (filtered out), because the records 2 and 3 of the Clients tbl (highlighted in green) are not satisfied my Filter 1 / Filter 2.
Here is the final Episodes dataset I should have (without the 2 records in red):
I was starting to update my DAX code as the following (below).
But keep receiving error "Parameter is not the correct type"
enter
DaysSUM_Filters =
CALCULATE (
SUMX (
SUMMARIZE (
'Episodes',
'Episodes'[EpisodeID_epi],
'Episodes'[ProgramID_epi],
'Episodes'[ClientID_epi],
'Episodes'[Days_epi]
),
'Episodes'[Days_epi]
),
FILTER (
'Episodes',
'Episodes'[Category_epi] = "Homeless"
), TREATAS(DATEDIFF('Clients'[AdmDate_clnt],
'Clients'[DischDate_clnt], DAY)>=365,
'Clients'[Date_clnt])
)
Not exactly sure how to set those 2 filters correctly in DAX Power BI, as I
am relatively new to it.
Please help!
I can't say about all the case. But what is obvious is that you use TREATAS in a wrong way. It works like this TREATAS({"Red", "White", "Blue"}, 'Product'[Color]).
In your case
DATEDIFF('Clients'[AdmDate_clnt],
'Clients'[DischDate_clnt], DAY)>=365
will return TRUE or FALSE value. The first argument of TREATAS - is a column or set of columns not a single value.
You can use the filter like this:
FILTER(
'Clients'
,DATEDIFF(
'Clients'[AdmDate_clnt]
,'Clients'[DischDate_clnt]
,DAY
)>=365
)
This will return you a filtered table.
This may work if your tables are linked.
Hi I am trying to use group by rollup to get a grand total for a column but when I do it is duplicating the rows. What am I doing wrong? Thanks.
Code:
WITH TOTS AS
(
select
swkl.prn_cln_n,
swkl.swkl_bgn_dt,
swkl.swkl_end_dt,
swkl.sec_id,
actbl.*
from actbl
join actblc on actblc.actbl_seq_id = actbl.actbl_seq_id
join swkl on swkl.swkl_id = actblc.swkl_id
where swkl.prn_cln_n = '242931'
and swkl.stlm_rcd_sta_cd = 'A'
and trunc(swkl.stlm_rcd_mntd_ts) = to_date('03/10/2021','mm/dd/yyyy') --'14-JUN-2021'
and actblc.actblc_wkfl_pcs_cd = 'COM'
and actblc.stlm_rcd_sta_cd = 'A'
)
,F2 AS
(
SELECT PRN_CLN_N AS CLIENT_NUMBER
,LINE_TYPE_HM
,PR_TYP_C
,SUM(BIIL_A) AS BILL_AMOUNT
FROM TOTS
GROUP BY PRN_CLN_N
,LINE_TYPE_HM
,PR_TYP_C
)
SELECT coalesce(CLIENT_NUMBER,'TOTAL') AS CLIENT_NUMBER
,LINE_TYPE_HM
,PR_TYP_C
,SUM(BILL_AMOUNT) BILL_AMOUNT
FROM F2
group by rollup (CLIENT_NUMBER
,LINE_TYPE_HM
,PR_TYP_C)
There's nothing wrong, as far as I can tell.
When using rollup, you specify columns in it - client_number, line_type_hm, pr_typ_c which is 3 column. rollup will produce 3 + 1 = 4 levels of subtotals. Those subtotals are visually identified by having NULL values in rollup columns. In your screenshot,
1st level are all "fully populated" lines (those that have all columns with some values, i.e. the 1st line, 3rd, 5th, ...)
2nd level are lines whose pr_typ_c is NULL (2nd line, 4th, 6th, ...)
3rd level is the penultimate row (has both line_type_hm and pr_typ_c empty)
4th level is "grand total", the last line with TOTAL in client_number column
I don't have your tables nor data so it is you who might know what to do next because you can reduce number of subtotals by performing partial rollup. How? For example,
group by client_number, rollup(line_type_hm, pr_typ_c)
or any other combination of rollup columns.
Try it and see what happens.
I'm trying to do an Excel kind of calculation in SQL. This involves using the closing rate (ClRate) from the previous row and using it to calculate values in the next row. The table starts from 1 Jan and has 1000 rows and each row has known data and data which needs to be calculated (shown in [ ])
Date RecQty RecAmt IssQty IssAmt ClQty ClAmt ClRate
1 Jan - - - - 100 $20,000 200
2 Jan +10 +$2100 -5 [ ] [ ] [ ] [ ]
The calculations to generate the desired result are in the table below
Date RecQty RecAmt IssQty IssAmt ClQty ClAmt ClRate
1 Jan 100 $20,000 200
2 Jan +10 +$2100 -5 -[200*5] [100+10-5] [20,000+2100-200*5] [ClAmt/ClQty]
The IssAmt for each day will be calculated by multiplying the IssQty by the previous days' ClRate. The ClQty is computed as previous day ClQty + current day RecQty - current day IssQty. The ClAmt is computed as previous day ClAmt+ current day RecAmt - current day IssAmt. Finally, the ClRate for each day is computed as ClAmt / ClQty
The only ClRate known is the opening inventory row of the table (1 Jan)- thereafter the ClRate for each subsequent row needs to be computed.
In Excel, you would simply do this calculation by linking the required cells of the previous row and copying/pasting the formula to all the rows below.
How would you do this in SQL? I have tried self joining CTEs, loops and LAG- none of these seems to work. The reason is that the ClRate for each row from 2 Jan onwards is not known - and while Excel can handle computing results on the fly which are used in the following row - SQL is unable to do this.
Seeking help to solve this problem. I'm using SQL Server 2017 and SSMS. If required I can provide the code
Table DDL
CREATE TABLE [Auto].[IronOreTbl](
[Id] [int] NULL,
[Counter] [int] NULL,
[TDate] [date] NOT NULL,
[RecQty] [decimal](16, 2) NULL,
[RecAmt] [decimal](16, 2) NULL,
[IssQty] [decimal](16, 2) NULL,
[IssAmt] [decimal](16, 2) NULL,
[ClQty] [decimal](16, 2) NULL,
[ClAmt] [decimal](16, 2) NULL,
[ClRate] [decimal](16, 2) NULL
) ON [PRIMARY]
GO
INSERT INTO [Auto].[IronOreTbl]
([Id],[Counter],[TDate],[RecQty],[RecAmt],[IssQty],[IssAmt],[ClQty],[ClAmt],[ClRate])
VALUES
(1,0,'2019-01-01',NULL,NULL,NULL,NULL,100,20000,200),
(2,1,'2019-01-02',10,2100,5,NULL,105,NULL,NULL),
(3,2,'2019-01-03',8,1600,2,NULL,111,NULL,NULL),
(4,3,'2019-01-04',20,2400,10,NULL,121,NULL,NULL)
CTE attempts
;WITH ClAmtCTE AS
(
SELECT
Id,RecQty,RecAmt,IssQty,ClQty,ClAmt,ClRate
,EffRate = ClRate
,CumHoldVal= ClAmt
--CAST(ClAmt AS decimal(16,2))
,CumClRt=CAST(ClRate AS decimal(16,2))
,[Counter]
FROM
[Auto].IronOreTbl
WHERE
Id=1
UNION ALL
SELECT
C2.Id,C2.RecQty,c2.RecAmt,C2.IssQty,C2.ClQty,C2.ClAmt,c2.ClRate,
EffRate = (SELECT CumClRt WHERE C2.ID=C2.[Counter]+1),
CumRN =
CAST(
(
CumHoldVal+ISNULL(C2.RecAmt,0)-
(EffRate)*ISNULL(C2.IssQty,0)
)
AS decimal(16,2)
),
CumClRt=CAST(CumHoldVal/C2.ClQty AS decimal(16,2)),
C2.[Counter],
FROM
[Auto].IronOreTbl C2
INNER JOIN ClAmtCTE C1 ON C1.Id = C2.[Counter]
The following code achieves the desired result - while I had got close several days ago, it still took all this time to tie up the last bit; of matching the ClRate with the correct row. There was an additional issue encountered where on days where there are no issues, but only receipts, the rate picked up belonged to the wrong row (I still have no clue why and how this was happening - all I know is that the previous code needed revision to resolve this discrepancy and the modified code attends to the same)
;WITH ClAmtCTE AS
(
SELECT
Id,RecQty,RecAmt,IssQty,ClQty,ClAmt,ClRate
,EffRate = ClRate
,CumHoldVal= ClAmt
--CAST(ClAmt AS decimal(16,2))
,CumClRt=CAST(ClRate AS decimal(16,2))
,[Counter]
FROM
[Auto].IronOreTbl
WHERE
Id=1
UNION ALL
SELECT
C2.Id,C2.RecQty,c2.RecAmt,C2.IssQty,C2.ClQty,C2.ClAmt,c2.ClRate,
EffRate = (SELECT CumClRt WHERE C2.ID=C2.[Counter]+1),
CumRN =
CAST(
(
CumHoldVal+ISNULL(C2.RecAmt,0)-
((SELECT CumClRt WHERE C2.ID=C2.[Counter]+1))*ISNULL(C2.IssQty,0)
)
AS decimal(16,2)
),
CumClRt=CAST((CumHoldVal+ISNULL(C2.RecAmt,0)-
((SELECT CumClRt WHERE C2.ID=C2.[Counter]+1))*ISNULL(C2.IssQty,0))/C2.ClQty AS decimal(16,2)),
C2.[Counter]
FROM
[Auto].IronOreTblC2
INNER JOIN ClAmtCTE C1 ON C1.Id = C2.[Counter]
)
UPDATE [Auto].IronOreTbl
SET ClRate = T1.CumClRt,
ClAmt=CumHoldVal
FROM ClAmtCTE T1
INNER JOIN [Auto].IronOreTbl T2
ON T1.ID = T2.Id
OPTION (MAXRECURSION 0)
Attempting and, in what appears to me as, solving it has taught me several things. Primarily these include:
Calculations which you can set up and run in a heartbeat in a spreadsheet are anything but in SQL
Excel has the ability to both calculate on the fly and utilise results calculated on the fly in the dependent calculations. SQL cannot do this. Having this ability in Excel means you do not have to iterate over the data - once to have Excel compute the results and then for Excel to apply the results where they are needed
For all its use and utility as a data housing medium SQL has a long way to go in attending to standard real world calculations - such as this example; multiple loans, changing interest rates and relevant interest calculations etc etc.
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.
I have a table with different objects and the objects evolve over time. One object is identified by object_number and we can track it with the object_line_number. And every evolution of the object has a status.
I want to calculate the time elapsed between some status.
Below is my table for one object_number "us1":
In yellow are the rowscontaining the starting date. They are found if (status_id = 0 and (old_status <> 0 or object_line_number = 1) and emergency_level = 1).
In green are the rows containing the ending date. They are found if (status_id =2,3,4,5 and old_status = 0).
The column old_status does not exist in the table. This is the status of the previous row (according to the object)line_number). I am retrieving it thanks to the following measure:
old_status = CALCULATE (
MAX(fact_object[status_id]),
FILTER (
ALL(fact_object),
fact_object[object_line_number] = IF(fact_object[object_line_number]=1, fact_object[object_line_number], MAX (fact_object[object_line_number])-1)),
VALUES (fact_object[object_number]))
I am in DirectQuery mode, so a lot of functions are not present for Calculated Columns, that's why I am using Measures.
Once that is done, I want then to be able to get for every green row the date_modification of the previous yellow row.
In this example, the result would be 4/4 then 1. So that I can calculate the time difference between the date_modification of the current green row and the date_modification of the previous yellow row.
So I was thinking of adding a new column named date_received, which is the date_modification of the previous yellow row;
From there, I just have to keep only the green rows and calculate the difference between date_modification and date_received.
My final calcul is actually to have this :
Result = (number of green rows which date difference between date_modification and date_received <= 15 min) / (number of green rows
which DAY(date_modification) = DAY(date_received))
But I don't know how to do it.
I have tried in the same spirit of the old_status measure to do this:
date_received = CALCULATE (
MAX(fact_object[date_modification]),
FILTER (
ALL(fact_object),
(fact_object[object_line_number] = MAX (fact_object[object_line_number])-1) && MY OTHER FILTERS
),
VALUES (fact_object[object_number])
)
But didn't succeed.
In SQL, the equivalent would be like this:
SELECT
SUM(CASE WHEN (DATEDIFF(MINUTE, T.date_received, T.date_planification) <= 15) THEN 1 ELSE 0 END) /
SUM(CASE WHEN (DAY(T.date_received) = DAY(T.date_planification)) THEN 1 ELSE 0 END) as result
FROM (
SELECT *, T.status_id as current_status,
LAG(T.date_modification) OVER(PARTITION BY T.object_number ORDER BY T.object_line_number) as date_received,
T.date_modification as date_planification
FROM
(
select *,
LAG (status_id) OVER(PARTITION BY object_number ORDER BY object_line_number) AS old_status
from dbo.fact_object
) AS T
WHERE ((T.status_id = 0 AND (T.old_status <> 0 OR T.object_line_number = 1) AND T.emergency_level = 1) OR (T.old_status = 0 AND T.status_id IN (2,3,4,5)))--974
) AS T
WHERE old_status = 0
(Well maybe there is a better way to do it in SQL that I've done).
How can I achieve this?
In this case, I would first sort the table by Object then by Object Line number (or Date Modified - but these appear not to change for each row.)
Duplicate the table
Table1 - Add an index starting at 1
Table2 - Add an index starting at 0
From Table1, merge it with table2, using the new index fields
Expand the MergedStatus ID (rename to NextStatusID) and the Object (rename to NextObject) field.
You can now create a new conditional column to compare the two status fields. E.g. Status 2 = If Object = NextObject then [NextStatusID] else null