Can a IF Statement be used in a Pivot function? - sql

I finally figured out how to obatin this through a pivot via some online articles. However I still have a two issue, the code posted below works fine and returns my results for the span of a year. Issue that i'm still encountering however is, theres a parmeter being sent into this sproc call 'DateType' and it can be 'M' or 'Y'. if it's 'M' I need it to follow the logic below. If its 'Y', need it to follow same logic but populate the 'YTD' field. I'm not sure how to integrate a 'IF' statement into the use of this Pivot, or if its even possible. Any help with this would be greatly appreicated.
The 2nd issue thats not represented in the code below, is currently the logic shows the results for a span of a year. However I also need to add next to the result field the rating field. Example: 'JAN_Result | Jan_Rating | Feb_Result | Feb_Rating...' Can two fields be pivoted like this?
UPDATED Current Logic:
'code'
Select EmployeeID
,Employee
,EmpGroupID
,PA
,EmpLevel
,ObjectiveName as Objective
,Objectiveid AS Objectiveid
,Weighting
,ReportingYear
,[1] as JAN_Result
,[2] as FEB_Result
,[3] as MAR_Result
,[4] as APR_Result
,[5] as MAY_Result
,[6] as JUN_Result
,[7] as JUL_Result
,[8] as AUG_Result
,[9] as SEP_Result
,[10] as OCT_Result
,[11] as NOV_Result
,[12] as DEC_Result
,[13] as YTD
From
(
Select
EmployeeID
,Employee
,EmpGroupID
,PA
,EmpLevel
,ObjectiveName
,Objectiveid
,Weighting
,ReportingYear
,Result
,Rating
,Max(CASE WHEN r.datetype = 'M' THEN Month(startdate) WHEN r.datetype = 'Y' THEN 13 END) as StartMonth
From #tblResults R
INNER JOIN #Emphist h
ON r.Empgroupid = h.Groupid
LEFT OUTER JOIN Config.tblRatingDescription rt
ON r.Rating = rt.RatingID
LEFT OUTER JOIN Config.tblRatingDescription rtovr
ON r.RatingOverride = rtovr.RatingID
WHERE r.datetype IN ('M','Y')
and r.startdate BETWEEN '2012-01-01' AND '2012-04-01'
Group By
EmployeeID,
Employee,
EmpGroupID,
PA,
EmpLevel,
ObjectiveName,
Objectiveid,
ReportingYear,
Weighting,
h.sortorder,
Result,
Rating
)ps
PIVOT
(
max(result)
FOR StartMonth IN([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13])
) as pvt
'code'
Example Data:
EmployeeID Employee EmpGroupID PA EmpLevel Objective Jan_Result Feb_Result
1010101 TestUser 111 NE CustService Equip_Res 94.44 9.92

Your statement is very big. I will not repeat it. Basically, all you need to do is to replace this line:
,Month(startdate) as StartMonth
with a:
,CASE WHEN r.datetype = 'M' THEN Month(startdate) ELSE 13 END as StartMonth
If other values come on board, you can just continue the statement:
,CASE WHEN r.datetype = 'M' THEN Month(startdate) WHEN r.datetype = 'Q' THEN 14 ELSE 13 END as StartMonth

Related

Datediff on 2 rows of a table with a condition

My data looks like the following
TicketID OwnedbyTeamT Createddate ClosedDate
1234 A
1234 A 01/01/2019 01/05/2019
1234 A 10/05/2018 10/07/2018
1234 B 10/04/2019 10/08/2018
1234 finance 11/01/2018 11/11/2018
1234 B 12/02/2018
Now, I want to calculate the datediff between the closeddates for teams A, and B, if the max closeddate for team A is greater than max closeddate team B. If it is smaller or null I don't want to see them. So, for example,I want to see only one record like this :
TicketID (Datediff)result-days
1234 86
and for another tickets, display the info. For example, if the conditions aren't met then:
TicketID (Datediff)result-days
2456 -1111111
Data sample for 2456:
TicketID OwnedbyTeamT Createddate ClosedDate
2456 A
2456 A 10/01/2019 10/05/2019
2456 B 08/05/2018 08/07/2018
2456 B 06/04/2019 06/08/2018
2456 finance 11/01/2018 11/11/2018
2456 B 12/02/2018
I want to see the difference in days between 01/05/2019 for team A, and
10/08/2018 for team B.
Here is the query that I wrote, however, all I see is -1111111, any help please?:
SELECT A.incidentid,
( CASE
WHEN Max(B.[build validation]) <> 'No data'
AND Max(A.crfs) <> 'No data'
AND Max(B.[build validation]) < Max(A.crfs) THEN
Datediff(day, Max(B.[build validation]), Max(A.crfs))
ELSE -1111111
END ) AS 'Days-CRF-diff'
FROM (SELECT DISTINCT incidentid,
Iif(( ownedbyteam = 'B'
AND titlet LIKE '%Build validation%' ), Cast(
closeddatetimet AS NVARCHAR(255)), 'No data') AS
'Build Validation'
FROM incidentticketspecifics) B
INNER JOIN (SELECT incidentid,
Iif(( ownedbyteamt = 'B'
OR ownedbyteamt =
'Finance' ),
Cast(
closeddatetimet AS NVARCHAR(255)), 'No data') AS
'CRFS'
FROM incidentticketspecifics
GROUP BY incidentid,
ownedbyteamt,
closeddatetimet) CRF
ON A.incidentid = B.incidentid
GROUP BY A.incidentid
I hope the following answer will be of help.
With two subqueries for the two teams (A and B), the max date for every Ticket is brought. A left join between these two tables is performed to have these information in the same row in order to perform DATEDIFF. The last WHERE clause keeps the row with the dates greater for A team than team B.
Please change [YourDB] and [MytableName] in the following code with your names.
--Select the items to be viewed in the final view along with the difference in days
SELECT A.[TicketID],A.[OwnedbyTeamT], A.[Max_DateA],B.[OwnedbyTeamT], B.[Max_DateB], DATEDIFF(dd,B.[Max_DateB],A.[Max_DateA]) AS My_Diff
FROM
(
--The following subquery creates a table A with the max date for every project for team A
SELECT [TicketID]
,[OwnedbyTeamT]
,MAX([ClosedDate]) AS Max_DateA
FROM [YourDB].[dbo].[MytableName]
GROUP BY [TicketID],[OwnedbyTeamT]
HAVING [OwnedbyTeamT]='A')A
--A join between view A and B to bring the max dates for every project
LEFT JOIN (
--The max date for every project for team B
SELECT [TicketID]
,[OwnedbyTeamT]
,MAX([ClosedDate]) AS Max_DateB
FROM [YourDB].[dbo].[MytableName]
GROUP BY [TicketID],[OwnedbyTeamT]
HAVING [OwnedbyTeamT]='B')B
ON A.[TicketID]=B.[TicketID]
--Fill out the rows on the max dates for the teams
WHERE A.Max_DateA>B.Max_DateB
You might be able to do with a PIVOT. I am leaving a working example.
SELECT [TicketID], "A", "B", DATEDIFF(dd,"B","A") AS My_Date_Diff
FROM
(
SELECT [TicketID],[OwnedbyTeamT],MAX([ClosedDate]) AS My_Max
FROM [YourDB].[dbo].[MytableName]
GROUP BY [TicketID],[OwnedbyTeamT]
)Temp
PIVOT
(
MAX(My_Max)
FOR Temp.[OwnedbyTeamT] in ("A","B")
)PIV
WHERE "A">"B"
Your sample query is quite complicated and has conditions not mentioned in the text. It doesn't really help.
I want to calculate the datediff between the closeddates for teams A, and B, if the max closeddate for team A is greater than max closeddate team B. If it is smaller or null I don't want to see them.
I think you want this per TicketId. You can do this using conditional aggregation:
SELECT TicketId,
DATEDIFF(day,
MAX(CASE WHEN OwnedbyTeamT = 'B' THEN ClosedDate END),
MAX(CASE WHEN OwnedbyTeamT = 'A' THEN ClosedDate END) as diff
)
FROM incidentticketspecifics its
GROUP BY TicketId
HAVING MAX(CASE WHEN OwnedbyTeamT = 'A' THEN ClosedDate END) >
MAX(CASE WHEN OwnedbyTeamT = 'B' THEN ClosedDate END)

Building Subquery to be a column/Field Name

I am unable to bundled groups of subqueries correctly in order to create column titled "Discharge_To"
I am using Teradata Studio Express. I was asked to create a column for field that is not inside a table we normally used. We want to know where a patient was discharged to from a previous place of service. In order to answer this, there has to be steps to determine that. So far, I can get it read correctly until line 94.
Select S.Member_ID, S.PAC_Sty_ID, S.Stay_Admit_Date, S.Stay_Discharge_Date, S.POS, S.LOS,
(
Select
S.Member_ID, S.PAC_Sty_ID,
Case
When S.Discharge_To is null
and H.POS is not null And S.POS <> '12' then 'Home With Care'
When S.Discharge_To is null then 'Home Without Care'
Else S.Discharge_To
End Discharge_To
From (
Select
S.Member_ID, S.PAC_Sty_ID, S.Stay_Admit_Date, S.Stay_Discharge_Date, S.POS,
Case trim(D.POS)
When '21' then 'Hospital' When '23' then 'ER' When '31' then 'SNF'
When '61' then 'IRF' When 'LTAC' then 'LTAC'
End Discharge_To
From ECONIMICS.PAC_02_MODEL_SUMMARY_Combined S
Left Join (
Select S.Member_ID, S.PAC_Sty_ID, S.POS, S.Stay_Admit_Date, S.Stay_Discharge_Date
From ECONIMICS.PAC_02_MODEL_SUMMARY_Combined S
Where PAC_Sty_ID is not null
And POS <> '12'
) D On D.Member_ID = S.Member_ID And D.PAC_Sty_ID <> S.PAC_Sty_ID
And D.Stay_Admit_Date Between S.Stay_Admit_Date and S.Stay_Discharge_Date + 1
Where S.PAC_Sty_ID is not null
Qualify Row_Number() Over (
Partition By S.PAC_Sty_ID Order By Case trim(D.POS)
When '21' then 1 When 'LTAC' then 2 when '61' then 3 When '31' then 4 end
) = 1
) S
Left Join (
Select *
From ECONIMICS.PAC_02_MODEL_SUMMARY_Combined
Where POS = '12'
) H On H.Member_ID = S.Member_ID
And H.From_Date Between S.Stay_Discharge_Date and S.Stay_Discharge_Date + 7
Qualify Row_Number() Over (Partition By S.PAC_Sty_ID Order By H.From_Date) = 1
) E On E.Member_ID = S.Member_ID And E.PAC_Sty_ID = S.PAC_Sty_ID
Where S.PAC_Sty_ID is not Null
AND S.STAY_DISCHARGE_DATE between '2017-01-01' and '2020-12-31'
AND S.LOB in ('CARE', 'DUAL')
AND S.ORPHAN_CLM_ID IS NULL
AND S.ORPHAN_CLM_LN IS NULL
Group By 1, 2, 3, 4, 5, 6
There should be 7 columns with the 7th column titled "Discharge_to" and values in the seventh column would be text (e.g., "Home without Care")
Posting here, since it's easier. Your query doesn't seem to be formatted correctly. It's of this form:
select S.Member_ID, ... ,
(
Select ... -- Sub-query trying to derive Discharge_To field
) E on E.Member_ID = S.Member_ID ...
where ...
A couple notes:
There is no FROM clause in the outer query yet you are trying to return S. fields
There is no S result set to join your E result to
The E result set is trying to be used as a sub-SELECT, but it also has an alias
Not knowing what your error message is, I'd suggest breaking apart the query into its sub-queries and running those individually to try to determine where the problem lies.

SQL Query to show order of work orders

First off sorry for the poor subject line.
EDIT: The Query here duplicates OrderNumbers I am needing the query to NOT duplicate OrderNumbers
EDIT: Shortened the question and provided a much cleaner question
I have a table that has a record of all of the work orders that have been performed. there are two types of orders. Installs and Trouble Calls. My query is to find all of the trouble calls that have taken place within 30 days of an install and match that trouble call (TC) to the proper Install (IN). So the Trouble Call date has to happen after the install but no more than 30 days after. Additionally if there are two installs and two trouble calls for the same account all within 30 days and they happen in order the results have to reflect that. The problem I am having is I am getting an Install order matching to two different Trouble Calls (TC) and a Trouble Call(TC) that is matching to two different Installs(IN)
In the example on SQL Fiddle pay close attention to the install order number 1234567810 and the Trouble Call order number 1234567890 and you will see the issue I am having.
http://sqlfiddle.com/#!3/811df/8
select b.accountnumber,
MAX(b.scheduleddate) as OriginalDate,
b.workordernumber as OriginalOrder,
b.jobtype as OriginalType,
MIN(a.scheduleddate) as NewDate,
a.workordernumber as NewOrder,
a.jobtype as NewType
from (
select workordernumber,accountnumber,jobtype,scheduleddate
from workorders
where jobtype = 'TC'
) a join
(
select workordernumber,accountnumber,jobtype,scheduleddate
from workorders
where jobtype = 'IN'
) b
on a.accountnumber = b.accountnumber
group by b.accountnumber,
b.scheduleddate,
b.workordernumber,
b.jobtype,
a.accountnumber,
a.scheduleddate,
a.workordernumber,
a.jobtype
having MIN(a.scheduleddate) > MAX(b.scheduleddate) and
DATEDIFF(day,MAX(b.scheduleddate),MIN(a.scheduleddate)) < 31
Example of what I am looking for the results to look like.
Thank you for any assistance you can provide in setting me on the correct path.
You were actually very close. I realized that what you really want is the MIN() TC date that is greater than each install date for that account number so long as they are 30 days or less apart.
So really you need to group by the install dates from your result set excluding WorkOrderNumbers still. Something like:
SELECT a.AccountNumber, MIN(a.scheduleddate) TCDate, b.scheduleddate INDate
FROM
(
SELECT WorkOrderNumber, ScheduledDate, JobType, AccountNumber
FROM workorders
WHERE JobType = 'TC'
) a
INNER JOIN
(
SELECT WorkOrderNumber, ScheduledDate, JobType, AccountNumber
FROM workorders
WHERE JobType = 'IN'
) b
ON a.AccountNumber = b.AccountNumber
WHERE b.ScheduledDate < a.ScheduledDate
AND DATEDIFF(DAY, b.ScheduledDate, a.ScheduledDate) <= 30
GROUP BY a.AccountNumber, b.AccountNumber, b.ScheduledDate
This takes care of the dates and AccountNumbers, but you still need the WorkOrderNumbers, so I joined the workorders table back twice, once for each type.
NOTE: I assume that each workorder has a unique date for each account number. So, if you have workorder 1 ('TC') for account 1 done on '1/1/2015' and you also have workorder 2 ('TC') for account 1 done on '1/1/2015' then I can't guarantee that you will have the correct WorkOrderNumber in your result set.
My final query looked like this:
SELECT
aggdata.AccountNumber, inst.workordernumber OriginalWorkOrderNumber, inst.JobType OriginalJobType, inst.ScheduledDate OriginalScheduledDate,
tc.WorkOrderNumber NewWorkOrderNumber, tc.JobType NewJobType, tc.ScheduledDate NewScheduledDate
FROM (
SELECT a.AccountNumber, MIN(a.scheduleddate) TCDate, b.scheduleddate INDate
FROM
(
SELECT WorkOrderNumber, ScheduledDate, JobType, AccountNumber
FROM workorders
WHERE JobType = 'TC'
) a
INNER JOIN
(
SELECT WorkOrderNumber, ScheduledDate, JobType, AccountNumber
FROM workorders
WHERE JobType = 'IN'
) b
ON a.AccountNumber = b.AccountNumber
WHERE b.ScheduledDate < a.ScheduledDate
AND DATEDIFF(DAY, b.ScheduledDate, a.ScheduledDate) <= 30
GROUP BY a.AccountNumber, b.AccountNumber, b.ScheduledDate
) aggdata
LEFT OUTER JOIN workorders tc
ON aggdata.TCDate = tc.ScheduledDate
AND aggdata.AccountNumber = tc.AccountNumber
AND tc.JobType = 'TC'
LEFT OUTER JOIN workorders inst
ON aggdata.INDate = inst.ScheduledDate
AND aggdata.AccountNumber = inst.AccountNumber
AND inst.JobType = 'IN'
select in1.accountnumber,
in1.scheduleddate as OriginalDate,
in1.workordernumber as OriginalOrder,
'IN' as OriginalType,
tc.scheduleddate as NewDate,
tc.workordernumber as NewOrder,
'TC' as NewType
from
workorders in1
out apply (Select min(in2.scheduleddate) as scheduleddate from workorders in2 Where in2.jobtype = 'IN' and in1.accountnumber=in2.accountnumber and in2.scheduleddate>in1.scheduleddate) ins
join workorders tc on tc.jobtype = 'TC' and tc.accountnumber=in1.accountnumber and tc.scheduleddate>in1.scheduleddate and (ins.scheduleddate is null or tc.scheduleddate<ins.scheduleddate) and DATEDIFF(day,in1.scheduleddate,tc.scheduleddate) < 31
Where in1.jobtype = 'IN'

SQL get number of hours on previous rows

I am working on a query that extracts information about a store opening and close time. This is the resultset:
RTL_LOC_ID TRANS_TYPCODE BEGIN_DATETIME
---------- ------------------------------ ---------------------------
2390 WORKSTATION_OPEN 14.10.01 09:53:43,121000000
2390 WORKSTATION_CLOSE 14.10.01 23:51:49,729000000
2390 WORKSTATION_OPEN 14.10.02 09:57:47,768000000
2390 WORKSTATION_CLOSE 14.10.02 23:47:00,120000000
2390 WORKSTATION_OPEN 14.10.03 09:47:38,949000000
2390 WORKSTATION_CLOSE 14.10.03 23:45:42,602000000
6 rows selected
This is the query:
SELECT RTL_LOC_ID,TRANS_TYPCODE, BEGIN_DATETIME
FROM TRN_TRANS
WHERE(trans_typcode = 'WORKSTATION_OPEN' OR trans_typcode='WORKSTATION_CLOSE')
AND BUSINESS_DATE BETWEEN '14.10.01 00:00:00' AND '14.10.03 00:00:00'
ORDER BY BUSINESS_DATE, BEGIN_DATETIME ASC;
So I need to calculate the number of hours between the opening and closing of the store and place that value into a new column. I would also like to put the result for the day in the same row instead of two separate lines for each day.
This answer assumes MySQL since the question was not tagged with Oracle to begin with. I'm leaving this answer here, since it might inspire someone with Oracle skills toward a solution...
Assuming a location always opens before it closes, a quick and dirty solution could look like this:
SELECT RTL_LOC_ID, DATE(BUSINESS_DATE),
MIN(BUSINESS_DATE) AS [OpenTime],
MAX(BUSINESS_DATE) AS [CloseTime]
FROM
TRN_TRANS
WHERE(trans_typcode = 'WORKSTATION_OPEN' OR trans_typcode='WORKSTATION_CLOSE')
AND BUSINESS_DATE BETWEEN '14.10.01 00:00:00' AND '14.10.03 00:00:00'
GROUP BY RTL_LOC_ID, DATE(BUSINESS_DATE)
ORDER BY DATE(BUSINESS_DATE)
Or if you want to be pedantic:
SELECT RTL_LOC_ID, DATE(BUSINESS_DATE),
MAX(CASE trans_typcode WHEN 'WORKSTATION_OPEN' THEN BUSINESS_DATE ELSE NULL END) AS [OpenTime],
MAX(CASE trans_typcode WHEN 'WORKSTATION_CLOSE' THEN BUSINESS_DATE ELSE NULL END) AS [CloseTime],
FROM
-- rest of query same as above --
Is this what you mean?
SELECT
TRN_TRANS.RTL_LOC_ID,
DATE_FORMAT(BEGIN_DATETIME ,'%Y-%m-%d') AS _date,
TIMEDIFF(closing_time.BEGIN_DATETIME , opening_time.BEGIN_DATETIME ) AS _hours
FROM TRN_TRANS
INNER JOIN
(
SELECT RTL_LOC_ID, BEGIN_DATETIME, DATE_FORMAT(BEGIN_DATETIME ,'%Y-%m-%d') as _date
FROM TRN_TRANS
WHERE TRANS_TYPCODE = 'WORKSTATION_OPEN'
) AS opening_time
ON
TRN_TRANS.RTL_LOC_ID = opening_time.RTL_LOC_ID
AND
DATE_FORMAT(TRN_TRANS.BEGIN_DATETIME ,'%Y-%m-%d') = opening_time._date
INNER JOIN
(
SELECT RTL_LOC_ID, BEGIN_DATETIME, DATE_FORMAT(BEGIN_DATETIME ,'%Y-%m-%d') as _date
FROM TRN_TRANS
WHERE TRANS_TYPCODE = 'WORKSTATION_CLOSE'
) AS closing_time
ON
TRN_TRANS.RTL_LOC_ID = closing_time.RTL_LOC_ID
AND
DATE_FORMAT(TRN_TRANS.BEGIN_DATETIME ,'%Y-%m-%d') = closing_time._date
GROUP BY TRN_TRANS.RTL_LOC_ID, _date, _hours

SQL Month comparison to declared variable

select
sc.locationid, --here to get a result
(
if month(date()) between 8 and 12 then #semTerm = 'S1'
else #semTerm = 'S2'
end if
)as #semTerm
from student_class sc
where #semTerm = sc.semester
;
In db2 student management system. Read only access. Desired outcome is If Jan thru June, S2 else if Aug thru Dec, S1. Trying to setup a variable based on the current date stamp where the month is segregated then assigned to a variable then compared against a column in student_class table.
Have tried case statements as well with no luck. Unable to declare #semTerm without error above select statement. Looked at where clause solution also. Am I out in left field? Seems simple but struggling with the syntax. Part of a larger statement with locationID as one column in student_class.
You can't really use an IF statement in a simple SELECT statement, you must use CASE:
select
sc.locationid, --here to get a result
case
when month(current date) between 8 and 12 then 'S1'
when month(current date) between 1 and 6 then 'S2'
else ''
end as semTerm
from
student_class sc
If you want to find only the students for the current semester, then you would want to move the CASE statement into the WHERE clause:
select
sc.locationid, --here to get a result
sc.semester,
...
from
student_class sc
where
sc.semester = case
when month(current date) between 8 and 12 then 'S1'
when month(current date) between 1 and 6 then 'S2'
end
A CASE expression is generally the way to implement conditional logic in a SELECT statement. However, it would be more efficient if you didn't have to recalculate it on every row, right?
One approach would be to "precalculate" it in a common table expression, and join to that as your selection criteria:
with v (semester) as
( values
case
when month(current date) > 7 then 'S1'
when month(current date) < 7 then 'S2'
else null
end
)
select
sc.locationid,
sc.semester,
...
from
student_class sc
join
v on sc.semester = v.semester;
OR
If you you find that this current semester value would be useful in many other places, another approach could be to create a 'global session variable' to hold the value. (except on z/OS)
create or replace variable
v_sememster char(2)
default
case
when month(current date) > 7
then 'S1'
when month(current date) < 7
then 'S2'
else null
end;
Then you can have a very simple query:
select
sc.locationid,
sc.semester,
...
from
student_class sc
where
sc.semester = v_semester;