SQL Server Select one column by aggregate but not another - sql

Not good with sql. Forgive me if the question isn't 100% clear. Here is my query
SELECT
MAX(PatientId),
[Date],
[Time],
CASE WHEN MAX(CAST(HealthScoreSkipped as INT)) = 1
THEN '--'
ELSE MAX(DailyHealthScore)
END DailyHealthScore,
ProtocolGroupName,
MAX(BloodPressure) BloodPressure,
MAX(SystolicAlert) SystolicAlert,
MAX(DiastolicAlert) DiastolicAlert,
MAX(BloodPressureSkipped) BloodPressureSkipped,
MAX(Pulse) Pulse,
MAX(PulseAlert) PulseAlert,
MAX(PulseSkipped) PulseSkipped,
MAX(BloodSugar) BloodSugar,
MAX(BloodSugarAlert) BloodSugarAlert,
MAX(BloodSugarSkipped) BloodSugarSkipped,
MAX(Steps) Steps,
MAX(StepsAlert) StepsAlert,
MAX(StepsSkipped) StepsSkipped,
MAX(O2) O2,
MAX(O2Alert) O2Alert,
MAX(O2Skipped) O2Skipped,
MAX(Weight) Weight,
MAX(WeightAlert) WeightAlert,
#BaselineWeight AS BaselineWeight,
MAX(WeightSkipped) WeightSkipped,
MAX(Temperature) Temperature,
MAX(TemperatureAlert) TemperatureAlert,
MAX(TemperatureUnit) TemperatureUnit,
MAX(TemperatureSkipped) TemperatureSkipped,
MAX(PEF) PEF,
MAX(PEFAlert) PEFAlert,
MAX(PEFSkipped) PEFSkipped,
MAX(FEV1) FEV1,
MAX(FEV1Alert) FEV1Alert,
MAX(FEV1Skipped) FEV1Skipped,
MAX(FEVRatio) FEVRatio,
MAX(FEVRatioAlert) FEVRatioAlert,
MAX(FEVRatioSkipped) FEVRatioSkipped,
#SpiroEnabled SpiroEnabled
FROM #bioAndScores
GROUP BY PatientId, Date, Time, ProtocolGroupName
The problem here is on the lines
MAX(Steps) Steps,
MAX(StepsAlert) StepsAlert
I want to select the max Steps but the stepalert value that goes with that row not the max of the stepAlert.

You can create a sub query in the select statement to get the steps alert that corresponds to your step.
something along the lines of the below (note that I'm not sure why you are grouping by patientId, if you are taking the max(patientId) if you do want to group by patient id, the where clause of the sub query should also match on patient Id
SELECT
MAX(bas.PatientId),
bas.[Date],
bas.[Time],
bas.ProtocolGroupName,
.
.
.
MAX(bas.Steps) Steps,
--sub query to get the StepsAlert that corresponds to max steps
(SELECT
StepsAlert
FROM
#bioAndScores subBas
WHERE
--This is the important part of finding the match for Max Steps
MAX(bas.Steps) = subBas.Steps AND
--commented out because the MAX(PatientId) was ambiguous
--bas.PatientId = subBas.PatientId AND
bas.[Date] = subBas.[Date] AND
bas.[Time] = subBas.[Time] AND
bas.ProtocolGroupName = subBas.ProtocolGroupName) as StepsAlert
FROM
#bioAndScores as bas
GROUP BY
--PatientId,
bas.Date,
bas.Time,
bas.ProtocolGroupName

Remove the MAX() function from StepAlerts and add StepAlerts to your GROUP BY clause.
MAX(Steps) AS Steps,
StepsAlert AS StepsAlert
And in your GROUP BY:
GROUP BY PatientId, Date, Time, ProtocolGroupName, StepAlerts

Just add StepsAlert column to the group by clause and remove the MAX aggregate function.
GROUP BY PatientId, Date, Time, ProtocolGroupName,StepsAlert
I would suggest you go through this to better understand about how group by works.

You can do this using apply() to select the set of values that correspond to the highest Steps at the earliest StepsAlert like so:
select
PatientId
, [Date]
, [Time]
, DailyHealthScore = case
when MAX(CAST(HealthScoreSkipped as int))= 1 then '--'
else MAX(DailyHealthScore)
end
, ProtocolGroupName
, BloodPressure = MAX(BloodPressure)
, SystolicAlert = MAX(SystolicAlert)
, DiastolicAlert = MAX(DiastolicAlert)
, BloodPressureSkipped= MAX(BloodPressureSkipped)
, Pulse = MAX(Pulse)
, PulseAlert = MAX(PulseAlert)
, PulseSkipped = MAX(PulseSkipped)
, BloodSugar = MAX(BloodSugar)
, BloodSugarAlert = MAX(BloodSugarAlert)
, BloodSugarSkipped = MAX(BloodSugarSkipped)
, Steps = x.Steps
, StepsAlert = x.StepsAlert
, StepsSkipped = MAX(StepsSkipped)
, O2 = MAX(O2)
, O2Alert = MAX(O2Alert)
, O2Skipped = MAX(O2Skipped)
, Weight = MAX(Weight)
, WeightAlert = MAX(WeightAlert)
, BaselineWeight = #BaselineWeight
, WeightSkipped = MAX(WeightSkipped)
, Temperature = MAX(Temperature)
, TemperatureAlert = MAX(TemperatureAlert)
, TemperatureUnit = MAX(TemperatureUnit)
, TemperatureSkipped = MAX(TemperatureSkipped)
, PEF = MAX(PEF)
, PEFAlert = MAX(PEFAlert)
, PEFSkipped = MAX(PEFSkipped)
, FEV1 = MAX(FEV1)
, FEV1Alert = MAX(FEV1Alert)
, FEV1Skipped = MAX(FEV1Skipped)
, FEVRatio = MAX(FEVRatio)
, FEVRatioAlert = MAX(FEVRatioAlert)
, FEVRatioSkipped = MAX(FEVRatioSkipped)
, SpiroEnabled = #SpiroEnabled
from #bioAndScores b
cross apply (
select top 1
i.Steps
, i.StepsAlert
from #bioAndScores i
where b.PatientId = i.PatientId
and b.[Date] = i.[Date]
and b.[Time] = i.[Time]
and b.ProtocolGroupName = i.ProtocolGroupName
order by i.Steps desc, i.StepsAlert asc
) x
group by
PatientId
, date
, time
, ProtocolGroupName

Related

Looking for the best way to return pass in a parameter to allow me to return a specific customer or all customers in SQL

I have the below query that could defenitely be optimized but I'm looking for the best way to add a parameter that allows me to return the same results and pass in a Parameter that would say if pass it in as "All" it would return all WO.BillTo records but if I passed in a value other than "All" it would compare that value to the WO.BillTo to only return records for that specific BillTo Customer.
Any help or suggestions would be greatly appreciated.
SELECT WO.WONo ,
WO.BillTo ,
WO.ShipTo ,
WO.ShipName ,
WO.ClosedDate ,
WOParts.PartNo ,
WOParts.Description ,
WOParts.ShipQty ,
WOParts.SellRate ,
Customer.Name
FROM WO,WOParts,Customer
WHERE (((
((WO.ClosedDate >= #startdate ) AND (WO.ClosedDate < #closedate ) )
AND (WO.Disposition = 2 ) )
AND (WO.WONo = WOParts.WONo ) )
AND (WO.BillTo = Customer.Number ) )
AND WOParts.TransferWONoTo =''
and Woparts.shipqty <> 0
order by wo.ShipTo
This is known as a "catch all" query. I would suggest using NULL rather than 'all', but the syntax would be the same. The OPTION (RECOMPILE) is there to stop poor query plan caching. Also I've "updated" you to 1992's ANSI-92 explicit JOIN syntax, as it has been around for around 30 years now:
SELECT W.WONo ,
W.BillTo ,
W.ShipTo ,
W.ShipName ,
W.ClosedDate ,
WP.PartNo ,
WP.Description ,
WP.ShipQty ,
WP.SellRate ,
C.Name
FROM dbo.WO W --Let's update to 1992!
JOIN dbo.WOParts WP ON W.WONo = WP.WONo
JOIN dbo.Customer C ON W.BillTo = C.Number
WHERE W.ClosedDate >= #startdate AND W.ClosedDate < #closedate
AND W.Disposition = 2
AND WP.TransferWONoTo =''
AND WP.shipqty <> 0
AND (WO.BillTo = #YourParameter OR #YourParameter IS NULL)
ORDER BY W.ShipTo
OPTION (RECOMPILE);

Convert Oracle SQL statement into SQL Server statement

A bookings project now requires the same data extract - but from an SQL Server database - instead of Oracle. Can anyone assist converting the following into SQL Server syntax?
SELECT *
FROM (
SELECT o.ot_outlet_code
,v.lab_site_code ot_outlet_code
,v.brand
,v.region
, bd.cd_day_date booking_date, dd.cd_day_date dining_date
, f.last_change_date, f.created_date
, f.modified_date, t15.ts_timeslot_desc
, t.TIME, s.session_type
, tbs.booking_status, f.ADDED_BY_USER
, bp.product, bs.booking_source
, f.SPECIAL_OFFER, f.SEATING_PREFERENCE
, f.Tables_guest_id, covers
, booking_occurrence, breakfast_flag
, row_number() OVER (PARTITION BY f.Tables_guest_id ORDER BY f.last_change_date DESC, f.last_change_time DESC) rank_latest_record
, f.title, f.emailoptout
, f.MOBILE_OPT_IN, f.HIGH_CHAIR_COVERS
, f.GUEST_TYPE, f.Booking_ID
FROM owbi.whs_fact_rest_booking f
, owbi.whs_dim_cal_date bd
, owbi.whs_dim_cal_date dd
, owbi.whs_dim_bat_booking_source bs
, owbi.whs_dim_time_of_day t
, owbi.whs_dim_bat_product bp
, owbi.whs_dim_15_timeslot t15
, owbi.whs_dim_bat_booking_status tbs
, owbi.whs_dim_bat_session s
, owbi.bat_restaurants_v v
WHERE f.whs_dim_outlet = v.outlet
AND f.whs_dim_booking_date = bd.dimension_Key
AND f.whs_dim_dining_date = dd.dimension_key
AND f.whs_dim_bat_session = s.dimension_key
AND f.whs_dim_bat_booking_status = tbs.dimension_key
AND f.whs_dim_bat_product = bp.dimension_Key
AND f.whs_dim_bat_booking_source = bs.dimension_key
AND f.whs_dim_booking_time = t.dimension_Key
AND f.whs_dim_dining_15_timeslot = t15.dimension_key
AND dd.ey_year_code in ('2018')
AND f.whs_dim_dining_date >= 20170303
)
WHERE rank_latest_record = 1
ORDER BY BOOKING_DATE DESC;
The derived table must have an alias. eg
SELECT *
FROM (
SELECT o.ot_outlet_code
,v.lab_site_code ot_outlet_code
,v.brand
,v.region
, bd.cd_day_date booking_date, dd.cd_day_date dining_date
, f.last_change_date, f.created_date
, f.modified_date, t15.ts_timeslot_desc
, t.TIME, s.session_type
, tbs.booking_status, f.ADDED_BY_USER
, bp.product, bs.booking_source
, f.SPECIAL_OFFER, f.SEATING_PREFERENCE
, f.Tables_guest_id, covers
, booking_occurrence, breakfast_flag
, row_number() OVER (PARTITION BY f.Tables_guest_id ORDER BY f.last_change_date DESC, f.last_change_time DESC) rank_latest_record
, f.title, f.emailoptout
, f.MOBILE_OPT_IN, f.HIGH_CHAIR_COVERS
, f.GUEST_TYPE, f.Booking_ID
FROM owbi.whs_fact_rest_booking f
, owbi.whs_dim_cal_date bd
, owbi.whs_dim_cal_date dd
, owbi.whs_dim_bat_booking_source bs
, owbi.whs_dim_time_of_day t
, owbi.whs_dim_bat_product bp
, owbi.whs_dim_15_timeslot t15
, owbi.whs_dim_bat_booking_status tbs
, owbi.whs_dim_bat_session s
, owbi.bat_restaurants_v v
WHERE f.whs_dim_outlet = v.outlet
AND f.whs_dim_booking_date = bd.dimension_Key
AND f.whs_dim_dining_date = dd.dimension_key
AND f.whs_dim_bat_session = s.dimension_key
AND f.whs_dim_bat_booking_status = tbs.dimension_key
AND f.whs_dim_bat_product = bp.dimension_Key
AND f.whs_dim_bat_booking_source = bs.dimension_key
AND f.whs_dim_booking_time = t.dimension_Key
AND f.whs_dim_dining_15_timeslot = t15.dimension_key
AND dd.ey_year_code in ('2018')
AND f.whs_dim_dining_date >= 20170303
) dt
WHERE rank_latest_record = 1
ORDER BY BOOKING_DATE DESC;
In SQL Server it's considered poor form not use ANSI-style JOINs, although it's perfectly legal for inner joins to write them as a cross-join with the join criteria in the WHERE clause.
And it's generally better to use CTEs instead of subqueries/inline views/derived tables in the FROM clause.

How to add a count/sum and group by in a CTE

Just a question on displaying a row on flight level and displaying a count on how many crew members on that flight.
I want to change the output so it will only display a single record at flight level and it will display two additional columns. One column (cabincrew) is the count of crew members that have the 'CREWTYPE' = 'F' and the other column (cockpitcrew) is the count of crew members that have the `'CREWTYPE' = 'C'.
So the query result should look like:
Flight DepartureDate DepartureAirport CREWBASE CockpitCrew CabinCrew
LS361 2016-05-19 BFS BFS 0 3
Can I have a little help tweaking the below query please:
WITH CTE AS (
SELECT cd.*, c.*, l.Carrier, l.FlightNumber, l.Suffix, l.ScheduledDepartureDate, l.ScheduledDepartureAirport
FROM
(SELECT *, ROW_NUMBER() OVER(PARTITION BY LegKey ORDER BY UpdateID DESC) AS RowNumber FROM Data.Crew) c
INNER JOIN
Data.CrewDetail cd
ON c.UpdateID = cd.CrewUpdateID
AND cd.IsPassive = 0
AND RowNumber = 1
INNER JOIN
Data.Leg l
ON c.LegKey = l.LegKey
)
SELECT
sac.Airline + CAST(sac.FlightNumber AS VARCHAR) + sac.Suffix AS Flight
, sac.DepartureDate
, sac.DepartureAirport
, sac.CREWBASE
, sac.CREWTYPE
, sac.EMPNO
, sac.FIRSTNAME
, sac.LASTNAME
, sac.SEX
FROM
Staging.SabreAssignedCrew sac
LEFT JOIN CTE cte
ON sac.Airline + CAST(sac.FlightNumber AS VARCHAR) + sac.Suffix = cte.Carrier + CAST(cte.FlightNumber AS VARCHAR) + cte.Suffix
AND sac.DepartureDate = cte.ScheduledDepartureDate
PLEASE TRY THIS.
SELECT Flight,
DepartureDate,
DepartureAirport,
CREWBASE,
SUM(CASE WHEN CREWTYPE = 'F' THEN 1 ELSE 0 END) AS CabinCrew ,
SUM(CASE WHEN CREWTYPE = 'C' THEN 1 ELSE 0 END) AS CockpitCrew
FROM #Table
GROUP BY Flight, DepartureDate, DepartureAirport, CREWBASE
Please Try This:
select Flight, DepartureDate, DepartureAirport,CREWBASE,
count(case when CREWTYPE='F' then 1 end ) as CabinCrew,count(case when CREWTYPE='C' then 1 end ) as CockpitCrew
from Staging.SabreAssignedCrew
group by Flight, DepartureDate, DepartureAirport,CREWBASE

Use of MAX function in SQL query to filter data

The code below joins two tables and I need to extract only the latest date per account, though it holds multiple accounts and history records. I wanted to use the MAX function, but not sure how to incorporate it for this case. I am using My SQL server.
Appreciate any help !
select
PROP.FileName,PROP.InsName, PROP.Status,
PROP.FileTime, PROP.SubmissionNo, PROP.PolNo,
PROP.EffDate,PROP.ExpDate, PROP.Region,
PROP.Underwriter, PROP_DATA.Data , PROP_DATA.Label
from
Property.dbo.PROP
inner join
Property.dbo.PROP_DATA on Property.dbo.PROP.FileID = Actuarial.dbo.PROP_DATA.FileID
where
(PROP_DATA.Label in ('Occupancy' , 'OccupancyTIV'))
and (PROP.EffDate >= '42278' and PROP.EffDate <= '42643')
and (PROP.Status = 'Bound')
and (Prop.FileTime = Max(Prop.FileTime))
order by
PROP.EffDate DESC
Assuming your DBMS supports windowing functions and the with clause, a max windowing function would work:
with all_data as (
select
PROP.FileName,PROP.InsName, PROP.Status,
PROP.FileTime, PROP.SubmissionNo, PROP.PolNo,
PROP.EffDate,PROP.ExpDate, PROP.Region,
PROP.Underwriter, PROP_DATA.Data , PROP_DATA.Label,
max (PROP.EffDate) over (partition by PROP.PolNo) as max_date
from Actuarial.dbo.PROP
inner join Actuarial.dbo.PROP_DATA
on Actuarial.dbo.PROP.FileID = Actuarial.dbo.PROP_DATA.FileID
where (PROP_DATA.Label in ('Occupancy' , 'OccupancyTIV'))
and (PROP.EffDate >= '42278' and PROP.EffDate <= '42643')
and (PROP.Status = 'Bound')
and (Prop.FileTime = Max(Prop.FileTime))
)
select
FileName, InsName, Status, FileTime, SubmissionNo,
PolNo, EffDate, ExpDate, Region, UnderWriter, Data, Label
from all_data
where EffDate = max_date
ORDER BY EffDate DESC
This also presupposes than any given account would not have two records on the same EffDate. If that's the case, and there is no other objective means to determine the latest account, you could also use row_numer to pick a somewhat arbitrary record in the case of a tie.
Using straight SQL, you can use a self-join in a subquery in your where clause to eliminate values smaller than the max, or smaller than the top n largest, and so on. Just set the number in <= 1 to the number of top values you want per group.
Something like the following might do the trick, for example:
select
p.FileName
, p.InsName
, p.Status
, p.FileTime
, p.SubmissionNo
, p.PolNo
, p.EffDate
, p.ExpDate
, p.Region
, p.Underwriter
, pd.Data
, pd.Label
from Actuarial.dbo.PROP p
inner join Actuarial.dbo.PROP_DATA pd
on p.FileID = pd.FileID
where (
select count(*)
from Actuarial.dbo.PROP p2
where p2.FileID = p.FileID
and p2.EffDate <= p.EffDate
) <= 1
and (
pd.Label in ('Occupancy' , 'OccupancyTIV')
and p.Status = 'Bound'
)
ORDER BY p.EffDate DESC
Have a look at this stackoverflow question for a full working example.
Not tested
with temp1 as
(
select foo
from bar
whre xy = MAX(xy)
)
select PROP.FileName,PROP.InsName, PROP.Status,
PROP.FileTime, PROP.SubmissionNo, PROP.PolNo,
PROP.EffDate,PROP.ExpDate, PROP.Region,
PROP.Underwriter, PROP_DATA.Data , PROP_DATA.Label
from Actuarial.dbo.PROP
inner join temp1 t
on Actuarial.dbo.PROP.FileID = t.dbo.PROP_DATA.FileID
ORDER BY PROP.EffDate DESC

Joining two SELECT statements using Outer Join with multiple alias

I have a complicated select statement that when it is executed, I give it a date or date range I want and the output comes out. The problem is I don't know how to join the same SQL statement with the first Statement having 1 date range and the second statement having another data range. Example below:
When I execute the select statement, I choose for the Month of November:
EMPLID NAME Current_Gross_Hours(November)
When I execute the select statement again, I choose from January to November:
EMPLID NAME Year_To_Date_Hours(January - November)
What I want:
EMPLID NAME Current_Gross_Hours(November) Year_To_Date_Hours(January - November)
The SQL Select statement runs correctly if execute by themselves. But I don't know how to join them.
Here is the SQL code that I want to write, but I don't know how to write the SQL statement correctly. Any help or direction is greatly appreciated.
(SELECT DISTINCT
SUM("PSA"."AL_HOURS") AS "Current Gross Hours", "PSJ"."EMPLID","PSP"."NAME"
FROM
"PS_JOB" "PSJ", "PS_EMPLOYMENT" "PSE", "PS_PERSONAL_DATA" "PSP", "PS_AL_CHK_HRS_ERN" "PSA"
WHERE
((("PSA"."CHECK_DT" = TO_DATE('2011-11-01', 'YYYY-MM-DD')) AND
("PSJ"."PAYGROUP" = 'SK2') AND
(("PSJ"."EFFSEQ"= (
SELECT MAX("INNERALIAS"."EFFSEQ")
FROM "PS_JOB" INNERALIAS
WHERE "INNERALIAS"."EMPL_RCD_NBR" = "PSJ"."EMPL_RCD_NBR"
AND "INNERALIAS"."EMPLID" = "PSJ"."EMPLID"
AND "INNERALIAS"."EFFDT" = "PSJ"."EFFDT")
AND
"PSJ"."EFFDT" = (
SELECT MAX("INNERALIAS"."EFFDT")
FROM "PS_JOB" INNERALIAS
WHERE "INNERALIAS"."EMPL_RCD_NBR" = "PSJ"."EMPL_RCD_NBR"
AND "INNERALIAS"."EMPLID" = "PSJ"."EMPLID"
AND "INNERALIAS"."EFFDT" <= SYSDATE)))))
AND
("PSJ"."EMPLID" = "PSE"."EMPLID" ) AND ("PSJ"."EMPLID" = "PSP"."EMPLID" ) AND ("PSJ"."FILE_NBR" = "PSA"."FILE_NBR" ) AND ("PSJ"."PAYGROUP" = "PSA"."PAYGROUP" ) AND ("PSE"."EMPLID" = "PSP"."EMPLID" )
GROUP BY
"PSJ"."EMPLID", "PSP"."NAME"
) AS "Q1"
LEFT JOIN
(SELECT DISTINCT
SUM("PSA"."AL_HOURS") AS "YEAR_TO_DATE Gross Hours", "PSJ"."EMPLID"
FROM
"PS_JOB" "PSJ", "PS_EMPLOYMENT" "PSE", "PS_PERSONAL_DATA" "PSP", "PS_AL_CHK_HRS_ERN" "PSA"
WHERE
((("PSA"."CHECK_DT" BETWEEN TO_DATE('2011-01-01', 'YYYY-MM-DD') AND TO_DATE('2011-11-01', 'YYYY-MM-DD')) AND
("PSJ"."PAYGROUP" = 'SK2') AND
(("PSJ"."EFFSEQ"= (
SELECT MAX("INNERALIAS"."EFFSEQ")
FROM "PS_JOB" INNERALIAS
WHERE "INNERALIAS"."EMPL_RCD_NBR" = "PSJ"."EMPL_RCD_NBR"
AND "INNERALIAS"."EMPLID" = "PSJ"."EMPLID"
AND "INNERALIAS"."EFFDT" = "PSJ"."EFFDT")
AND
"PSJ"."EFFDT" = (
SELECT MAX("INNERALIAS"."EFFDT")
FROM "PS_JOB" INNERALIAS
WHERE "INNERALIAS"."EMPL_RCD_NBR" = "PSJ"."EMPL_RCD_NBR"
AND "INNERALIAS"."EMPLID" = "PSJ"."EMPLID"
AND "INNERALIAS"."EFFDT" <= SYSDATE)))))
AND
("PSJ"."EMPLID" = "PSE"."EMPLID" ) AND ("PSJ"."EMPLID" = "PSP"."EMPLID" ) AND ("PSJ"."FILE_NBR" = "PSA"."FILE_NBR" ) AND ("PSJ"."PAYGROUP" = "PSA"."PAYGROUP" ) AND ("PSE"."EMPLID" = "PSP"."EMPLID" )
GROUP BY
"PSJ"."EMPLID"
) AS "Q2"
ON "Q1"."EMPLID"="Q2"."EMPLID"
ORDER BY
"Q1"."NAME"
You are missing a SELECT ... FROM at the start. The AS keyword only works when creating column aliases, not query block aliases. Quotation marks are only necessary for case-sensitive column names - they don't look incorrect in your example but they frequently cause mistakes.
SELECT Q1.NAME, ...
FROM
(
SELECT ...
) Q1
JOIN
(
SELECT ...
) Q2
ON Q1.EMPLID=Q2.EMPLID
ORDER BY Q1.NAME