Max date won't work, alternative? - sql

I read through some of the answers but couldn't find the right answer for the following question. I have the below query that runs:
SELECT
mbr_src_code as 'C',
cst_recno as 'ID',
ind_first_name as 'FN',
ind_last_name as 'LN',
cst_org_name_dn as 'Company',
cst_ixo_title_dn as 'Title',
MAX(inv_trx_date) as 'Latest Transaction',
inv_add_user as 'User',
pyd_type as 'Type',
bat_code as 'Code',
mbr_add_user 'Add User',
mbr_rejoin_date as 'rejoin',
mbt_code,
adr_state as 'state',
adr_country as 'country',
ivd_amount_cp
FROM
mb_membership
JOIN
co_customer ON cst_key = mbr_cst_key AND mbr_delete_flag = 0
LEFT JOIN
mb_member_type ON mbr_mbt_key = mbt_key
LEFT JOIN
co_customer_x_address ON cxa_key = cst_cxa_key
LEFT JOIN
co_address ON cxa_adr_key = adr_key
LEFT JOIN
co_individual ON ind_cst_key = cst_key
LEFT JOIN
mb_membership_x_ac_invoice ON mxi_mbr_key = mbr_key
LEFT JOIN
ac_invoice ON mxi_inv_key = inv_key
LEFT JOIN
ac_invoice_detail ON ivd_inv_key = inv_key
LEFT JOIN
ac_payment_detail ON pyd_ivd_key = ivd_key
LEFT JOIN
ac_payment ON pyd_pay_key = pay_key
LEFT JOIN
ac_batch ON pay_bat_key = bat_key
LEFT JOIN
ac_payment_info ON pay_pin_key = pin_key
LEFT JOIN
co_customer_x_customer ON cxc_cst_key_1 = co_customer.cst_key
AND (cxc_end_date IS NULL OR DATEDIFF(dd, GETDATE(), cxc_end_date) >= 0)
AND cxc_rlt_code = 'Chapter Member'
LEFT JOIN
co_chapter ON cxc_cst_key_2 = chp_cst_key
WHERE
(mbr_src_code LIKE N'%1DMFY18%' OR mbr_src_code LIKE N'%2DMFY18%'
OR mbr_src_code LIKE N'%INPhoneFY18%' OR mbr_src_code LIKE N'%OBTMFY18%'
OR mbr_src_code LIKE N'%3DMFY18%')
AND cst_recno = '20239'
GROUP BY
mbr_key, mbr_src_code, cst_recno,
ind_first_name, ind_last_name, cst_org_name_dn, cst_ixo_title_dn,
inv_add_user, pyd_type, bat_code, mbr_add_user, mbr_rejoin_date,
mbt_code, adr_state, adr_country, pin_cc_number_display, pin_cc_cardholder_name,
ivd_amount_cp, chp_name
ORDER BY
ind_last_name
and I get the following result(sample):
C ID FN LN Company Title Latest transaction User Type Code Add User rejoin mbt_code state country ivd_amount_cp
2DMFY18 20239 Gus Bauman Beveridge & Diamond Attorney 2013-09-23 00:00:00 Membership Renewal Payment 2013-09-23-ULI-USD-C-SP-01 ULI_Conversion NULL Associate Member DC UNITED STATES 430.00
2DMFY18 20239 Gus Bauman Beveridge & Diamond Attorney 2014-08-04 00:00:00 Membership Renewal Payment 2014-08-04-ULI-USD-C-SP-01 ULI_Conversion NULL Associate Member DC UNITED STATES 430.00
2DMFY18 20239 Gus Bauman Beveridge & Diamond Attorney 2015-09-02 00:00:00 Membership Renewal Payment 2015-09-02-ULI-USD-C-SP-02 ULI_Conversion NULL Associate Member DC UNITED STATES 440.00
2DMFY18 20239 Gus Bauman Beveridge & Diamond Attorney 2016-09-12 00:00:00 Membership Renewal Payment 2016-09-12-ULI-USD-C-SP-01 ULI_Conversion NULL Associate Member DC UNITED STATES 440.00
2DMFY18 20239 Gus Bauman Beveridge & Diamond Attorney 2017-09-22 00:00:00 Membership Renewal Payment 2017-09-22-ULI-USD-C-SP-01 ULI_Conversion NULL Associate Member DC UNITED STATES 440.00
So my MAX function doesn't work(probably because there are other columns with different value,just like in inv_trx_date) , what would be the best alternative to use? I would like to basically take the whole query and select MAX(inv_trx_date) as 'Latest Transaction' per each unique cst_recno as 'ID'.

I think the canonical answer to this question is as follows
with AllData as
(
select ... from ...
where ...
)
select * from allData ad1
inner join
(
select pk1, pk2, pk<n>, max(MaxThing) MaxVal
from AllData
group by pk1, pk2, pk<n>
) as ad2
on (ad1.pk1=ad2.pk1 and ad1.pk2=ad2.pk2 and ad1.pk<n>=ad2.pk<n>
and ad1.MaxThing=ad2.MaxVal)
In your case cst_recno is the PK and inv_trx_date is the MaxThing

MAX works over the entire group you have specified. If you want the MAX aggregation to work for each unique cst_recno then you need to group by only each unique cst_recno.

The issue of duplicate rows is because your CODE and ivd_amount_cp columns contain non-unique values in the recordset. Had they all contained the exact same information, your MAX function would have worked without any problems.
You will have to use a Common Table Expression, as others have suggested. Let's assume you have a table that contains a specific CustomerID, and order dates, as well as a lot of other information. A customer can place multiple orders on the same date, and for whatever reason, we're only interested in the latest order of that customer. However, we do want to see all information related to that order.
The first thing we do is build a CTE to identify which order is the latest:
/* Example table */
CREATE TABLE myOrders
(
OrderID int IDENTITY(1,1)
, CustomerID int
, OrderDate datetime
, ImportantInfo nvarchar(255)
)
;
/* Some test data to work with */
INSERT INTO myOrders
VALUES (
1, '01-01-2017', 'We do not want this row'
), (
1, '01-02-2017', 'We do not want this row either'
), (
1, '01-10-2017', 'Getting closer, but not this one either'
), (
1, '01-10-2017', 'This is the one we want!'
)
;
WITH myMaxOrder AS
(
SELECT CustomerID, MAX(OrderID) AS MaxOrderID
FROM myORders
GROUP BY CustomerID
)
Once you identified the MAX of whatever you need, you then simply use that to identify all the other data you want to retrieve, by using the CTE to join back to the original table using the values you just obtained in the CTE:
SELECT
o.*
FROM
MyOrders o
JOIN myMaxOrder o1 ON o.CustomerID = o1.CustomerID
AND o1.MaxOrderID = o.OrderID

Related

Creating Daily In-Use table w/ Zeros When NULL

Hello Stack Community,
I am not sure if I titled this accurately, but I am attempting to create a table that tracks the daily in-use quantity by product code. Currently my code drops dates where a product isn't in-use whereas I need that to show as a 0.
My thoughts where that by using the date from the date table that my LEFT OUTER JOIN with the ISNULL on the field would produce a 0, but nay.
Here is my code, with a screenshot of what it outputs with the red square highlighting where it's missing date records that I need to show as 0 :
SELECT
DD.DATE,
DE.PRODUCT_CODE,
--OOC = OUT OF CONTEXT, EITHER ISN'T CHARGEABLE OR ISN'T CURRENTLY ACTIVE
ISNULL(SUM(LIDV.QTY - LIDV.QTYSUB),0),
OD.LOCATION,
OD.SOURCE
FROM Dim_Date AS DD
LEFT OUTER JOIN ORDERv_DatesDays AS OD ON DD.DATE BETWEEN OD.SHIP_DATE AND OD.adjRETURN_DATE
LEFT OUTER JOIN FACT_Orders_LIDs AS LIDV ON LIDV.SORDERID_DAX = OD.SORDERID_DAX
LEFT OUTER JOIN DIM_ECODES AS DE ON DE.PRODUCT_CODE = LIDV.eCODE
WHERE
--DD.DATE = '3/1/2017' AND
DD.DATE BETWEEN '1/1/2017' AND EOMONTH( DATEADD( MONTH , -1, CURRENT_TIMESTAMP ) ) AND
DE.PRODUCT_CODE = '07316-' AND
YEAR(DD.DATE) = 2017
GROUP BY
DD.DATE,
DE.PRODUCT_CODE,
OD.LOCATION,
OD.SOURCE
ORDER BY
DD.DATE
I also thought, since I'm no SQL expert, that perhaps I need to just create a table with each product code and date for a specified date range but I got tripped up trying to create that as well.
Thank you for any assistance, if I need to add more info just let me know what I'm missing.
This WHERE predicate is killing your left join:
DE.PRODUCT_CODE = '07316-' AND
If product_code 07316 was not "out on loan" (or whatever) between Feb 24 and April 6 then all those rows would have looked like:
DATE PRODUCT_CODE INUSE LOCATION
2017-02-25 NULL NULL NULL
2017-02-26 NULL NULL NULL
2017-02-27 NULL NULL NULL
2017-02-28 NULL NULL NULL
...
2017-04-05 NULL NULL NULL
But, that NULL in product_code means that when the where clause asks "is NULL equal to 07316- ?" the answer is false, so the row diasppears from the resultset
Consider
LEFT OUTER JOIN DIM_ECODES AS DE
ON
DE.PRODUCT_CODE = LIDV.eCODE AND
DE.PRODUCT_CODE = '07316-'
You might also want to make some changes in the SELECT block too:
'07316-' as PRODUCT_CODE,
COALESCE(INUSE,0) AS INUSE
It might make more sense to you to write it like this:
FROM
Dim_Date AS DD
LEFT OUTER JOIN
(
SELECT
OD.SHIP_DATE,
OD.adjRETURN_DATE,
LIDV.QTY,
LIDV.QTYSUB,
OD.LOCATION,
OD.SOURCE
FROM
ORDERv_DatesDays AS OD
INNER JOIN FACT_Orders_LIDs AS LIDV ON LIDV.SORDERID_DAX = OD.SORDERID_DAX
INNER JOIN DIM_ECODES AS DE ON DE.PRODUCT_CODE = LIDV.eCODE
WHERE
DE.PRODUCT_CODE = '07316-'
) x
ON DD.DATE BETWEEN x.SHIP_DATE AND x.adjRETURN_DATE
WHERE
This is "list of dates on the left" and "any relevant data, already joined together and where'd on the right"
It should also be noted that if you're doing this for multiple product codes, to prevent just a single date row if both product 07316 and 07317 are in use on the 28th Feb you'd need to:
FROM
(
SELECT DISTINCT DD.DATE, DE.PRODUCT_CODE
FROM Dim_Date AS DD CROSS JOIN DIM_ECODES DE
WHERE ..date range clause..
)
This takes your list of dates, and crosses it with your list of prod codes, so you can be certain there are at least these two rows:
2017-02-28 07316-
2017-02-28 07317-
Then when you left join the products on date and product code, both those rows' data survive the left join, and become associated with nulls:
2017-02-28 07316- NULL NULL
2017-02-28 07317- NULL NULL
Without doing that CROSS, you'd have just one row (null in product code)

Sql Joining 3 Tables Query for Loan Total Result

I have to get the total of Customer Loan from 3 tables the two tables are given loan to sum and the other subtract the paid amount and the tables have Customer ID in common. so far I can get the result only if the Customer ID exist in all tables but if it doesn't exist in one table I won't get Customer in my result. or I get NULL customer IDs when I anchor to the customer.
SELECT
AS1.C_ID AS [Customer ID],
ISNULL(AS1.OldCustomerLoan, 0) AS [Old Loan],
ISNULL(AS2.NewGivenLoan, 0) AS [New Given Loan],
ISNULL(AS3.LoanPaid, 0) AS [PaidLoanAmount],
(ISNULL(AS1.OldCustomerLoan, 0) +
ISNULL(AS2.NewGivenLoan, 0) -
ISNULL(AS3.LoanPaid,0) ) AS Total
FROM
Customer C
LEFT OUTER JOIN
(SELECT
MOC.C_ID,
SUM(MOC.Quantity) AS OldCustomerLoan
FROM
Money_On_Customer MOC (NOLOCK)
GROUP BY
MOC.C_ID) AS1
ON c.C_Id = AS1.C_Id
LEFT OUTER JOIN
(SELECT
NGL.C_ID
,SUM(NGL.G_Take_Loan) AS NewGivenLoan
FROM
Given_Loan NGL
GROUP BY
NGL.C_ID) AS2
ON c.C_Id = AS2.C_Id
LEFT OUTER JOIN
(SELECT
GLP.C_ID, SUM(GLP.G_P_Loan) AS LoanPaid
FROM
Given_Loan_Paid GLP
GROUP BY
GLP.C_ID ) AS3
ON c.C_Id = AS3.C_Id
Here Is a picture of my two results:
When I get NULL Customer IDs
When I don't get All the Customers
You need to use c.c_id for the first column
In order to only get records where they exist in at least one of the tables you can add this to you query, just put you current query in place of the dots, and add the leftid col
Select *
From
(Select c.c_id custonerid,
Coalesce(Coalesce(as1.c_id,as2.c_id),as3.c_id) leftid,......
From ....
) ilv
Where leftid is not null
You might be able to just add
Where coalesce(coalesce(as1.c_id,as2.c_id),as3.c_id) is not null
To then end of your query
#Ab Bennett's answer is right,
because you should use your main(master) table's primary key column
if Customer ID is not available in as1 (Money_On_Customer) it will show null.
Hope you understand my explanation.
UPDATE:
and use following for getting customer id
COALESCE(c.C_Id, AS1.C_Id, AS2.C_Id)
you will get first not null Customer ID
Here is My answer with the help of #Ab Bennett
Select *
From
(
SELECT
C.C_Name AS [Customer ID],
ISNULL(AS1.OldCustomerLoan, 0) AS [Old Loan],
ISNULL(AS2.NewGivenLoan, 0) AS [New Given Loan],
ISNULL(AS3.LoanPaid, 0) AS [PaidLoanAmount],
(ISNULL(AS1.OldCustomerLoan, 0) +
ISNULL(AS2.NewGivenLoan, 0) -
ISNULL(AS3.LoanPaid,0) ) AS Total
FROM
Customer C
LEFT OUTER JOIN
(SELECT
MOC.C_ID,
SUM(MOC.Quantity) AS OldCustomerLoan
FROM
Money_On_Customer MOC (NOLOCK)
GROUP BY
MOC.C_ID) AS1
ON c.C_Id = AS1.C_Id
LEFT OUTER JOIN
(SELECT
NGL.C_ID
,SUM(NGL.G_Take_Loan) AS NewGivenLoan
FROM
Given_Loan NGL
GROUP BY
NGL.C_ID) AS2
ON c.C_Id = AS2.C_Id
LEFT OUTER JOIN
(SELECT
GLP.C_ID, SUM(GLP.G_P_Loan) AS LoanPaid
FROM
Given_Loan_Paid GLP
GROUP BY
GLP.C_ID ) AS3
ON c.C_Id = AS3.C_Id) ilv
Where not ([Old Loan] = 0 and [New Given Loan]=0 and PaidLoanAmount =0 )

Difference Max and Min from Different Dates

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)

Select max from several columns

I'm writing code to select patients that die within 30 days of a hospital discharge, my issue is that when I have a patient with multiple discharges within that 30 day tolerance it pulls back multiple rows! I've tried to solve this using max discharge date, which worked, yet when I add extra columns it seems to pull certain elements from other rows. Here is my code:
SELECT MAX(IPS.disch_dttm) [Discharge Datetime]
,MAX(IPS.IP_SPELL_ID) [Spell ID]
,pat.PAS_ID [K Number]
,MAX(IPS.DIS_WARD_ID) [Ward ID]
,DSSU.SU_DESCRIPTION [Discharging Ward]
FROM Pat_spell AS IPS
LEFT JOIN PATIENT PAT WITH (NOLOCK) ON PAT.DIM_PATIENT_ID = IPS.DIM_PATIENT_ID
LEFT JOIN SPECIALTY SPEC WITH (NOLOCK) ON SPEC.DIM_SPECIALTY_ID = IPS.DIM_DIS_SPECT_ID
LEFT JOIN SERVICE_UNIT DSSU WITH (NOLOCK) ON IPS.DIM_DIS_WARD_ID = DSSU.DIM_SSU_ID
WHERE (IPS.DISCH_DTTM <= PAT.DEATH_DTTM + 30)
AND IPS.DIM_DIS_SPECT_ID = '7195'
AND IPS.DISCH_DTTM BETWEEN '01/01/2014' AND '30/06/2014'
GROUP BY pat.PAS_ID
,pat.DEATH_DTTM
,IPS.DIM_PATIENT_ID
,DSSU.SSU_DESCRIPTION
ORDER BY pat.PAS_ID
Here is output from the above code for a single row that I've been using to debug:
Disch Date Event_ID Unique ID Ward ID Discharging Ward
2014-06-14 8366113 A123456 77085 WardA
The above gets the ward ID correct, but the "Discharging Ward" is wrong. Also the Event_ID corresponds with a previous attendance. What I'm trying to achieve is to pull only the most recent event within 30 days of a time of death, with 'Event ID' as my unique ID. This is what the output would look like if I wanted multiple rows:
Disch Date Event ID Unique ID Ward ID Discharging Ward
1 2014-06-14 8208846 A123456 77085 Ward B
2 2014-05-16 8366113 A123456 77036 Ward A
This is what my output should look like:
Disch Date Event_ID Unique ID Ward ID Discharging Ward
2014-06-14 8208846 A123456 77085 Ward B
So to sum up, my code pulls the correct "discharge date", the correct "Ward ID" but seems to pull the rest from other rows in the table. Apologies for the huge ask - any help would be appreciated, or if this has been explored to death, please point me in the right direction.
A simplified version of what you need looks like this...
SELECT [DETAIL INFO, no need to MAX or GROUP BY]
FROM Pat_spell AS IPS
LEFT JOIN PATIENT PAT WITH (NOLOCK) ON PAT.DIM_PATIENT_ID = IPS.DIM_PATIENT_ID
LEFT JOIN SPECIALTY SPEC WITH (NOLOCK) ON SPEC.DIM_SPECIALTY_ID = IPS.DIM_DIS_SPECT_ID
LEFT JOIN SERVICE_UNIT DSSU WITH (NOLOCK) ON IPS.DIM_DIS_WARD_ID = DSSU.DIM_SSU_ID
INNER JOIN (
SELECT PatientID, MAX(IPS.disch_dttm) AS DischargeDt
FROM [AllMyTables]
WHERE (IPS.DISCH_DTTM <= PAT.DEATH_DTTM + 30)
AND IPS.DIM_DIS_SPECT_ID = '7195'
AND IPS.DISCH_DTTM BETWEEN '01/01/2014' AND '30/06/2014'
) t1 ON PAT.PatientID = t1.PatientID AND IPS.disch_dttm = t1.DischargeDt
ORDER BY pat.PAS_ID
Since the INNER SQL is returning 1 row per patient, there is no need to group on the OUTER SQL.
If I had more data to work with, I might be able to stitch together the full SQL, but maybe this points you in the right direction.
You are getting the max of each field independently. If you want the row that corresponds with the latest discharge date, you need to row_number it in Descending order, then select where that =1.
We do the same type query for 30 day re-admits.
So something like
WITH
LastDischargeCTE
AS
(SELECT pat.PAS_ID [K Number], IPS.disch_dttm [Discharge Datetime], (IPS.IP_SPELL_ID) [Spell ID]
,(IPS.DIS_WARD_ID) [Ward ID]
,DSSU.SU_DESCRIPTION [Discharging Ward]
,ROW_NUMBER () OVER (PARTITION BY pat.PAS_ID ORDER BY IPS.disch_dttm DESC) AS DischargeSequence
FROM Pat_spell
LEFT JOIN PATIENT PAT WITH (NOLOCK) ON PAT.DIM_PATIENT_ID = IPS.DIM_PATIENT_ID
LEFT JOIN SPECIALTY SPEC WITH (NOLOCK) ON SPEC.DIM_SPECIALTY_ID = IPS.DIM_DIS_SPECT_ID
LEFT JOIN SERVICE_UNIT DSSU WITH (NOLOCK) ON IPS.DIM_DIS_WARD_ID = DSSU.DIM_SSU_ID
WHERE (IPS.DISCH_DTTM <= PAT.DEATH_DTTM + 30)
AND IPS.DIM_DIS_SPECT_ID = '7195'
AND IPS.DISCH_DTTM BETWEEN '01/01/2014' AND '30/06/2014'
)
SELECT *
FROM LastDischargeCTE
WHERE DischargeSequence =1

SQL Join returning all rows in a table

I am looking to get an account name from a table, but it is returning both rows in the table instead of the one that matches. Here's the table called LEDGERTRANS:
Account Date Voucher
402000 2014-01-14 CM-00011026
554500 2014-01-14 CM-00011026
This is being joined to a table called LEDGERTABLE which will match up the Account based on this tables account number. So we get a voucher number, then the account number, then match that to the table to get the account name. The thing is that this is bringing back BOTH account numbers descriptions from the table. Here's the SQL
SELECT DISTINCT
dbo.CUSTTABLE.NAME AS 'Customer',
dbo.CUSTINVOICEJOUR.INVOICEACCOUNT AS 'Acct #',
dbo.CUSTINVOICEJOUR.SALESID AS 'Sales Order',
dbo.CUSTINVOICEJOUR.INVOICEDATE AS 'Date',
dbo.CUSTINVOICEJOUR.INVOICEID AS 'Invoice',
(INVOICEAMOUNT - SALESBALANCE) AS 'Inv Amt',
'Misc Charge' AS ITEMID,
'Misc. Charge' AS 'Reason',
[DESCRIPTION] AS 'Division',
CREATEDBY
,LEDGERTABLE.ACCOUNTNUM as 'Account Number'
FROM
dbo.CUSTINVOICEJOUR INNER JOIN
dbo.CUSTINVOICETRANS ON dbo.CUSTINVOICEJOUR.INVOICEID = dbo.CUSTINVOICETRANS.INVOICEID INNER JOIN
dbo.CUSTTABLE ON ACCOUNTNUM = dbo.CUSTINVOICEJOUR.INVOICEACCOUNT INNER JOIN
dbo.DIMENSIONS ON NUM = dbo.CUSTINVOICEJOUR.DIMENSION2_
JOIN LEDGERTRANS ON LEDGERTRANS.VOUCHER = CUSTINVOICEJOUR.INVOICEID
inner JOIN LedgerTable ON LedgerTable.ACCOUNTNUM = Ledgertrans.ACCOUNTNUM
WHERE
dbo.CUSTINVOICEJOUR.INVOICEID LIKE 'CM-00%'
AND
dbo.CUSTINVOICEJOUR.INVOICEDATE BETWEEN #start AND #end
AND
dbo.CUSTINVOICEJOUR.DIMENSION2_ IN (#division)
AND
INVOICEAMOUNT <> SALESBALANCE
AND
CREATEDBY IN (#createdBy)
AND
LEDGERTRANS.CREDITING='0'
This effectively brings back 2 entries for each item. How can I get rid of this extra row?
C3 Ingenuity 110051 SO-00670938 CM-00011026 -33.750000000000 Misc Charge 402000
C3 Ingenuity 110051 SO-00670938 CM-00011026 -33.750000000000 Misc Charge 554500
even:
Select LEDGERTABLE.ACCOUNTNUM from LedgerTable JOIN Ledgertrans ON LedgerTable.ACCOUNTNUM = Ledgertrans.ACCOUNTNUM Where LEDGERTRANS.VOUCHER = CUSTINVOICEJOUR.INVOICEID
Returns both results
The difference is the last column (LEDGERTABLE.ACCOUNTNUM if I understand correctly).
You can exclude the table/column from the query, or GROUP BY the rest of columns leaving MIN/MAX from the exisitng account numbers