SQL Select multiple joins and MAX(field) result - sql

I'm using IBM Cognos to create a report which allows for fairly standard SQL. I am ultimately trying to take data from 2 tables and compare them to each other to ensure they match. Billing_Term, Bill_Period and Contract_Term_Amount all need to match when comparing a given Contract_Number, Contract_Item and Stream_Type between t1 and t3 but only for the MAX Seq_No from t3.
I tried a simple MAX() on Seq_No but that didn't work so I'm looking for help in limiting the results to the MAX Seq_No for the associated query results.
SELECT
t1.Contract_Number,
t1.Contract_Item,
t1.Stream_Type,
t1.Billing_Term,
t1.Bill_Period,
t1.Contract_Term_Amount,
t2.Reference_Document,
t3.Billing_Term,
t3.Bill_Period,
t3.Contract_Term_Amount,
t3.Seq_No
FROM
LeasingStreamData t1
INNER JOIN ContractsData t2 ON t1.Contract_Number = t2.Sales_Document
LEFT JOIN LeasingStreamData t3 ON t2.Reference_Document = t3.Contract_Number AND
t1.Contract_Item = t3.Contract_Item AND
t1.Stream_Type = t3.Stream_Type
WHERE
t1.Contract_Number IN ([some list of contracts])
GROUP BY
t1.Contract_Number,
t1.Contract_Item,
t1.Stream_Type,
t1.Billing_Term,
t1.Bill_Period,
t1.Contract_Term_Amount,
t2.Reference_Document,
t3.Billing_Term,
t3.Bill_Period,
t3.Contract_Term_Amount,
t3.Seq_No
I hope this is enough to get some much needed help, many thanks for any assistance you can provide!

If I understand you requirement, I think you want to create queries and join them in a way that will look like this SQL:
SELECT
t1.Contract_Number
, t1.Contract_Item
, t1.Stream_Type
, t1.Billing_Term
, t1.Bill_Period
, t1.Contract_Term_Amount
, t2.Reference_Document
, t3.Billing_Term
, t3.Bill_Period
, t3.Contract_Term_Amount
, t3.Seq_No
FROM (
SELECT Contract_Number
, Contract_Item
, Stream_Type
, Billing_Term
, Bill_Period
, Contract_Term_Amount
FROM LeasingStreamData
WHERE Contract_Number in ([some list of contracts])
) t1
INNER JOIN (
SELECT Sales_Document
, Reference_Document
FROM ContractsData
WHERE Sales_Document in ([some list of contracts])
) t2 ON t1.Contract_Number = t2.Sales_Document
INNER JOIN LeasingStreamData t3 ON t2.Reference_Document = t3.Contract_Number
AND t1.Contract_Item = t3.Contract_Item
AND t1.Stream_Type = t3.Stream_Type
INNER JOIN (
select max(Seq_No) as Seq_No
, Contract_Number
, Contract_Item
, Stream_Type
from LeasingStreamData lsd
group by Contract_Number
, Contract_Item
, Stream_Type
) maxseq on maxseq.Contract_Number = t3.Contract_Number
and maxseq.Contract Item = t3.Contract_Item
and maxseq.Stream_Type = t3.Stream_Type
and maxseq.Seq_No = t3.Seq_No
WHERE t1.Billing_Term <> t3.Billing_Term
and t1.Bill_Period <> t3.Bill_Period
and t1.Contract_Term_Amount <> t3.Contract_Term_Amount
GROUP BY
t1.Contract_Number
, t1.Contract_Item
, t1.Stream_Type
, t1.Billing_Term
, t1.Bill_Period
, t1.Contract_Term_Amount
, t2.Reference_Document
, t3.Billing_Term
, t3.Bill_Period
, t3.Contract_Term_Amount
, t3.Seq_No
I think this will filter to only the max Seq_No for t3 and return only the records that you care about (the ones that don't match).

Try this:
SELECT t1.Contract_Number
,t1.Contract_Item
,t1.Stream_Type
,t1.Billing_Term
,t1.Bill_Period
,t1.Contract_Term_Amount
,t2.Reference_Document
,t3.Billing_Term
,t3.Bill_Period
,t3.Contract_Term_Amount
,t3.Seq_No
FROM LeasingStreamData t1
INNER JOIN ContractsData t2 ON t1.Contract_Number = t2.Sales_Document
LEFT JOIN (
SELECT Contract_Number
,Contract_Item
,Stream_type
,MAX(Seq_No) AS "Seq_No"
FROM LeasingStreamData
GROUP BY Contract_Number
,Contract_Item
,Stream_Type
) t3 ON t2.Reference_Document = t3.Contract_Number
AND t1.Contract_Item = t3.Contract_Item
AND t1.Stream_Type = t3.Stream_Type
WHERE t1.Contract_Number IN ([some list of contracts])
Since the rollup for the aggregate function (MAX) relies on the group by to determine context, you have to isolate it via a subquery to get the max before joining to the rest of the tables.
Also, since you are preaggregating the max sequence number, you no longer need a group by in the main query.

Related

Join 2 oracle queries

someone, please help to join the below queries.
I have tried my best but not able to join with the condition.
PLN_ID is the common column on both the tables.
Query 1-
SELECT PLN_ID
, ASSORTMENT_GROUP
, STORE
, PLANOGRAM
, STATUS
FROM ACN_PLANOGRAMS
WHERE PLANOGRAM not like '%<Untitled>%'
;
​
Query 2
SELECT distinct(PLN_ID)
, count(*)
, (sum(WIDTH)) AS width
FROM ACN_FIXEL
WHERE type='0'
GROUP BY PLN_ID
HAVING count(*) > 1
;
Please changes join what you want you. Try this query:
SELECT
DISTINCT(a.PLN_ID),
(SUM(a.WIDTH)) AS width,
b.PLN_ID,
b.ASSORTMENT_GROUP,
b.STORE,
b.PLANOGRAM,
b.STATUS
FROM
ACN_FIXEL a
INNER JOIN
ACN_PLANOGRAMS b ON a.PLN_ID = b.PLN_ID
WHERE
a.type = '0'
AND b.PLANOGRAM NOT LIKE '%<Untitled>%'
GROUP BY
a.PLN_ID,
b.PLN_ID,
b.ASSORTMENT_GROUP,
b.STORE,
b.PLANOGRAM,
b.STATUS
HAVING
COUNT(*) > 1
There are several ways to solve this. Without understanding your data model or business logic I offer the simplest solution, a derived table (inline view):
SELECT p.PLN_ID
, p.ASSORTMENT_GROUP
, p.STORE
, p.PLANOGRAM
, p.STATUS
, f.fixel_count
, f.fixel_width
FROM ACN_PLANOGRAMS p
inner join (SELECT PLN_ID
, count(*) as fixel_count
, (sum(WIDTH)) AS fixel_width
FROM ACN_FIXEL
WHERE type='0'
GROUP BY PLN_ID
HAVING count(*) > 1 ) f
on f.pln_id = p.pln_id
WHERE p.PLANOGRAM not like '%<Untitled>%'
;
This solution only returns results for PLN_ID in both result sets. If you have a different logic you may need to use LEFT OUTER JOIN instead.
Make Query 2 a subquery:
SELECT ap.PLN_ID
, ap.ASSORTMENT_GROUP
, ap.STORE
, ap.PLANOGRAM
, ap.STATUS
, sq.cnt
, sq.width
FROM ACN_PLANOGRAMS ap
JOIN (
SELECT PLN_ID
, count(*) AS cnt
, sum(WIDTH) AS width
FROM ACN_FIXEL
WHERE type='0'
GROUP BY PLN_ID
HAVING count(*) > 1
) sq
ON ( sq.PLN_ID = ap.PLN_ID )
WHERE ap.PLANOGRAM not like '%<Untitled>%'
;

How do I change this sql statement to only select the first from each ID?

I have the below code to select from a database, however, I only want the first record for each unique ID. Is there a way to change the SQL to achieve this?
SELECT
[CARL_Property].ID
,[PrDoorNum]
,[PrAddress1]
,[PrAddress2]
,[PrAddress3]
,[PrAddress4]
,[PrPostcode]
,[PrRent]
,[PrAgreedRent]
,[PrCommence]
,[PrEnd]
,[PrAvailable]
,[PrGrossIncome]
,[PrCouncilTax]
,[PrInventoryFee]
,[PrLetFee]
,[PrReletFee]
,[PrDateWithdrawn]
,[Rent Review]
,CARL_Owners.OwForenames
,CARL_Owners.OwSurname
,CARL_Property_List.[ID]
,CARL_Property_List.[PrId]
,CARL_Property_List.[PLBedrooms]
,CARL_Property_List.[PlRooms]
,CARL_Property_List.[PlBathrooms]
,CARL_Property_List.[PlReceptions]
,CARL_Property_List.[PlDeposit]
,CARL_Tenant_Contacts.[Tenant Name]
,CARL_New_Tenants.[TnLeaseperiod]
,CARL_Property_List.[PlAdvertising]
,[CARL_Property_Memos].[PrNotes]
,[CARL_Safety].[PrGasInsp]
from dbo.CARL_Property Join dbo.[CARL_Property_Memos] on CARL_Property.ID=CARL_Property_Memos.PrID Join dbo.CARL_Owners on CARL_Owners.ID=CARL_Property.OwID Join dbo.CARL_PROPERTY_LIST ON dbo.CARL_PROPERTY.ID=dbo.CARL_PROPERTY_LIST.PrId Join dbo.[CARL_New_Tenants] ON CARL_New_Tenants.PrId=CARL_Property.ID JOIN CARL_Tenant_Contacts ON CARL_New_Tenants.ID = CARL_Tenant_Contacts.TnID Join [dbo].[CARL_Safety] On dbo.CARL_Property.ID=dbo.CARL_Safety.PrID
The result is as seen below.
Something along these lines I think is what you are looking for. Also, notice that I used aliases in your main query. It makes this a lot simpler to work with and reduces the amount of typing by a LOT.
with SortedResults as
(
SELECT
cp.ID
, ROW_NUMBER() over(partition by cp.ID order by pl.ID) as RowNum --order by whatever column defines "first"
, [PrDoorNum]
, [PrAddress1]
, [PrAddress2]
, [PrAddress3]
, [PrAddress4]
, [PrPostcode]
, [PrRent]
, [PrAgreedRent]
, [PrCommence]
, [PrEnd]
, [PrAvailable]
, [PrGrossIncome]
, [PrCouncilTax]
, [PrInventoryFee]
, [PrLetFee]
, [PrReletFee]
, [PrDateWithdrawn]
, [Rent Review]
, o.OwForenames
, o.OwSurname
, pl.[ID] as PL_ID
, pl.[PrId]
, pl.[PLBedrooms]
, pl.[PlRooms]
, pl.[PlBathrooms]
, pl.[PlReceptions]
, pl.[PlDeposit]
, tc.[Tenant Name]
, nt.[TnLeaseperiod]
, pl.[PlAdvertising]
, pm.[PrNotes]
, cs.[PrGasInsp]
from dbo.CARL_Property p
Join dbo.[CARL_Property_Memos] pm on p.ID = pm.PrID
Join dbo.CARL_Owners o on o.ID = p.OwID
Join dbo.CARL_PROPERTY_LIST pl ON p.ID = pl.PrId
Join dbo.[CARL_New_Tenants] nt ON nt.PrId = p.ID
JOIN CARL_Tenant_Contacts tc ON nt.ID = tc.TnID
Join [dbo].[CARL_Safety] cs On p.ID = cs.PrID
)
select *
from SortedResults
where RowNum = 1
order by ID

SQL Query to get only 1 instance of a record where one to many relationship exists

Ive got an SQL Query trying to get 1 record back when a 1 to many relationship exists.
SELECT dbo.BlogEntries.ID AS blog_entries_id, dbo.BlogEntries.BlogTitle, dbo.BlogEntries.BlogEntry, dbo.BlogEntries.BlogName,
dbo.BlogEntries.DateCreated AS blog_entries_datecreated, dbo.BlogEntries.inActive AS blog_entries_in_active,
dbo.BlogEntries.HtmlMetaDescription AS blog_entries_html_meta_description, dbo.BlogEntries.HtmlMetaKeywords AS blog_entries_html_meta_keywords,
dbo.BlogEntries.image1, dbo.BlogEntries.image2, dbo.BlogEntries.image3, dbo.BlogEntries.formSelector, dbo.BlogEntries.image1Alignment,
dbo.BlogEntries.image2Alignment, dbo.BlogEntries.image3Alignment, dbo.BlogEntries.blogEntryDisplayName, dbo.BlogEntries.published AS blog_entries_published,
dbo.BlogEntries.entered_by, dbo.BlogEntries.dateApproved, dbo.BlogEntries.approved_by, dbo.blog_entry_tracking.id AS blog_entry_tracking_id,
dbo.blog_entry_tracking.blog, dbo.blog_entry_tracking.blog_entry, dbo.BlogCategories.ID, dbo.BlogCategories.BlogCategoryName,
dbo.BlogCategories.BlogCategoryComments, dbo.BlogCategories.DateCreated, dbo.BlogCategories.BlogCategoryTitle, dbo.BlogCategories.BlogCategoryTemplate,
dbo.BlogCategories.inActive, dbo.BlogCategories.HtmlMetaDescription, dbo.BlogCategories.HtmlMetaKeywords, dbo.BlogCategories.entry_sort_order,
dbo.BlogCategories.per_page, dbo.BlogCategories.shorten_page_content, dbo.BlogCategories.BlogCategoryDisplayName, dbo.BlogCategories.published,
dbo.BlogCategories.blogParent
FROM dbo.BlogEntries LEFT OUTER JOIN
dbo.blog_entry_tracking ON dbo.BlogEntries.ID = dbo.blog_entry_tracking.blog_entry LEFT OUTER JOIN
dbo.BlogCategories ON dbo.blog_entry_tracking.blog = dbo.BlogCategories.ID
i have some records assigned to 2 different blogcategories, and when i query everything it returns duplicate records.
How do i only return 1 instance of a blog?
Try this one -
SELECT blog_entries_id = be.Id
, be.BlogTitle
, be.BlogEntry
, be.BlogName
, blog_entries_datecreated = be.DateCreated
, blog_entries_in_active = be.inActive
, blog_entries_html_meta_description = be.HtmlMetaDescription
, blog_entries_html_meta_keywords = be.HtmlMetaKeywords
, be.image1
, be.image2
, be.image3
, be.formSelector
, be.image1Alignment
, be.image2Alignment
, be.image3Alignment
, be.blogEntryDisplayName
, blog_entries_published = be.published
, be.entered_by
, be.dateApproved
, be.approved_by
, blog_entry_tracking_id = bet.Id
, bet.blog
, bet.blog_entry
, bc2.Id
, bc2.BlogCategoryName
, bc2.BlogCategoryComments
, bc2.DateCreated
, bc2.BlogCategoryTitle
, bc2.BlogCategoryTemplate
, bc2.inActive
, bc2.HtmlMetaDescription
, bc2.HtmlMetaKeywords
, bc2.entry_sort_order
, bc2.per_page
, bc2.shorten_page_content
, bc2.BlogCategoryDisplayName
, bc2.published
, bc2.blogParent
FROM dbo.BlogEntries be
LEFT JOIN dbo.blog_entry_tracking bet ON be.Id = bet.blog_entry
OUTER APPLY (
SELECT TOP 1 *
FROM dbo.BlogCategories bc
WHERE bet.blog = bc.Id
) bc2
Also, I would like to mention that in this case, using of aliases in the column names decreases the size of your query and makes it more convenient for understanding.
if you just need one record back, you can use
SELECT TOP 1 dbo.BlogEntries.ID AS blog_entries_id, dbo.Bl.... (same as you have now).
it is more efficient than SELECT DISTINCT
Here is a Northwind Example.
It will return only 1 row in the Order Detail table for each Order.
Use Northwind
GO
Select COUNT(*) from dbo.Orders
select COUNT(*) from dbo.[Order Details]
select * from dbo.Orders ord
join
(select ROW_NUMBER() OVER(PARTITION BY OrderID ORDER BY UnitPrice DESC) AS "MyRowID" , * from dbo.[Order Details] innerOD) derived1
on ord.OrderID = derived1.OrderID
Where
derived1.MyRowID = 1
Order by ord.OrderID

How do I remove duplicate results by looking for max date?

I know I have duplicate results from this query because the tables ReleaseHistory and IterationHistory have multiple records per ReleaseID and IterationID. I would like to only select the records with max date from dbo.ReleaseHistory and dbo.IterationHistory. How would I do that in this query? SQL SERVER 2008
SELECT dbo.Assignable.AssignableID AS ID,
dbo.EntityType.Abbreviation AS Entity,
dbo.General.Name, dbo.Assignable.Effort,
dbo.Assignable.EffortCompleted,
dbo.Assignable.EffortToDo,
dbo.EntityState.Name AS State,
dbo.ReleaseHistory.Name AS Release,
dbo.IterationHistory.Name AS Iteration,
dbo.General.CustomField3 AS [Scrum Team]
FROM dbo.Assignable INNER JOIN
dbo.General ON dbo.Assignable.AssignableID =
dbo.General.GeneralID INNER JOIN
dbo.EntityType ON dbo.General.EntityTypeID =
dbo.EntityType.EntityTypeID INNER JOIN
dbo.EntityState ON dbo.Assignable.EntityStateID =
dbo.EntityState.EntityStateID AND
dbo.EntityType.EntityTypeID =
dbo.EntityState.EntityTypeID INNER JOIN
dbo.ReleaseHistory ON dbo.Assignable.ReleaseID =
dbo.ReleaseHistory.ReleaseID INNER JOIN
dbo.IterationHistory ON
dbo.Assignable.IterationID =
dbo.IterationHistory.IterationID LEFT OUTER JOIN
dbo.CustomField ON dbo.General.CustomField3 =
dbo.CustomField.CustomFieldID
WHERE (dbo.Assignable.ProjectID = 4054)
GROUP BY dbo.Assignable.AssignableID,
dbo.EntityType.Abbreviation,
dbo.General.Name,
dbo.Assignable.Effort,
dbo.Assignable.EffortCompleted,
dbo.Assignable.EffortToDo,
dbo.EntityState.Name,
dbo.ReleaseHistory.Name,
dbo.IterationHistory.Name,
dbo.General.CustomField3
Brian,
I am amusing you are doing this in MS SQL and there will always be at least one record in ReleaseHistory and IterationHistory tables. If assumptions are correct then you can simply use CROSS APPLY to get top 1 record from both tables.
SELECT
dbo.Assignable.AssignableID AS ID ,
dbo.EntityType.Abbreviation AS Entity ,
dbo.General.Name ,
dbo.Assignable.Effort ,
dbo.Assignable.EffortCompleted ,
dbo.Assignable.EffortToDo ,
dbo.EntityState.Name AS State ,
Release ,
Iteration ,
dbo.General.CustomField3 AS [Scrum Team]
FROM
dbo.Assignable
INNER JOIN dbo.General ON dbo.Assignable.AssignableID = dbo.General.GeneralID
INNER JOIN dbo.EntityType ON dbo.General.EntityTypeID = dbo.EntityType.EntityTypeID
INNER JOIN dbo.EntityState ON dbo.Assignable.EntityStateID = dbo.EntityState.EntityStateID
AND dbo.EntityType.EntityTypeID = dbo.EntityState.EntityTypeID
CROSS APPLY( SELECT TOP 1 name Release FROM ReleaseHistory WHERE ReleaseID = Assignable.ReleaseID ORDER BY MaxDateColumn) a
CROSS APPLY( SELECT TOP 1 name Iteration FROM IterationHistory WHERE IterationID = Assignable.IterationID ORDER BY MaxDateColumn) b
LEFT OUTER JOIN dbo.CustomField ON dbo.General.CustomField3 = dbo.CustomField.CustomFieldID
WHERE
( dbo.Assignable.ProjectID = 4054 )
GROUP BY
dbo.Assignable.AssignableID ,
dbo.EntityType.Abbreviation ,
dbo.General.Name ,
dbo.Assignable.Effort ,
dbo.Assignable.EffortCompleted ,
dbo.Assignable.EffortToDo ,
dbo.EntityState.Name ,
dbo.ReleaseHistory.Name ,
dbo.IterationHistory.Name ,
dbo.General.CustomField3

PIVOT'ing in SQL server

I have the below query whcih I want to pivot.
SELECT
tbl_track_empHours.track_empHours_hours as emphours
,tbl_track_empHours.track_empHours_date as empHDate
, tbl_track_jobInfo.track_jobInfo_jobNum AS JobNum
, tbl_track_jobInfo.track_jobInfo_ProjName AS ProjName
, tbl_track_jobCodes.track_jobCode_jc AS jc
, tbl_track_jobCodes.track_jobCode_id_pk AS ts_JobCodeID
, tbl_track_empHours.track_empHours_main_usr_id_fk
, tbl_track_jobInfo.track_jobInfo_id_pk AS ts_JobID
FROM tbl_track_empHours INNER JOIN
tbl_track_jobInfo ON tbl_track_empHours.track_empHours_jobinfo_id_fk=tbl_track_jobInfo.track_jobInfo_id_pk INNER JOIN
tbl_track_jobCodes ON tbl_track_empHours.track_empHours_jobCode_id_fk = tbl_track_jobCodes.track_jobCode_id_pk
WHERE (tbl_track_empHours.track_empHours_main_usr_id_fk = '268')
AND (tbl_track_empHours.track_empHours_date BETWEEN '05/09/2011' AND '05/15/2011')
ORDER BY tbl_track_jobInfo.track_jobInfo_jobNum, tbl_track_jobCodes.track_jobCode_jc!
The result looks like this.
I want to pivot the column 'emphours' against the rest of the columns. The pivoted columns should have the dates between '05/09/2011' AND '05/15/2011'
Any help appreciated.
Pivot result
This could help you for sure.
Select * from (Select JobNum,ProjName,jc,ts_JobCodeID,mainUsrFk,ts_JobID,
[05/09/2011] as col1,[05/11/2011] as col2,[05/12/2011] as col3,
[05/13/2011] as col4,[05/14/2011] as col5,[05/15/2011] as col6,[05/10/2011] as col7 from (
SELECT
tbl_track_empHours.track_empHours_hours
,tbl_track_empHours.track_empHours_date
, tbl_track_jobInfo.track_jobInfo_jobNum AS JobNum
, tbl_track_jobInfo.track_jobInfo_ProjName AS ProjName
, tbl_track_jobCodes.track_jobCode_jc AS jc
, tbl_track_jobCodes.track_jobCode_id_pk AS ts_JobCodeID
, tbl_track_empHours.track_empHours_main_usr_id_fk as mainUsrFk
, tbl_track_jobInfo.track_jobInfo_id_pk AS ts_JobID
FROM tbl_track_empHours INNER JOIN
tbl_track_jobInfo ON tbl_track_empHours.track_empHours_jobinfo_id_fk = tbl_track_jobInfo.track_jobInfo_id_pk INNER JOIN
tbl_track_jobCodes ON tbl_track_empHours.track_empHours_jobCode_id_fk = tbl_track_jobCodes.track_jobCode_id_pk
WHERE (tbl_track_empHours.track_empHours_main_usr_id_fk = '268')
AND (tbl_track_empHours.track_empHours_date BETWEEN '5/09/2011' AND '5/15/2011')
) o
PIVOT( SUM(o.track_empHours_hours)
FOR o.track_empHours_date in ([05/09/2011],[05/10/2011],[05/11/2011],[05/12/2011],
[05/13/2011],[05/14/2011],[05/15/2011]))p ) as a