Difference Max and Min from Different Dates - sql

I'm going to try to explain this the best I can.
The code below does the following:
Finds a service address from the ServiceLocation table.
Finds a service type (electric or water).
Finds how many days in the past to pull data.
Once it has this, it calculates the "daily usage" by subtracting the max meter read for a day from the minimum meter read for a day.
(MAX(mr.Reading) - MIN(mr.Reading)) AS 'DaytimeUsage'
However, what I'm missing is the max reading from the day prior and the minimum reading from the current day. Mathematically, this should look something like this:
MAX(PriorDayReading) - MIN(ReadDateReading)
Essentially, if it goes back 5 days it should kick out a table that reads as follows:
Service Location | Read Date | Usage |
123 Main St | 4/20/15 | 12 |
123 Main St | 4/19/15 | 8 |
123 Main St | 4/18/15 | 6 |
123 Main St | 4/17/15 | 10 |
123 Main St | 4/16/15 | 11 |
Where "Usage" is the 'DaytimeUsage' + usage that I'm missing (and the question above). For example, 4/18/15 would be the 'DaytimeUsage' in the query below PLUS the the difference between the MAX read from 4/17/15 and the MIN read from 4/18/15.
I'm not sure how to accomplish this or if it is possible.
SELECT
A.ServiceAddress AS 'Service Address',
convert(VARCHAR(10),A.ReadDate,101) AS 'Date',
SUM(A.[DaytimeUsage]) AS 'Usage'
FROM
(
SELECT
sl.location_addr AS 'ServiceAddress',
convert(VARCHAR(10),mr.read_date,101) AS 'ReadDate',
(MAX(mr.Reading) - MIN(mr.Reading)) AS 'DaytimeUsage'
FROM
DimServiceLocation AS sl
INNER JOIN FactBill AS fb ON fb.ServiceLocationKey = sl.ServiceLocationKey
INNER JOIN FactMeterRead as mr ON mr.ServiceLocationKey = sl.ServiceLocationKey
INNER JOIN DimCustomer AS c ON c.CustomerKey = fb.CustomerKey
WHERE
c.class_name = 'Tenant'
AND sl.ServiceLocationKey = #ServiceLocation
AND mr.meter_type = #ServiceType
GROUP BY
sl.location_addr,
convert(VARCHAR(10),
mr.read_date,101)
) A
WHERE A.ReadDate >= GETDATE()-#Days
GROUP BY A.ServiceAddress, convert(VARCHAR(10),A.ReadDate,101)
ORDER BY convert(VARCHAR(10),A.ReadDate,101) DESC

It seems like you could solve this by just calculating the difference between the MAX of yesterday & today, however this is how I would approach it. Join to the same table again for the previous day relative to any given day, and select the Max/Min for that too within your inner query. Also if you place the date in the inner query where clause the data set you return will be quicker & smaller.
SELECT
A.ServiceAddress AS 'Service Address',
convert(VARCHAR(10),A.ReadDate,101) AS 'Date',
SUM(A.[TodayMax]) - SUM(A.[TodayMin]) AS 'Usage',
SUM(A.[TodayMax]) - SUM(A.[YesterdayMax]) AS 'Usage with extra bit you want'
FROM
(
SELECT
sl.location_addr AS 'ServiceAddress',
convert(VARCHAR(10),mr.read_date,101) AS 'ReadDate',
MAX(mrT.Reading) AS 'TodayMax',
MIN(mrT.Reading) AS 'TodayMin',
MAX(mrY.Reading) AS 'YesterdayMax',
MIN(mrY.Reading) AS 'YesterdayMin',
FROM
DimServiceLocation AS sl
INNER JOIN FactBill AS fb ON fb.ServiceLocationKey = sl.ServiceLocationKey
INNER JOIN FactMeterRead as mrT ON mrT.ServiceLocationKey = sl.ServiceLocationKey
INNER JOIN FactMeterRead as mrY ON mrY.ServiceLocationKey = s1.ServiceLocationKey
AND mrY.read_date = mrT.read_date -1)
INNER JOIN DimCustomer AS c ON c.CustomerKey = fb.CustomerKey
WHERE
c.class_name = 'Tenant'
AND sl.ServiceLocationKey = #ServiceLocation
AND mr.meter_type = #ServiceType
AND convert(VARCHAR(10), mrT.read_date,101) >= GETDATE()-#Days
GROUP BY
sl.location_addr,
convert(VARCHAR(10),
mr.read_date,101)
) A
GROUP BY A.ServiceAddress, convert(VARCHAR(10),A.ReadDate,101)
ORDER BY convert(VARCHAR(10),A.ReadDate,101) DESC

You can use the APPLY operator if you are above sql server 2005. Here is a link to the documentation. https://technet.microsoft.com/en-us/library/ms175156(v=sql.105).aspx The APPLY operation comes in two forms OUTER APPLY AND CROSS APPLY - OUTER works like a left join and CROSS works like an inner join. They let you run a query once for each row returned. I setup my own sample of what you were trying to do, here it is and I hope it helps.
http://sqlfiddle.com/#!6/fdb3f/1
CREATE TABLE SequencedValues (
Location varchar(50) NOT NULL,
CalendarDate datetime NOT NULL,
Reading int
)
INSERT INTO SequencedValues (
Location,
CalendarDate,
Reading
)
SELECT
'Address1',
'4/20/2015',
10
UNION SELECT
'Address1',
'4/19/2015',
9
UNION SELECT
'Address1',
'4/19/2015',
20
UNION SELECT
'Address1',
'4/19/2015',
25
UNION SELECT
'Address1',
'4/18/2015',
8
UNION SELECT
'Address1',
'4/17/2015',
7
UNION SELECT
'Address2',
'4/20/2015',
100
UNION SELECT
'Address2',
'4/20/2015',
111
UNION SELECT
'Address2',
'4/19/2015',
50
UNION SELECT
'Address2',
'4/19/2015',
65
SELECT DISTINCT
sv.Location,
sv.CalendarDate,
sv_dayof.MINDayOfReading,
sv_daybefore.MAXDayBeforeReading
FROM SequencedValues sv
OUTER APPLY (
SELECT MIN(sv_dayof_inside.Reading) AS MINDayOfReading
FROM SequencedValues sv_dayof_inside
WHERE sv.Location = sv_dayof_inside.Location
AND sv.CalendarDate = sv_dayof_inside.CalendarDate
) sv_dayof
OUTER APPLY (
SELECT MAX(sv_daybefore_max.Reading) AS MAXDayBeforeReading
FROM SequencedValues sv_daybefore_max
WHERE sv.Location = sv_daybefore_max.Location
AND sv_daybefore_max.CalendarDate IN (
SELECT TOP 1 sv_daybefore_inside.CalendarDate
FROM SequencedValues sv_daybefore_inside
WHERE sv.Location = sv_daybefore_inside.Location
AND sv.CalendarDate > sv_daybefore_inside.CalendarDate
ORDER BY sv_daybefore_inside.CalendarDate DESC
)
) sv_daybefore
ORDER BY
sv.Location,
sv.CalendarDate DESC

I'm not sure I full understood your db structure but I may have a solution so feel free to edit my answer to adapt or correct any mistake.
The idea is to use two aliases for the table FactMeterRead. mrY (Y as yesterday) and mrT (T as Today). And differentiate them with a read_date restriction.
However I didn't understand enough your tables to write a fully functional query. I hope you will get the idea anyway with this example.
SELECT
sl.location_addr AS 'ServiceAddress',
convert(VARCHAR(10),mrT.read_date,101) AS 'ReadDate',
(MAX(mrY.Reading) - MIN(mrT.Reading)) AS 'DaytimeUsage'
FROM
DimServiceLocation AS sl
INNER JOIN FactMeterRead as mrY ON mrY.ServiceLocationKey = sl.ServiceLocationKey
INNER JOIN FactMeterRead as mrT ON mrT.ServiceLocationKey = sl.ServiceLocationKey
WHERE mrY.read_date=DATE_SUB(mrT.read_date,1 DAY)

Related

Select highest value based off of a different column

I am trying to get the highest value based off of another column.
SELECT DISTINCT
AppDetailVehicleValuation.AppID,
VehicleValuationOption.Description,
MAX (VehicleValuationOptionValueType.Value)
FROM
AppDetailVehicleValuation
INNER JOIN VehicleValuationOption
ON AppDetailVehicleValuation.ValuationID = VehicleValuationOption.ValuationID
INNER JOIN VehicleValuationOptionValueType
ON VehicleValuationOption.ValuationOptionID = VehicleValuationOptionValueType.ValuationOptionID
WHERE
(VehicleValuationOption.IsSelected LIKE '1')
AND (VehicleValuationOption.IsSystemOption LIKE '1')
What I have is this
AppID | Description | Value
999 Beats Audio 425.00
999 Beats Audio 475.00
999 Power Str. 600.00
999 Power Str. 750.00
this is what I need
AppID | Description | Value
999 Beats Audio 475.00
999 Power Str. | 750.00
You are just missing a GROUP BY clause in your query:
SELECT
AppDetailVehicleValuation.AppID,
VehicleValuationOption.Description,
MAX (VehicleValuationOptionValueType.Value)
FROM
AppDetailVehicleValuation
INNER JOIN VehicleValuationOption
ON AppDetailVehicleValuation.ValuationID = VehicleValuationOption.ValuationID
INNER JOIN VehicleValuationOptionValueType
ON VehicleValuationOption.ValuationOptionID = VehicleValuationOptionValueType.ValuationOptionID
WHERE
(VehicleValuationOption.IsSelected LIKE '1')
AND (VehicleValuationOption.IsSystemOption LIKE '1')
GROUP BY AppDetailVehicleValuation.AppID, VehicleValuationOption.Description
You can simply do this:
SELECT
t.AppId,
t.Description,
max(t.Value)
FROM mytable t
GROUP BY t.description, t.AppId
This is too long for a comment.
Glad you found an answer that works with the GROUP BY. I would suggest you start using aliases in your queries. It can quickly and easily turn a wall of text into something fairly easy to see what is going on. You might end with something along these lines.
SELECT advv.AppID
, vvo.Description
, MaxValue = MAX(vvot.Value)
FROM AppDetailVehicleValuation advv
INNER JOIN VehicleValuationOption vvo ON advv.ValuationID = vvo.ValuationID
INNER JOIN VehicleValuationOptionValueType vvot ON vvo.ValuationOptionID = vvot.ValuationOptionID
WHERE vvo.IsSelected = '1'
AND vvo.IsSystemOption = '1'
group by advv.AppID
, vvo.Description

Select Latest or most recent date in SQL query

I am running a query in SQL on our EHR/EMR database. I am primarily looking at an assessment that is done by a nurse during each patient encounter/visit and looking to return an answer for the most recent assessment date along with some other info. I have the query created and all the data is coming over, however, it is returning all assessment dates and the answers instead of just the latest date and answer. I'll attach the full code below.
SELECT DISTINCT
MAX(PTA.ASSESSMENT_DATE) AS Max_Date,
SAQ.QUESTION_TEXT, SAA.ANSWER_TEXT, dbo.PT_BASIC.PATIENT_CODE,
dbo.PT_BASIC.NAME_FULL
FROM
dbo.PTC_ASSESSMENT_ANSWER AS PAA
INNER JOIN
dbo.PTC_ASSESSMENT AS PTA ON PTA.ASSESSMENT_ID = PAA.ASSESSMENT_ID
AND PTA.PATIENT_ID = PAA.PATIENT_ID
INNER JOIN
dbo.SYS_ASSESSMENT_POINTER AS SAP ON SAP.POINTER_ID = PAA.POINTER_ID
INNER JOIN
dbo.SYS_ASSESSMENT_QUESTION AS SAQ ON SAQ.QUESTION_ID = SAP.QUESTION_ID
INNER JOIN
dbo.SYS_ASSESSMENT_ANSWER AS SAA ON SAA.ANSWER_ID = SAP.ANSWER_ID
INNER JOIN
dbo.PT_BASIC ON PTA.PATIENT_ID = dbo.PT_BASIC.PATIENT_ID
WHERE
(PTA.ASSESSMENT_DATE BETWEEN CONVERT(DATETIME, '2017-09-05 00:00:00', 102)
AND CONVERT(DATETIME, '2017-10-12 00:00:00', 102))
GROUP BY
dbo.PT_BASIC.PATIENT_CODE, dbo.PT_BASIC.NAME_FULL, SAQ.QUESTION_TEXT,
SAA.ANSWER_TEXT
HAVING
(SAA.ANSWER_TEXT LIKE '%LEVEL % -%')
The current output would be something similar to this:
9/5/2017 PATIENT ABC Answer1
9/6/2017 PATIENT ABC Answer2
9/7/2017 PATIENT ABC Answer3
9/6/2017 PATIENT XYZ Answer4
What I am expecting is:
9/7/2017 PATIENT ABC Answer3
9/6/2017 PATIENT XYZ Answer4
If your version of SQL Server supports it, using ROW_NUMBER() OVER() is an efficient and simple method for arriving at "latest" (or "earliest") rows from a single table. However as we know so little about your data model it isn't easy to guess how to reduce the rows to just the "lastest answer" which probably requires a more complex subquery. However you can still use ROW_NUMBER() OVER() on that subquery. I suspect that the nature of questions and answers is that the table aliases SAP, SAQ, SAA may all need to be involved in this subquery.
Note that instead of directly joining PTA this is now a subquery and the join condition to the outer query requires that RN=1 which is the row with the "latest" date.
SELECT
MAX(PTA.ASSESSMENT_DATE) AS Max_Date
, SAQ.QUESTION_TEXT
, SAA.ANSWER_TEXT
, dbo.PT_BASIC.PATIENT_CODE
, dbo.PT_BASIC.NAME_FULL
FROM dbo.PTC_ASSESSMENT_ANSWER AS PAA
INNER JOIN (
SELECT
*
, ROW_NUMBER() OVER (PARTITION BY PATIENT_ID
ORDER BY ASSESSMENT_DATE DESC) AS RN
FROM dbo.PTC_ASSESSMENT
WHERE ASSESSMENT_DATE BETWEEN '20170905' AND '20171012'
) AS PTA ON PTA.ASSESSMENT_ID = PAA.ASSESSMENT_ID
AND PTA.PATIENT_ID = PAA.PATIENT_ID
AND PTA.RN = 1
INNER JOIN dbo.SYS_ASSESSMENT_POINTER AS SAP ON SAP.POINTER_ID = PAA.POINTER_ID
INNER JOIN dbo.SYS_ASSESSMENT_QUESTION AS SAQ ON SAQ.QUESTION_ID = SAP.QUESTION_ID
INNER JOIN dbo.SYS_ASSESSMENT_ANSWER AS SAA ON SAA.ANSWER_ID = SAP.ANSWER_ID
INNER JOIN dbo.PT_BASIC ON PTA.PATIENT_ID = dbo.PT_BASIC.PATIENT_ID
WHERE SAA.ANSWER_TEXT LIKE '%LEVEL % -%'
GROUP BY
dbo.PT_BASIC.PATIENT_CODE
, dbo.PT_BASIC.NAME_FULL
, SAQ.QUESTION_TEXT
, SAA.ANSWER_TEXT
select distinct is not required on this query (or any similar query using GROUP BY)
yyymmdd is the safest date literal in SQL Server, you don't need the converts using style 102
your having clause should be moved to a where clause as it does not evaluate any aggregated value
Cross apply allows you to use a correlated query and chive the top most n records ordered by date desc for each patient assessment. (after review maybe you just need patient?)
Perhaps just change:
INNER JOIN
dbo.PTC_ASSESSMENT AS PTA ON PTA.ASSESSMENT_ID = PAA.ASSESSMENT_ID
AND PTA.PATIENT_ID = PAA.PATIENT_ID
TO:
CROSS APPLY (SELECT TOP 1 *
FROM dbo.PTC_ASSESSMENT PTA2
WHERE PTA2.ASSESSMENT_ID = PAA.ASSESSMENT_ID
/*AND PTA2.PATIENT_ID = PAA.PATIENT_ID*/
ORDER BY PTA2.Assessment_date desc) PTA
GIVING YOU: (I left the /AND PTA2.PATIENT_ID = PAA.PATIENT_ID/ --I think you can omit this. I left the */ in place but it's not needed)
SELECT MAX(PTA.ASSESSMENT_DATE) AS Max_Date
, SAQ.QUESTION_TEXT
, SAA.ANSWER_TEXT
, dbo.PT_BASIC.PATIENT_CODE
, dbo.PT_BASIC.NAME_FULL
FROM dbo.PTC_ASSESSMENT_ANSWER AS PAA
CROSS APPLY (SELECT TOP 1 *
FROM dbo.PTC_ASSESSMENT PTA2
WHERE PTA2.ASSESSMENT_ID = PAA.ASSESSMENT_ID --I think you can omit this.
/*AND PTA2.PATIENT_ID = PAA.PATIENT_ID*/
ORDER BY PTA2.Assessment_date desc) PTA
INNER JOIN dbo.SYS_ASSESSMENT_POINTER AS SAP
ON SAP.POINTER_ID = PAA.POINTER_ID
INNER JOIN dbo.SYS_ASSESSMENT_QUESTION AS SAQ
ON SAQ.QUESTION_ID = SAP.QUESTION_ID
INNER JOIN dbo.SYS_ASSESSMENT_ANSWER AS SAA
ON SAA.ANSWER_ID = SAP.ANSWER_ID
INNER JOIN dbo.PT_BASIC
ON PTA.PATIENT_ID = dbo.PT_BASIC.PATIENT_ID
WHERE (PTA.ASSESSMENT_DATE BETWEEN CONVERT(DATETIME, '2017-09-05 00:00:00', 102) AND CONVERT(DATETIME, '2017-10-12 00:00:00', 102))
GROUP BY dbo.PT_BASIC.PATIENT_CODE
, dbo.PT_BASIC.NAME_FULL
, SAQ.QUESTION_TEXT
, SAA.ANSWER_TEXT
HAVING (SAA.ANSWER_TEXT LIKE '%LEVEL % -%')
It appears you're not concerned about patients w/o assessments as all your joins are inner or we could use OUTER APPPLY to be sure to keep all answers regardless if an assessment has been provided.
Alternatively you could use a row_number() logic ( Tab Alleman's link has this covered) and a cte; but if cross apply is available might as well use it here.
Please include order by PTA.ASSESSMENT_DATE DESC to see the latest records at the top.

SQL Query including pivot

I have done a query which include the left outer join and the pivot.
However I keep getting a bugs saying incorrect column.
SELECT * FROM
(select Max(datetimestamp)as datetimestamp, currentSet, tGroup_id from tPhos_Line_Operator
group by currentSet, tGroup_id)T
LEFT OUTER JOIN
(SELECT PO.tGroup_id AS G_ID, PO.CurrentSet AS cr,gP.tTest_id AS Header,convert(float,Po.Results) as Results from tPhos_Line_Operator PO
inner join tPhos_Line_Parameter pp
on PO.tPhos_Line_Parameter_id = PP.id
INNER JOIN tGroup_Parameter GP
on pp.tGroup_Parameter_id = gp.id
where PP.tPhosline_id=134)P
on T.tGroup_id = P.G_ID
AND T.CurrentSet = p.cr
PIVOT ( MAX(p.Results) For Header IN ([4],[23],[24])) AS pvt
Anyone know how to get the DateTimeStamp and the pivot record?
Which mean i will only have 4 columns in this case.
Currently i need to select * from.
I'm sorry still a junior in query.
Thanks in advance.
sample data could go here:
sample of expected result:
dateTime | currentset | tGroup_id | G_ID | cr | 4 | 23 | 24 |
2015-03-11 07:00:24.313 1 69 69 1 8.36 10 14.4
2015-03-12 00:31:58.257 2 69 69 2 9.12 8 14.4
I am making a guess. It appears that you want to "pivot" some results so you get to see these side by side instead of across multiple rows.
While PIVOT has been added into many SQL implementations, it is not the only way to achieve pivoted data nor is it always the best or easiest way to do it. Here is an old fashioned "pivot" that uses a set of case expressions and 'GROUP BY':
SELECT
PO.tGroup_id AS G_ID
, PO.CurrentSet AS cr
, MAX( datetimestamp ) AS datetimestamp
, MAX( CASE WHEN gP.tTest_id = 4 THEN CONVERT(float, Po.Results) END ) AS Results4
, MAX( CASE WHEN gP.tTest_id = 23 THEN CONVERT(float, Po.Results) END ) AS Results23
, MAX( CASE WHEN gP.tTest_id = 24 THEN CONVERT(float, Po.Results) END ) AS Results24
FROM tPhos_Line_Operator PO
INNER JOIN tPhos_Line_Parameter pp ON PO.tPhos_Line_Parameter_id = PP.id
INNER JOIN tGroup_Parameter GP ON pp.tGroup_Parameter_id = gp.id
WHERE PP.tPhosline_id = 134
GROUP BY
PO.currentSet
, PO.tGroup_id
Because you haven't supplied sample data I don't know the details but hopefully you can bend this to suit your data.
This is an alternative approach using the PIVOT operator but this also relies on using MAX() OVER(). One complication for using the PIVOT operator here is that you require a maximum datetime value as well as pivoted rows which is complex using the inbuilt pivot operator. I believe that complexity can be overcome by the MaxDateTime column seen below:
SELECT
MaxDateTime , CR, G_ID, [4], [23], [24]
FROM (
SELECT
PO.tGroup_id AS G_ID
, PO.CurrentSet AS cr
, gP.tTest_id AS Header
, MAX( PO.datetimestamp ) OVER (PARTITION BY PO.tGroup_id, PO.CurrentSet, gP.tTest_id) AS MaxDateTime
, CONVERT( float, Po.Results ) AS Results
FROM tPhos_Line_Operator PO
INNER JOIN tPhos_Line_Parameter pp ON PO.tPhos_Line_Parameter_id = PP.id
INNER JOIN tGroup_Parameter GP ON pp.tGroup_Parameter_id = gp.id
WHERE PP.tPhosline_id = 134
) AS sourve_tbl
PIVOT (MAX( Results ) FOR Header IN ([4], [23], [24])
) AS pvt_tbl
;
Yes your existing query is wrong.
I hv tried to correct it.
;With CTE as
(
select Max(datetimestamp)as datetimestamp, currentSet, tGroup_id
from tPhos_Line_Operator
group by currentSet, tGroup_id
)
Select * from
( SELECT PO.tGroup_id AS G_ID, PO.CurrentSet AS cr,gP.tTest_id AS Header
,convert(float,Po.Results) as Results
,T.*
from tPhos_Line_Operator PO
inner join tPhos_Line_Parameter pp
on PO.tPhos_Line_Parameter_id = PP.id
INNER JOIN tGroup_Parameter GP
on pp.tGroup_Parameter_id = gp.id
left join CTE T on T.tGroup_id = P.PO.tGroup_id
AND T.CurrentSet = PO.CurrentSet
where PP.tPhosline_id=134)tbl
PIVOT ( MAX(p.Results) For Header IN ([4],[23],[24])) AS pvt

Get percentages of larger group

The query below is kind of an ugly one so I hope I've got it spaced well enough to make it readable. The query finds the percentage of people that visit a given hospital if they are from a certain area. For instance, if 100 people live in county X and 20 go to hospital A and 80 go to hospital B the query outputs. How the heck is this sort of thing done? Let me know if I need to document the query or whatever I can do to make it clearer.
hospital A 20
hospital B 80
The query below works exactly like I want it to, but it give me thinking: how could this be done for every county in my table?
select hospitalname, round(cast(counts as float)/cast(fayettestrokepop as float)*100,2)as percentSeen
from
(
SELECT tblHospitals.hospitalname, COUNT(tblHospitals.hospitalname) AS counts, tblStateCounties_1.countyName,
(SELECT COUNT(*) AS Expr1
FROM Patient INNER JOIN
tblStateCounties ON Patient.stateCode = tblStateCounties.stateCode AND Patient.countyCode = tblStateCounties.countyCode
WHERE (tblStateCounties.stateCode = '21') AND (tblStateCounties.countyName = 'fayette')) AS fayetteStrokePop
FROM Patient AS Patient_1 INNER JOIN
tblHospitals ON Patient_1.hospitalnpi = tblHospitals.hospitalnpi INNER JOIN
tblStateCounties AS tblStateCounties_1 ON Patient_1.stateCode = tblStateCounties_1.stateCode AND Patient_1.countyCode = tblStateCounties_1.countyCode
WHERE (tblStateCounties_1.stateCode = '21') AND (tblStateCounties_1.countyName = 'fayette')
GROUP BY tblHospitals.hospitalname, tblStateCounties_1.countyName
) as t
order by percentSeen desc
EDIT: sample data
The sample data below is without the outermost query (the as t order by part).
The countsInTheCounty column is the (select count(*)..) part after 'tblStateCounties_1.countyName'
hospitalName hospitalCounts countyName countsInTheCounty
st. james 23 X 300
st. jude 40 X 300
Now with the outer query we would get
st james 0.076 (23/300)
st. jude 0.1333 (40/300)
Here is my guess. You'll have to test against your data or provide proper DDL + sample data.
;WITH totalCounts AS
(
SELECT StateCode, countyCode, COUNT(*) AS totalcount
FROM dbo.Patient GROUP BY StateCode, countyCode
)
SELECT
h.hospitalName,
hospitalCounts = COUNT(p.hospitalnpi),
c.countyName,
countsInTheCounty = tc.totalCount,
percentseen = CONVERT(DECIMAL(5,2), COUNT(p.hospitalnpi)*100.0/tc.totalCount)
FROM
dbo.Patient AS p
INNER JOIN
dbo.tblHospitals AS h
ON p.hospitalnpi = h.hospitalnpi
INNER JOIN
totalCounts AS tc
ON p.StateCode = tc.StateCode
AND p.countyCode = tc.countyCode
INNER JOIN
dbo.tblStateCounties AS c
ON tc.StateCode = c.stateCode
AND tc.countyCode = c.countyCode
GROUP BY
h.hospitalname,
c.countyName,
tc.totalcount
ORDER BY
c.countyName,
percentseen DESC;

Rollup / recursive addition SQL Server 2008

I have a query with rollup that outputs data like (the query is a little busy, but I can post if necessary)
range subCounts Counts percent
1-9 3 100 3.0
10-19 13 100 13.0
20-29 30 100 33.0
30-39 74 100 74.0
NULL 100 100 100.0
How is it possible to keep a running summation total of percent? Say I need to find the bottom 15 percentile, in this case 3+13=16 so I would like for the last row to be returned read
range subCounts counts percent
10-19 13 100 13.0
EDIT1: here the query
select '$'+cast(+bin*10000 + ' ' as varchar(10)) + '-' + cast(bin*10000+9999 as varchar(10)) as bins,
count(*) as numbers,
(select count(distinct patient.patientid) from patient
inner join tblclaims on patient.patientid = tblclaims.patientid
and patient.admissiondate = tblclaims.admissiondate
and patient.dischargedate = tblclaims.dischargedate
inner join tblhospitals on tblhospitals.hospitalnpi = patient.hospitalnpi
where (tblhospitals.hospitalname = 'X')
) as Totals
, round(100*count(*)/cast((select count(distinct patient.patientid) from patient
inner join tblclaims on patient.patientid = tblclaims.patientid
and patient.admissiondate = tblclaims.admissiondate
and patient.dischargedate = tblclaims.dischargedate
inner join tblhospitals on tblhospitals.hospitalnpi = patient.hospitalnpi
where (tblhospitals.hospitalname = 'X')) as float),2) as binsPercent
from
(
select tblclaims.patientid, sum(claimsmedicarepaid) as TotalCosts,
cast(sum(claimsmedicarePaid)/10000 as int) as bin
from tblclaims inner join patient on patient.patientid = tblclaims.patientid
and patient.admissiondate = tblclaims.admissiondate
and patient.dischargedate = tblclaims.dischargedate
inner join tblhospitals on patient.hospitalnpi = tblhospitals.hospitalnpi
where tblhospitals.hospitalname = 'X'
group by tblclaims.patientid
) as t
group by bin with rollup
OK, so for whomever might use this for reference I figured out what I needed to do.
I added row_number() over(bin) as rownum to the query and saved all of this as a view.
Then I used
SELECT *,
SUM(t2.binspercent) AS SUM
FROM t t1
INNER JOIN t t2 ON t1.rownum >= t2.rownum
GROUP BY t1.rownum,
t1.bins, t1.numbers, t1.uktotal, t1.binspercent
ORDER BY t1.rownum
by joining t1.rownum >=t2.rownum you can get the rolling count sort of thing.
This isn't exactly what i was looking for, but it's on the same track:
http://blog.tallan.com/2011/12/08/sql-server-2012-windowing-functions-part-1-of-2-running-and-sliding-aggregates/ and http://blog.tallan.com/2011/12/19/sql-server-2012-windowing-functions-part-2-of-2-new-analytic-functions/ - check out PERCENT_RANK
CUME_DIST
PERCENTILE_CONT
PERCENTILE_DISC
Sorry for the lame answer