SQL query for most recent date - sql

I'm trying to query to only pull the most recent sale date but keep the unique value of "strap". This is the query result I have.
nh_cd strap dor_cd acreage sqft sale date reception_num price asd_val rea_cd
178.00 R0000001 AG 4.7160 205443 2019-07-11 00:00:00.000 3723615 890000 200 05
178.00 R0000001 AG 4.7160 205443 2020-05-29 00:00:00.000 3787823 880000 200 40
205.00 R0022222 AGRES 5.8030 252771 2019-06-10 00:00:00.000 3718473 647500 520200 40
This is what I've built so far, but it doesn't give me my desired result of a recent date.
SELECT distinct
parcel.nh_cd
,sales.strap
,parcel.dor_cd
,detail.acreage
,detail.sqft
,max(sales.dos)
,sales.reception_num
,sales.price
,parcel.asd_val
,sales.rea_cd
,sales.qu_flg
,sales.valid_cd
,sales.vi
,site.str_num
,site.str_pfx
,site.str
,site.str_sfx
,site.city
,parcel.status_cd
,strap_idx.folio
FROM detail INNER JOIN parcel ON parcel.strap = detail.strap
INNER JOIN sales ON parcel.strap = sales.strap
INNER JOIN site ON parcel.strap = site.strap
INNER JOIN strap_idx ON parcel.strap = strap_idx.strap
INNER JOIN lnd_a ON parcel.strap = lnd_a.strap
WHERE lnd_a.st_use_cd IN ('4117','4127','4137','4147','4167','4177','4180')
AND parcel.dor_cd LIKE 'AG%'
AND parcel.status_cd = 'A'
AND (sales.price > '0')
AND (site.ln_num = '1')
AND (sales.dos>='07/01/2018')
AND (sales.dos<='08/24/2020')
GROUP by parcel.nh_cd
,sales.strap
,parcel.dor_cd
,detail.acreage
,detail.sqft
,sales.dos
,sales.reception_num
,sales.price
,parcel.asd_val
,sales.rea_cd
,sales.qu_flg
,sales.valid_cd
,sales.vi
,site.str_num
,site.str_pfx
,site.str
,site.str_sfx
,site.city
,parcel.status_cd
,strap_idx.folio
This is the result I want
nh_cd strap dor_cd acreage sqft sale date reception_num price asd_val rea_cd
178.00 R0000001 AG 4.7160 205443 2020-05-29 00:00:00.000 3787823 880000 200 40
205.00 R0022222 AGRES 5.8030 252771 2019-06-10 00:00:00.000 3718473 647500 520200 40
How would I go about doing this?

You can ROW_NUMBER() it
SELECT *
FROM (
SELECT distinct parcel.nh_cd
,sales.strap
,parcel.dor_cd
,detail.acreage
,detail.sqft
,sales.dos
,sales.reception_num
,sales.price
,parcel.asd_val
,sales.rea_cd
,sales.qu_flg
,sales.valid_cd
,sales.vi
,site.str_num
,site.str_pfx
,site.str
,site.str_sfx
,site.city
,parcel.status_cd
,strap_idx.folio
, ROW_NUMBER() OVER(PARTITION BY parcel.nh_cd, sales.strap ORDER BY sales.dos DESC) AS rn
FROM detail INNER JOIN parcel ON parcel.strap = detail.strap
INNER JOIN sales ON parcel.strap = sales.strap
INNER JOIN site ON parcel.strap = site.strap
INNER JOIN strap_idx ON parcel.strap = strap_idx.strap
INNER JOIN lnd_a ON parcel.strap = lnd_a.strap
WHERE lnd_a.st_use_cd IN ('4117','4127','4137','4147','4167','4177','4180')
AND parcel.dor_cd LIKE 'AG%'
AND parcel.status_cd = 'A'
AND (sales.price > '0')
AND (site.ln_num = '1')
AND (sales.dos>='07/01/2018')
AND (sales.dos<='08/24/2020')
) t
WHERE rn = 1

Related

Multiple joins chose latest record by date

I am trying to link four tables (3 of them key to this question). I need to pull the latest payment type used from T16. T16 links to T17 via headerid, which links to A10 via pledgeid.
I have tried this a bunch of different ways. The code below is giving me the latest date for each payment type, but what I really want is just the last payment type.
SELECT DISTINCT
A10.RecordId
,A10.AccountNumber
,A01.FamilyId
,a01.FamilyMemberType
,A10.PledgeCode --Child Number
,A10.OriginalPledgeId
,A10.PledgeId
,A01.FirstName
,A01.LastName
,A10.PledgeStatus
,A10.AmountPerGift
,A10.PledgeFrequency
,t16.PaymentType
FROM
A10_AccountPledges A10
LEFT JOIN
A01_AccountMaster A01 ON a01.AccountNumber = a10.AccountNumber
LEFT JOIN
T17_RecurringDonations T17 ON T17.PledgeId = A10.PledgeId
LEFT JOIN
T16_RecurringTransactionHeaders T16 ON T16.HeaderId = T17.HeaderId
INNER JOIN
(SELECT
T17.pledgeID
,MAX(T16.LastUsedDate) as lastdate
FROM
T17_RecurringDonations T17
LEFT JOIN
T16_RecurringTransactionHeaders T16 ON T16.HeaderId = T17.HeaderId
GROUP BY
T17.pledgeID) pm ON pm.PledgeId = A10.PledgeId --and pm.lastdate = T16.LastUsedDate
WHERE
A01.[Status] = 'A'
AND a10.PledgeId = 398353 --test case
You can do this like below:
select top 1 *
from (
YOUR QUERY HERE
)
order by lastdate desc;
Notes:
YOUR QUERY HERE is a placeholder which will hold your whole query as a subquery
you need to add the selection of lastdate to your subselect in order to make sure you can order by lastdate desc
EDIT
As #spaindc explained, this idea was applied, resulting in
SELECT distinct
A10.AccountNumber
,A01.FamilyId
,a01.FamilyMemberType
,A10.PledgeCode --Child Number
,A10.OriginalPledgeId
,A10.PledgeId
,A01.FirstName
,A01.LastName
,A10.PledgeStatus
,A10.PledgeFrequency
,(SELECT top 1 T16.PaymentType
FROM T16_RecurringTransactionHeaders T16, T17_RecurringDonations T17
where T16.HeaderId = T17.HeaderId
and T17.PledgeId = A10.PledgeId
order by t16.LastUsedDate desc
) as PaymentType
FROM A10_AccountPledges A10
left join A01_AccountMaster A01 on a01.AccountNumber = a10.AccountNumber
where A01.[Status] = 'A'
Thanks to Lajos for correct answer. Here is the final code for reference.
SELECT distinct
A10.AccountNumber
,A01.FamilyId
,a01.FamilyMemberType
,A10.PledgeCode --Child Number
,A10.OriginalPledgeId
,A10.PledgeId
,A01.FirstName
,A01.LastName
,A10.PledgeStatus
,A10.PledgeFrequency
,(SELECT top 1 T16.PaymentType
FROM T16_RecurringTransactionHeaders T16, T17_RecurringDonations T17
where T16.HeaderId = T17.HeaderId
and T17.PledgeId = A10.PledgeId
order by t16.LastUsedDate desc
) as PaymentType
FROM A10_AccountPledges A10
left join A01_AccountMaster A01 on a01.AccountNumber = a10.AccountNumber
where A01.[Status] = 'A'

Combine ContainerID row and add Qty

I want to combine Container ID, Date, and add the Qty. This query shows data at the item level. I want it to print data at the order level and sum the "Qty" column.
I can combine rows using excel & pivot tables, but when I run reports for over 3 months, I run out of rows in excel, so I break it up into smaller chunks and add the results. Tedious. There has to be an easier way.
What I am getting:
OrderDate ContainerID Qty
2019-06-03 104922434 1
2019-06-03 104922434 1
2019-06-01 104934958 1
2019-06-01 104934958 1
2019-06-01 104934958 1
What I want:
OrderDate ContainerID Qty
2019-06-03 104922434 2
2019-06-01 104934958 3
My current query:
select
convert(date,oh.ShipTime) as 'OrderDate',
p.ContainerID,
cc.Qty
from dmhost.tblOrderHeader oh
join dmhost.tblContainer c on oh.OrderHeaderID = c.OrderHeaderID
join dmhost.tblPackage p on c.ContainerID = p.ContainerID
join dmhost.tblContainerContents cc on c.ContainerID = cc.ContainerID
join dmhost.tblItemMaster im on im.ItemMasterID = cc.ItemMasterID
where (oh.ShipTime between '06/1/2019' and '07/1/2019')
and (BusinessUnitCode like '03'or BusinessUnitCode like '04')
and cc.Qty <> 0
order by p.ContainerID
I appreciate the help.
You can use SUM and GROUP BY:
select
convert(date,oh.ShipTime) as 'OrderDate',
p.ContainerID,
SUM(cc.Qty) Qty
from dmhost.tblOrderHeader oh
join dmhost.tblContainer c on oh.OrderHeaderID = c.OrderHeaderID
join dmhost.tblPackage p on c.ContainerID = p.ContainerID
join dmhost.tblContainerContents cc on c.ContainerID = cc.ContainerID
join dmhost.tblItemMaster im on im.ItemMasterID = cc.ItemMasterID
where (oh.ShipTime between '06/1/2019' and '07/1/2019')
and (BusinessUnitCode like '03'or BusinessUnitCode like '04')
and cc.Qty <> 0
group by
convert(date,oh.ShipTime),
p.ContainerID
order by ContainerID

Advanced SQL: Sum of sales between a date range

I'm trying to get the sum of sales for a specific product between a date range. Unfortunately, the sum of sales from the results for both dates are the same. By right the total sales on 2019/01/01 is 5000 and the total sales on following day 2019/01/02 is 3000. The results showed total sales which is 8000 for both days. Which is wrong. Any expert can help to improve is this query?
Declare #BusinessDate datetime ='2019-01-01'
Declare #end datetime ='2019-01-02'
DECLARE #StoreId int = 100
SELECT [Terminals].[Id] AS [TerminalId],
[Terminals].[StoreId],
[EOD].[Id] AS [EODId],
SUM([Sales].[SalesAmount]) AS [SalesAmount],
[EOD].BusinessDate
FROM [CEPP]..[Stores] WITH (NOLOCK)
INNER JOIN [CEPP]..[Terminals] WITH (NOLOCK)
ON [Stores].[Id] = [Terminals].[StoreId]
AND [Terminals].[MWorkFlowStatusId] = 2
AND ([Terminals].[MStatusId] = 1
OR ([Terminals].[MStatusId] = 0
AND [Terminals].[SuspendedDate] > #BusinessDate ))
LEFT JOIN [EndOfDays] AS [EOD] WITH (NOLOCK)
ON [Terminals].[Id] = [EOD].[TerminalId]
AND [EOD].[BusinessDate] >= #BusinessDate and [EOD].[BusinessDate]<=#end
CROSS APPLY (
SELECT SUM([Products].[Deno]) AS [SalesAmount]
FROM [SalesOrders] AS [SO] WITH (NOLOCK)
INNER JOIN [SalesTransactions] AS [ST] WITH (NOLOCK)
ON [SO].[Id] = [ST].[SalesOrderId]
LEFT JOIN [VoidOrders] AS [VO] WITH (NOLOCK)
INNER JOIN [VoidTransactions] AS [VT] WITH (NOLOCK)
ON [VO].[Id] = [VT].[VoidOrderId]
ON [SO].[DealerId] = [VO].[DealerId]
AND [SO].[StoreId] = [VO].[StoreId]
AND [SO].[TerminalId] = [VO].[TerminalId]
AND [ST].[ProductId] = [VT].[ProductId]
AND [ST].[SerialNo] = [VT].[SerialNo]
AND [ST].[BusinessDate] = [VT].[BusinessDate]
AND [VT].[MVoidTypeId] = 1
INNER JOIN [CEPP].[dbo].[Products] WITH (NOLOCK)
ON [ST].[ProductId] = [Products].[Id]
WHERE [EOD].[Id] IS NOT NULL
AND [VT].[SerialNo] IS NULL
AND [SO].[TerminalId] = [Terminals].[Id]
AND [ST].[BusinessDate] >= #BusinessDate and [ST].[BusinessDate] <= #end
) AS [Sales]
WHERE [Stores].[DealerId] = 1 AND (#StoreId IS NULL OR [Terminals].[StoreId] = #StoreId)
GROUP BY [Terminals].[Id], [Terminals].[StoreId], [EOD].[Id], [Stores].[Code], [Terminals].[Code],[EOD].BusinessDate
ORDER BY ISNULL([EOD].[Id], 0), [Stores].[Code], [Terminals].[Code]
The unexpected results I got is :
TerminalId StoreId EODId SalesAmount BusinessDate
21598 100 5427531 8000.00 2019-01-01 00:00:00.000
21598 100 5427532 8000.00 2019-01-02 00:00:00.000
The results should be like this:
TerminalId StoreId EODId SalesAmount BusinessDate
21598 100 5427531 5000.00 2019-01-01 00:00:00.000
21598 100 5427532 3000.00 2019-01-02 00:00:00.000
From what I can see at a glance and without test data, is that the SUM([Products].[Deno]) is being performed in the CROSS APPLY irrespective of any GROUP BY you have in the outer query. Hence why you're getting SUM([Sales].[SalesAmount]) to equal 8000 for each output row.
Refactor the CROSS APPLY subquery to aggregate SUM([Products].[Deno]) with respect to a GROUP BY and join back to the main table by the GROUP BY predicates to your outer query.
AND [EOD].[BusinessDate] >= #BusinessDate and [EOD].[BusinessDate]<=#end
This part looks very suspicious to me. I think it should be something like
[EOD].[BusinessDate] = [Sales].[Date]
If that does not resolve your problem, please provide us with scripts for creation of tables and test data. That way it's much easier to investigate query.

Should I use a subquery or sum in this situation?

I am trying to get line 11 (which can have multiple results of square footage numbers of different areas of a house such as porches, garages and includes living area) and subtract line 10 if possible to get the total square footage of areas in a house other than living area.
as a-- sum(id1.[calc_area] - pp.living_area) as [other_ area],
my problem is the two numbers are from different tables, and the select statement uses a different from table pv. What would be the easiest way to accomplish this?
select distinct pv.prop_id,
pv.hood_cd as neighborhood,
pv.abs_subdv_cd as subdivision,
cast (pv.[legal_desc] as char(16)) as legal,
[deed_date],
[consideration],
pv.prop_val_yr as year,
sts1.[situs_num] as address,
cast(sts1.[situs_street] as char(11)) as street,
pp.living_area,
id1.[calc_area] as [total_area],
cast (pp.[land_total_acres]as decimal (6,2))as acres,
[sale_type],
case when [sale_date] >='01/01/2014'then convert(varchar(18), [sale_date], 101)else''end as'sale date',
pp.ls_table,
(pv.land_hstd_val + pv.land_non_hstd_val + pv.ag_market + pv.timber_market)as land_val,
cast(pp.[main_land_total_adj]as decimal (5,2)) as land_adj_total,
(pv.imprv_hstd_val + pv.imprv_non_hstd_val)as imprv_val,
case when [sale_date] >='01/01/2014'then [sale_price] else 0 end as'sale price',
pv.market
from property_val pv with (nolock)
inner join prop_supp_assoc psa with (nolock) on
pv.prop_id = psa.prop_id
and pv.prop_val_yr = psa.owner_tax_yr
and pv.sup_num = psa.sup_num
inner join property p with (nolock)on
pv.prop_id = p.prop_id
inner join owner o with (nolock) on
pv.prop_id = o.prop_id
and pv.prop_val_yr = o.owner_tax_yr
and pv.sup_num = o.sup_num
inner join account ac with (nolock) on
o.owner_id = ac.acct_id
inner join property_profile pp with (nolock) on
pv.prop_id = pp.prop_id
and pv.prop_val_yr = pp.prop_val_yr
left outer join imprv_detail as id1 with (nolock) on
pv.prop_id = id1.prop_id
and pv.prop_val_yr = id1.prop_val_yr
and pv.sup_num = id1.sup_num
left outer join
(select cop.prop_id,
convert(varchar(20), co.deed_dt, 101) as deed_date,
co.consideration as consideration, s.sl_dt as sale_date,
s.sl_price as sale_price, s.sl_type_cd as sale_type
from chg_of_owner_prop_assoc cop with (nolock)
inner join chg_of_owner co with (nolock) on
co.chg_of_owner_id = cop.chg_of_owner_id
inner join sale s with (nolock) on
co.chg_of_owner_id = s.chg_of_owner_id
where cop.seq_num = 0
)as c
on c.prop_id = pv.prop_id
basic results with some columns hidden-----
prop_id address street living_area total_area acres
x 322 SURBER ST 939 48 0
x 322 SURBER ST 939 288 0
x 322 SURBER ST 939 939 0
xy 318 SURBER STRE 1202 0 0
xy 318 SURBER STRE 1202 120 0
xy 318 SURBER STRE 1202 340 0
xy 318 SURBER STRE 1202 1052 0
if you need only additional sum and all currently returned rows then use SUM OVER function:
sum(id1.[calc_area] - pp.living_area) over (PARTITION BY pv.prop_id, pv.prop_val_yr) as [other_ area]
you can modify partitioning, for example:
sum(id1.[calc_area] - pp.living_area) over (PARTITION BY pv.prop_id, pv.prop_val_yr, pp.ls_table) as [other_ area]
but if you have unwanted row multiplication when you join table and you need aggregated values from this table, then use subquery in OUTER APPLY clause (and don't join this table in other way), for example:
SELECT ...
, id1.total_area
...
OUTER APPLY (
SELECT Sum(calc_area) as total_area
FROM imprv_detail
WHERE prop_id = pv.prop_id = id1.
and prop_val_yr = pv.prop_val_yr
and sup_num = pv.sup_num
) AS id1
then to calculate other_area use total_area - total_living_area

Avoid third table multiplying results

I have three tables.
Defect: Main table used to store defects found.
FollowUp: Table that stores followups to a specific Defect.
Defect_Attach: Related table used all photo attachments for Defects and FollowUps.
How can I get dates for all photo attachments?
Some of these photos were taken for a defect, then at a later date, more photos were related to the defect during a followup.
The results I'm trying to get would look something like this:
or
So far my query looks like this:
SELECT d.GUID
,p.ATTACHMENTID
,p.REL_OBJECTID
,p.CONTENT_TYPE
,p.ATT_NAME
,p.DATA_SIZE
,d.DateObserved as 'Defect Date'
--,f.DateObserved as 'FollowUp Date'
FROM [ECIMUSR].[DEFECT__ATTACH] p
LEFT OUTER JOIN ECIMUSR.DEFECT d on d.ObjectID = p.REL_OBJECTID
--LEFT JOIN ECIMUSR.FOLLOWUP f on f.DefectGUID = d.GUID
WHERE
d.GUID = '{E511EA70-F5E5-11E4-8189-6C3BE50ED71F}'
ORDER BY [Defect Date]
But as soon as I try joining my third table (FOLLOWUP), my results multiply.
UPDATE:
Results:
SELECT p.ATT_NAME
,d.DateObserved as 'Defect Date'
--,f.DateObserved as 'FollowUp Date'
FROM [ECIMUSR].[DEFECT__ATTACH] p
LEFT OUTER JOIN ECIMUSR.DEFECT d on d.ObjectID = p.REL_OBJECTID
--LEFT JOIN ECIMUSR.FOLLOWUP f on f.DefectGUID = d.GUID
WHERE
d.GUID = '{E511EA70-F5E5-11E4-8189-6C3BE50ED71F}'
ORDER BY [Defect Date]
Joining THIRD Table:
SELECT p.ATT_NAME
,d.DateObserved as 'Defect Date'
,f.DateObserved as 'FollowUp Date'
FROM [ECIMUSR].[DEFECT__ATTACH] p
LEFT OUTER JOIN ECIMUSR.DEFECT d on d.ObjectID = p.REL_OBJECTID
LEFT JOIN ECIMUSR.FOLLOWUP f on f.DefectGUID = d.GUID
WHERE
d.GUID = '{E511EA70-F5E5-11E4-8189-6C3BE50ED71F}'
ORDER BY [Defect Date]
SELECT
d.DateObserved AS defect_date,
p.ATT_NAME AS photo_name,
f.DateObserved AS follow_up_date
FROM
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY REL_OBJECTID
ORDER BY ATT_NAME) AS ordinal
FROM
ECIMUSR.DEFECT__ATTACH
)
p
FULL OUTER JOIN
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY DefectGUID
ORDER BY DateObserved) AS ordinal
FROM
ECIMUSR.FOLLOWUP
)
f
ON f.DefectGUID = p.REL_OBJECTID
AND f.ordinal = p.ordinal
RIGHT JOIN
ECIMUSR.DEFECT d
ON d.ObjectID = COALESCE(f.DefectGUID, p.REL_OBJECTID)
Would give something like...
defect_date | photo_name | follow_up_date
-------------+-----------------------------+----------------
2014-12-19 | photo1.jpg | 2015-01-16
2014-12-19 | PhotoFollowUp1_20150117.jpg | 2015-03-19
2014-12-19 | PhotoFollowUp1_20150324.jpg | 2015-04-17
2014-12-19 | PhotoFollowUp1_20150417.jpg | NULL
2014-12-19 | PhotoFollowUp2_20150324.jpg | NULL
The photo names and the follow up dates have nothing to do with each others. they're just in alphabetical order with gaps if one list is longer than the other.