SQL Select 1 line in function of 3 MAX/MIN fields - sql

I try to create a view, or just a select for the moment, based on this function :
SELECT
FLAG
FROM
(
SELECT
TE.FLAG
FROM
EVT E
INNER JOIN EVT_TYP TE ON TE.ID = E.FK_TYPE_EVT
WHERE
E.FK_OBJECT = NUMOBJECT
order by
trunc(E.EVT_DATE) desc,
e.evt_number desc,
e.id desc
)
where
rownum = 1;
NUMOBJECT is the function parameter. Function returns one FLAG for that NUMOBJECT.
I want to select one flag for each E.FK_OBJECT IN EVT table.
Problems are I can have several lines in EVT table for one E.FK_OBJECT the same day, and I don't have time part of the date, most of the time. E.evt_number can be int or NULL. And E.id haven't the same order that E.EVT_DATE.
I don't know how I can succeed it, can you help me please? I try with imbricates select but looks likes it's not possible beacause of NULL e.evt_number.
I work on Oracle DB.
edit :
Sample of data :
Heberger image http://img15.hostingpics.net/thumbs/mini_229922Sanstitre.png
I tried this :
SELECT E.Fk_Object
,TE.FLAG
FROM (
SELECT
E.Fk_Object
,E.EVT_DATE
,E.evt_number
,MAX(E.id) id
FROM (
SELECT
E.Fk_Object
,E.EVT_DATE
,MAX(NVL(e.evt_number, - 1)) evt_number
FROM (
SELECT
E.Fk_Object
,MAX(E.EVT_DATE) EVT_DATE
FROM EVT E
GROUP BY E.Fk_Object
) E_MAX
INNER JOIN EVT E ON E.Fk_Object = E_MAX.Fk_Object
AND E.EVT_DATE = E_MAX.EVT_DATE
WHERE e.flg_suppression = 0
AND e.evt_date IS NOT NULL
GROUP BY E.Fk_Object
,E.EVT_DATE
) E_MAX_2
INNER JOIN EVT E ON E.Fk_Object = E_MAX_2.Fk_Object
AND E.EVT_DATE = E_MAX_2.EVT_DATE
AND NVL(e.evt_number, - 1) = NVL(E_MAX_2.evt_number, - 1)
GROUP BY E.Fk_Object
,E.EVT_DATE
,E.evt_number
) E_MAX_3
left JOIN EVT E ON E.Fk_Object = E_MAX_3.Fk_Object
AND E.EVT_DATE = E_MAX_3.EVT_DATE
AND NVL(e.evt_number, - 1) = NVL(E_MAX_3.evt_number, - 1)
AND E.id = E_MAX_3.id
INNER JOIN EVT_TYP TE ON TE.id = E.FK_EVT_TYP
ORDER BY 2
,3;
But it doesn't give me same results than function

Done !
Instead of NVL(E_MAX_2.evt_number, - 1) I have to use NVL(E_MAX_2.evt_number, 99) and not forget the trunc() for E.EVT_DATE to keep the same order than the function and it is ok !!
With that, it runs in 12 seconds. It was 54 before with the function.
I will test to create a view to see if it's even better.

If I understand correctly, you are looking for a query that gives you the latest flag for not only one, but several objects. You can do this by selecting records for all these objects and then grouping by object applying Oracle's KEEP FIRST/LAST.
select
e.fk_object,
max(te.flag) keep (dense_rank first
order by trunc(e.evt_date) desc, e.evt_number desc, e.id desc) as current_flag
from evt e
join evt_typ et on et.id = e.fk_type_evt
where fk_object in (numobject1, numobject2, numobject3)
group by e.fk_object;
The same can be used as a subquery. Let's say you have a table OBJECTS with a column STATUS and you want to show all objects of status 'new' with their current flag each:
select o.*, flags.current_flag
from objects o
join
(
select
e.fk_object,
max(te.flag) keep (dense_rank first
order by trunc(e.evt_date) desc, e.evt_number desc, e.id desc) as current_flag
from evt e
join evt_typ et on et.id = e.fk_type_evt
group by e.fk_object
) flags on flags.fk_object = o.id
where o.status = 'new';

Related

SQL Server aggregate function without group by

I want to include tcon.Inductive_Injection_Hours, tcon.Capacitive_Injection_Hours without applying group by. How can I do that?
SELECT
bp.Serial_Number,
tcon.Serial_Number AS ConverterSerialNumber,
MAX(tcon.Time_Stamp) AS DateStamp,
tcon.Inductive_Injection_Hours,
tcon.Capacitive_Injection_Hours
FROM
dbo.Bypass AS bp
INNER JOIN
dbo.Converter AS c ON bp.Bypass_ID = c.Bypass_ID
INNER JOIN
dbo.Converter_Tel_Data AS tcon ON c.Converter_ID = tcon.Converter_ID
WHERE
(bp.Site_ID = 7)
GROUP BY
bp.Serial_Number, tcon.Serial_Number,
tcon.Inductive_Injection_Hours, tcon.Capacitive_Injection_Hours
ORDER BY
ConverterSerialNumber
I have figured it out.
select [data].Serial_Number,Time_Stamp,Inductive_Injection_Hours,Capacitive_Injection_Hours,b.Serial_Number from Converter_Tel_Data as [data]
inner join dbo.Converter AS c On [data].Converter_ID = c.Converter_ID
inner join dbo.Bypass as b on c.Bypass_ID = b.Bypass_ID
WHERE
(Time_Stamp = (SELECT MAX(Time_Stamp) FROM Converter_Tel_Data WHERE Converter_ID = [data].Converter_ID)) And ([data].Site_ID=7)
ORDER BY [data].Serial_Number
You can use row_number - either in a CTE/derived table or using a trick with TOP 1.
Select Top 1 With Ties
bp.Serial_Number
, tcon.Serial_Number AS ConverterSerialNumber
, tcon.Time_Stamp AS DateStamp
, tcon.Inductive_Injection_Hours
, tcon.Capacitive_Injection_Hours
From dbo.Bypass AS bp
Inner Join dbo.Converter AS c On bp.Bypass_ID = c.Bypass_ID
Inner Join dbo.Converter_Tel_Data AS tcon ON c.Converter_ID = tcon.Converter_ID
Where bp.Site_ID = 7
Order By
row_number() over(Partition By bp.Serial_Number Order By tcon.Time_Stamp desc)
This should return the latest row from the tconn table for each bp.Serial_Number.

Using parameters with dynamic data in SSRS

Hi I have the following SQL with which I can get data. So I am trying to use a parameter to show only the data based on a week. When I run the query the define query parament dialog opens but when I click ok after that I get an error saying:
An error occurred while executing the query.
Incorrect syntax near ';'. (Microsoft SQL Server Report Builder)
If I don't declare the parameter then it gives me an error that says I have to declare the paramenter. If I choose the datatype of the parameter then the query run but define parameter dialog doesn't appear.
I am not sure what I doing here wrong. I have looked at everything that is available but i can't seem to figure it out.
Declare #Week;
WITH Day_Level
AS
(
SELECT Microsoft_VSTS_Scheduling_CompletedWork,
Microsoft_VSTS_Scheduling_OriginalEstimate,
Microsoft_VSTS_Scheduling_RemainingWork,
x.[[WorkingItem]].[System_Id]]],
[Date].[Date] AS '[Date].[Date]',
[Date].[WeekOfYear] AS '[Date].[WeekOfYear]',
[Date].[WeekString] AS '[Date].[WeekString]',
CONCAT(LEFT(DATENAME(WEEKDAY, [Date].[Date]),3),'.') AS '[Date].[Weekday]',
[Date].[Year] AS '[Date].[Year]',
[Date].[YearString] AS '[Date].[YearString]'
FROM
(
select
Microsoft_VSTS_Scheduling_CompletedWork,
Microsoft_VSTS_Scheduling_OriginalEstimate,
Microsoft_VSTS_Scheduling_RemainingWork,
[Item].[System_Id] AS '[WorkingItem].[System_Id]',
[Date].[Date] AS '[Date].[Date]',
ROW_NUMBER() OVER (PARTITION BY [Item].[System_Id], [Date].[Date] ORDER BY [Date].[Date], [Item].[System_Rev] DESC, [Fact].[LastUpdatedDateTime] DESC) AS RN
from dbo.FactWorkItemHistory Fact
inner join dbo.DimWorkItem Item
on fact.WorkItemSK = item.WorkItemSK
and fact.TeamProjectSK = item.TeamProjectSK
inner join dbo.DimDate [date]
on fact.DateSK = [date].DateSK
inner join dbo.DimTeamProject Project
on project.ProjectNodeSK = fact.TeamProjectSK
inner join dbo.DimPerson Person
on person.PersonSK = item.System_AssignedTo__PersonSK
inner join DimIteration Iteration
on iteration.IterationSK = item.IterationSK
where fact.RevisionCount is not null AND
[Project].[ProjectPath] = '\B2B_CRM\PhProduct'
) AS x
inner join dbo.DimDate [date]
on x.[[Date]].[Date]]] = [date].[Date]
WHERE x.RN = 1
AND Microsoft_VSTS_Scheduling_CompletedWork IS NOT NULL
),
Attributes
AS
(
select
[Fact].[Microsoft_VSTS_Scheduling_CompletedWork] AS '[WorkItemFact].[Microsoft_VSTS_Scheduling_CompletedWork]',
[Fact].[Sca_Common_CompletedWorkTotal] AS '[WorkItemFact].[Sca_Common_CompletedWorkTotal]',
[Item].[Sca_Common_WBS] AS '[WorkItem].[Sca_Common_WBS]',
LEFT([Item].[Sca_Common_WBS], 18) AS '[WorkItem].[Sca_Common_WBS_Short]',
[Item].[Sca_Common_WBSType] AS '[WorkItem].[Sca_Common_WBSType]',
[Item].[System_Id] AS '[WorkItem].[System_Id]',
[Person].[Name] AS '[AssignedTo].[Name]',
IIF (YEAR([Item].[System_RevisedDate]) = 9999, 'True', 'False') AS '[WorkItem].[LastRevision]',
[Iteration].[IterationPath] AS '[WorkItem].[Iteration]'
from dbo.FactWorkItemHistory Fact
inner join dbo.DimWorkItem Item
on fact.WorkItemSK = item.WorkItemSK
and fact.TeamProjectSK = item.TeamProjectSK
inner join dbo.DimTeamProject Project
on project.ProjectNodeSK = fact.TeamProjectSK
inner join dbo.DimPerson Person
on person.PersonSK = item.System_AssignedTo__PersonSK
inner join DimIteration Iteration
on iteration.IterationSK = item.IterationSK
where fact.RevisionCount is not null AND
[Project].[ProjectPath] = '\B2B_CRM\PhProduct'
and YEAR([Item].[System_RevisedDate]) = 9999
),
Final
AS
(
SELECT
ISNULL(Microsoft_VSTS_Scheduling_CompletedWork - lag(Microsoft_VSTS_Scheduling_CompletedWork) over (PARTITION BY Day_Level.[[WorkingItem]].[System_Id]]] order by Day_Level.[[Date]].[Date]]]),Microsoft_VSTS_Scheduling_CompletedWork)
AS CompletedWork,
Microsoft_VSTS_Scheduling_OriginalEstimate AS OriginalWork,
Microsoft_VSTS_Scheduling_RemainingWork AS RemainingWork,
Day_Level.[[Date]].[WeekOfYear]]] AS WeekNumber,
*
FROM Day_Level
INNER JOIN Attributes
ON Day_Level.[[WorkingItem]].[System_Id]]] = Attributes.[[WorkItem]].[System_Id]]]
)
Select *
FROM Final
where WeekNumber = (#Week)
Using your CTE, in SSRS create a dataset along the lines of
Select distinct WeekNumber
FROM Final
Assign that dataset to your (#Week) parameters (which should appear in Report Builder (or whatever else you're using to build the report)
Default Values can be set by using the same dataset and you might want to allow multiple values as well.
In this instance, my dataset is called dsOfferingType but the data is taken from the results dataset...
Does that make sense?
#JonTout I get what you are saying but this not what I want. So I minimized the query to the following where you can see that I have a put in a parameter (variable) at the end and when I query using this it opens up a dialog box like this.
select
Microsoft_VSTS_Scheduling_CompletedWork,
Microsoft_VSTS_Scheduling_OriginalEstimate,
Microsoft_VSTS_Scheduling_RemainingWork,
[Item].[System_Id] AS '[WorkingItem].[System_Id]',
[Date].[Date] AS '[Date].[Date]',
ROW_NUMBER() OVER (PARTITION BY [Item].[System_Id], [Date].[Date] ORDER BY [Date].[Date], [Item].[System_Rev] DESC, [Fact].[LastUpdatedDateTime] DESC) AS RN
from dbo.FactWorkItemHistory Fact
inner join dbo.DimWorkItem Item
on fact.WorkItemSK = item.WorkItemSK
and fact.TeamProjectSK = item.TeamProjectSK
inner join dbo.DimDate [date]
on fact.DateSK = [date].DateSK
inner join dbo.DimTeamProject Project
on project.ProjectNodeSK = fact.TeamProjectSK
inner join dbo.DimPerson Person
on person.PersonSK = item.System_AssignedTo__PersonSK
inner join DimIteration Iteration
on iteration.IterationSK = item.IterationSK
where fact.RevisionCount is not null AND
[Project].[ProjectPath] = '\B2B_CRM\PhProduct'
AND Microsoft_VSTS_Scheduling_CompletedWork IS NOT NULL
AND Microsoft_VSTS_Scheduling_CompletedWork = #Something
Now that I add the second part like this then it gives me this error. Don't know what is causing it to be like this.
SELECT Microsoft_VSTS_Scheduling_CompletedWork,
Microsoft_VSTS_Scheduling_OriginalEstimate,
Microsoft_VSTS_Scheduling_RemainingWork,
x.[[WorkingItem]].[System_Id]]],
[Date].[Date] AS '[Date].[Date]',
[Date].[WeekOfYear] AS '[Date].[WeekOfYear]',
[Date].[WeekString] AS '[Date].[WeekString]',
CONCAT(LEFT(DATENAME(WEEKDAY, [Date].[Date]),3),'.') AS '[Date].[Weekday]',
[Date].[Year] AS '[Date].[Year]',
[Date].[YearString] AS '[Date].[YearString]'
FROM
(
select
Microsoft_VSTS_Scheduling_CompletedWork,
Microsoft_VSTS_Scheduling_OriginalEstimate,
Microsoft_VSTS_Scheduling_RemainingWork,
[Item].[System_Id] AS '[WorkingItem].[System_Id]',
[Date].[Date] AS '[Date].[Date]',
ROW_NUMBER() OVER (PARTITION BY [Item].[System_Id], [Date].[Date] ORDER BY [Date].[Date], [Item].[System_Rev] DESC, [Fact].[LastUpdatedDateTime] DESC) AS RN
from dbo.FactWorkItemHistory Fact
inner join dbo.DimWorkItem Item
on fact.WorkItemSK = item.WorkItemSK
and fact.TeamProjectSK = item.TeamProjectSK
inner join dbo.DimDate [date]
on fact.DateSK = [date].DateSK
inner join dbo.DimTeamProject Project
on project.ProjectNodeSK = fact.TeamProjectSK
inner join dbo.DimPerson Person
on person.PersonSK = item.System_AssignedTo__PersonSK
inner join DimIteration Iteration
on iteration.IterationSK = item.IterationSK
where fact.RevisionCount is not null AND
[Project].[ProjectPath] = '\B2B_CRM\PhProduct'
) AS x
inner join dbo.DimDate [date]
on x.[[Date]].[Date]]] = [date].[Date]
WHERE x.RN = 1
AND Microsoft_VSTS_Scheduling_CompletedWork IS NOT NULL
AND Microsoft_VSTS_Scheduling_CompletedWork = #Something

Removing duplicates rows in left Joining query

SELECT Rec.[Reg_ID]
,Rec.[Reg_No]
,Rec.[Case_ID]
,Det.Deleted AS CaseDeleted
,[Status].[Status]
,Det.[Unit_Submission_Date] AS [Signature]
,TD.TargetDate AS [Target]
,TD.TargetID
FROM [dbo].[Regestrations] Rec
LEFT JOIN [dbo].[Reg_Details] Det ON Rec.Case_ID = Det.CaseID
LEFT JOIN [dbo].[lkpStatus] [Status] ON Rec.Status_ID = [Status].StatusID
LEFT JOIN TargetDate TD ON TD.RecommId = Rec.Reg_ID
WHERE (Det.MissionID = 50 AND [Status].[Status] = 1 AND Rec.Deleted = 0 AND Det.Deleted = 0)
GROUP BY Rec.[Reg_ID],Rec.[Reg_No],Rec.[Case_ID]
,[Status].[Status]
,Det.[Unit_Submission_Date]
,TD.TargetDate
,Det.Deleted
,TD.TargetID
ORDER BY TD.TargetID desc
I have the above query that is supposed to return rows with unique Rec.[Reg_No]. But joined table TargetDate can have duplicate Rec.[Reg_ID] and if thats the case i get duplicate Rec.[Reg_No] rows in my results.
Table TargetDate has a date time column so i want to eliminate the duplicate Rec.[Reg_No] by selecting 1 row with the latest date value from table TargetDate.
How do modify my Join condition or the query where clause to achive the above?
One way is to use a window function such as ROW_NUMBER() that will generate sequential number based on the specified partition. This generated number can then be used to get the latest row.
SELECT Reg_ID, Reg_No, Case_ID, CaseDeleted, [Status], Signature, [Target], TargetID
FROM
(
SELECT Rec.[Reg_ID]
,Rec.[Reg_No]
,Rec.[Case_ID]
,Det.Deleted AS CaseDeleted
,[Status].[Status]
,Det.[Unit_Submission_Date] AS [Signature]
,TD.TargetDate AS [Target]
,TD.TargetID
,RN = ROW_NUMBER() OVER (PARTITION BY Rec.[Reg_No] ORDER BY TD.TargetID DESC)
FROM [BOI].[dbo].[Regestrations] Rec
LEFT JOIN [dbo].[Reg_Details] Det ON Rec.Case_ID = Det.CaseID
LEFT JOIN [dbo].[lkpStatus] [Status] ON Rec.Status_ID = [Status].StatusID
LEFT JOIN TargetDate TD ON TD.RecommId = Rec.Reg_ID
WHERE (Det.MissionID = 50 AND [Status].[Status] = 1 AND Rec.Deleted = 0 AND Det.Deleted = 0)
) subQuery
WHERE RN = 1
ORDER BY TargetID desc
This query can work correctly if you remove TD.TargetDate from GROUP BY clause and compute what you really need in output - MAX(TD.TargetDate)
But preferable way it to avoid GROUP BY clause at all:
...
FROM [BOI].[dbo].[Regestrations] Rec
LEFT JOIN [dbo].[Reg_Details] Det ON Rec.Case_ID = Det.CaseID
LEFT JOIN [dbo].[lkpStatus] [Status] ON Rec.Status_ID = [Status].StatusID
OUTER APPLY(
SELECT TOP 1 td.TargetDate, td.TargetID
FROM TargetDate TD
WHERE TD.RecommId = Rec.Reg_ID
ORDER BY TD.TargetDate DESC
) td
...
You should first find latest TargetDate for each Reg_ID or RecommId. Then you can use your normal join with TargetDate table just this time with matching both the RecommId and TargetDate.
Try this Query:
SELECT Rec.[Reg_ID]
,Rec.[Reg_No]
,Rec.[Case_ID]
,Det.Deleted AS CaseDeleted
,[Status].[Status]
,Det.[Unit_Submission_Date] AS [Signature]
,TD.TargetDate AS [Target]
,TD.TargetID
FROM [BOI].[dbo].[Regestrations] Rec
LEFT JOIN [dbo].[Reg_Details] Det ON Rec.Case_ID = Det.CaseID
LEFT JOIN [dbo].[lkpStatus] [Status] ON Rec.Status_ID = [Status].StatusID
LEFT JOIN (SELECT RecommId, MAX(TargetDate) MaxTargetDate GROUP BY RecommId) TDWithLatestDate ON TDWithLatestDate.RecommId = Rec.Reg_ID
LEFT OUTER JOIN TargetDate ON TD.RecommId = TDWithLatestDate.RecommId AND TD.TargetDate = TDWithLatestDate.MaxTargetDate
WHERE (Det.MissionID = 50
AND [Status].[Status] = 1
AND Rec.Deleted = 0
AND Det.Deleted = 0
)
GROUP BY Rec.[Reg_ID]
,Rec.[Reg_No]
,Rec.[Case_ID]
,[Status].[Status]
,Det.[Unit_Submission_Date]
,TD.TargetDate
,Det.Deleted
,TD.TargetID
ORDER BY TD.TargetID desc
You can improve this query if you want to avoid tie when there more than one record fighting to be latest.

First event per patients

The attached code is supposed to return the first ORDER_PROC.ORDER_INST for each patient. I'm getting multiple records in some cases.
Any suggestions on a better approach?
Thanks
Steve
SELECT DISTINCT
ORDER_PROC.PAT_ENC_CSN_ID as ordercsn, Min(ORDER_PROC.ORDER_INST) as
CodeStatus_Datetime, CLARITY_SER.PROV_NAME as CodeStatus_OrderProvider
FROM
ORDER_PROC with(nolock) , ORDER_METRICS with(nolock) , CLARITY_SER
with(nolock)
WHERE
ORDER_PROC.ORDER_PROC_ID = ORDER_METRICS.ORDER_ID AND
ORDER_METRICS.ORDERING_PROV_ID = CLARITY_SER.PROV_ID AND
--ORDER_PROC.REASON_FOR_CANC_C IS NULL AND
(ORDER_PROC.PROC_CODE = 'COD1' OR
ORDER_PROC.PROC_CODE = 'COD2' OR
ORDER_PROC.PROC_CODE = 'COD3'
)
GROUP by
ORDER_PROC.PAT_ENC_CSN_ID, ORDER_PROC.ORDER_INST,CLARITY_SER.PROV_NAME
Use ROW_NUMBER() to create partition for each patient
SELECT *
FROM (
SELECT OP.PAT_ENC_CSN_ID as ordercsn,
OP.ORDER_INST,
CodeStatus_Datetime,
CS.PROV_NAME as CodeStatus_OrderProvider,
ROW_NUMBER() OVER (PARTITION BY OP.PAT_ENC_CSN_ID
ORDER BY OP.ORDER_INST) as rn
FROM ORDER_PROC OP
JOIN ORDER_METRICS OM
OP.ORDER_PROC_ID = OM.ORDER_ID
JOIN CLARITY_SER CS
OM.ORDERING_PROV_ID = CS.PROV_ID
WHERE
OP.PROC_CODE IN ('COD1','COD2','COD3')
) as T
WHERE rn = 1

Get the rest of the row in a max group by

I'm trying to acquire the most recently passed training someone has taken. To do this, I have a view that works great
CREATE OR REPLACE FORCE VIEW MYAPP.most_recent_training (
employee_id, course_id, date_taken
) AS SELECT
who.employee_id,
course.course_id,
MAX(sess.end_date) date_taken
FROM employee_session_join esj
JOIN training_session sess on sess.session_id = esj.session_id
JOIN course_version vers on vers.version_id = sess.version_id
JOIN course course on course.course_id = vers.course_id
JOIN employee who on who.employee_id = esj.employee_id
WHERE esj.active_flag = 'Y'
AND sess.active_flag = 'Y'
AND course.active_flag = 'Y'
AND who.active_flag = 'Y'
AND esj.approval_status = 5 -- successfully passed
GROUP BY who.employee_id, course.course_id
Okay, so my query works excellent. Here's my problem - I also need the expiry date so I know when they go out of compliance. This is stored as a number of months on the version. But I can't add vers.valid_for_months because it complains ORA-00979: not a GROUP BY expression.
I just want to get whatever the rest of that row is. How can I do this?
I would think this would solve your problem:
SELECT who.employee_id, course.course_id,
MAX(add_months(sess.end_date, vers.valid_for_months))
That gets the latest end date. If you want the end date for the last session, use row_number():
SELECT employee_id, course_id, end_date
FROM (SELECT who.employee_id, course.course_id, sess.end_date,
row_number() over (partition by who.employee_id, course.course_id
order by sess.end_date
) as seqnum
FROM employee_session_join esj
JOIN training_session sess on sess.session_id = esj.session_id
JOIN course_version vers on vers.version_id = sess.version_id
JOIN course course on course.course_id = vers.course_id
JOIN employee who on who.employee_id = esj.employee_id
WHERE esj.active_flag = 'Y'
AND sess.active_flag = 'Y'
AND course.active_flag = 'Y'
AND who.active_flag = 'Y'
AND esj.approval_status = 5 -- successfully passed
) e
WHERE seqnum = 1;