Join 2 oracle queries - sql

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>%'
;

Related

JOIN a table with a grouped by table

I have two tables i am trying to join and do a count on, basically to bring over the date onto the Units table. The problem is that the intakes table has duplicates.
SELECT
Units.Clinic,
Units.display_id,
INTAKES.initial_intake_date,
COUNT(case_note_type_desc) AS CountOfUAs
FROM Units
LEFT JOIN (SELECT display_id,Clinic,initial_intake_date
FROM factIntakesAndDischarges
GROUP BY display_id,Clinic,initial_intake_date ) INTAKES
ON Units.display_id = INTAKES.display_id
AND Units.display_id = INTAKES.Clinic
WHERE casenotes_date BETWEEN '4/9/20' AND '5/9/20'
AND case_note_type_desc = '(UA)'
GROUP BY Units.Clinic,
Units.display_id,
INTAKES.initial_intake_date
ORDER BY CountOfUAs desc,Clinic,display_id,initial_intake_date
This gives me the correct count, but the initial_intake_date comes back NULL. The other join i tried gave me the correct initial_intake_date, but the count was off.
Based on your, I would really expect a query more like this:
SELECT u.Clinic, u.display_id, MIN(i.initial_intake_date) as initial_intake_date,
COUNT(*) AS CountOfUAs
FROM Units u LEFT JOIN
factIntakesAndDischarges fid
ON u.display_id = i.display_id AND
u.display_id = INTAKES.display_id
WHERE u.casenotes_date >= '2020-04-09' AND '2020-05-09' AND
u.case_note_type_desc = '(UA)'
GROUP BY u.Clinic, u.display_id,
ORDER BY CountOfUAs desc, Clinic, display_id, initial_intake_date;
Even if the numbers are not quite right, this is a simpler query for starting to fix.
ON Units.display_id = INTAKES.display_id
AND Units.display_id = INTAKES.Clinic
OR
ON Units.display_id = INTAKES.display_id
AND Units.Clinic = INTAKES.Clinic
WITH UnitsTable AS
(
SELECT
Clinic
, display_id
, CountOfUAs = COUNT(case_note_type_desc)
FROM Units
)
, IntakesTable AS
(
SELECT
display_id
, Clinic
, initial_intake_date
FROM factIntakesAndDischarges
-- I am asuming casenotes_date and casenotes_type_Desc belong to Intakes
-- If not, move this WHERE to UnitsTable above
WHERE
casenotes_date BETWEEN '4/9/20' AND '5/9/20'
AND case_note_type_desc = '(UA)'
GROUP BY
display_id
, Clinic
, initial_intake_date
)
SELECT
U.Clinic
, U.display_id
, I.initial_intake_date
, U.CountOfUAs
FROM UnitsTable U
JOIN IntakesTable I ON I.Display_ID = U.Display_ID
AND I.Clinic = U.Clinic
ORDER BY
U.CountOfUAs desc
, U.Clinic
, U.display_id
, I.initial_intake_date

Recursive CTE and SELECT

I have written a fairly simple recursive CTE statement. The purpose is that it looks up a structure and returns the top level item
Here is the code
WITH cte_BOM(parent_serial_id, serial_id, serial_batch_no, sort)
AS (SELECT BOM.parent_serial_id, BOM.serial_id, p.serial_batch_no, 1
FROM serial_status AS BOM
INNER JOIN item_serial_nos p ON BOM.parent_serial_id = p.serial_id
WHERE BOM.serial_id = '16320' AND BOM.is_current = 'Y'
UNION ALL
SELECT
BOM1.parent_serial_id, bom1.serial_id, p1.serial_batch_no, cte_BOM.sort + 1
FROM cte_BOM
INNER JOIN serial_status AS BOM1 ON cte_BOM.parent_serial_id =
BOM1.serial_id
INNER JOIN item_serial_nos p1 ON BOM1.parent_serial_id = p1.serial_id
WHERE BOM1.is_current = 'Y'
)
SELECT TOP 1
cte_BOM.*
FROM
cte_BOM
ORDER BY sort desc
As you can see I just hard code the serial_id at the moment. What I now need to accomplish is to run this cte against a subset of data. I’m now stuck on how I can do this.
So I would produce a list of serial_ids by means of another select statement, and then for each row use this serial_id in place of the ones that is currently hard coded and return the 1st record. Importantly if a serial_id has no parent that should still return a row
The second SELECT would be this:
SELECT serial_id
FROM
item_serial_nos
WHERE
item_serial_nos.item_id = '15683'
Any suggestions appreciated. (using SQL 2008 R2)
If I understand your goal correctly, you can just remove the hardcoded serial_id from the cte and add the start serial_id:
WITH cte_BOM(parent_serial_id, serial_id, serial_batch_no, sort, Original_Serial_id)
AS (
SELECT BOM.parent_serial_id
, BOM.serial_id
, p.serial_batch_no
, 1
, BOM.serial_id
FROM serial_status AS BOM
INNER JOIN item_serial_nos p
ON BOM.parent_serial_id = p.serial_id
WHERE BOM.is_current = 'Y'
UNION ALL
SELECT BOM1.parent_serial_id
, bom1.serial_id
, p1.serial_batch_no
, cte_BOM.sort + 1
, cte_BOM.Original_Serial_id
FROM cte_BOM
INNER JOIN serial_status AS BOM1
ON cte_BOM.parent_serial_id = BOM1.serial_id
INNER JOIN item_serial_nos p1
ON BOM1.parent_serial_id = p1.serial_id
WHERE BOM1.is_current = 'Y'
)
SELECT cte_BOM.*
FROM cte_BOM
INNER JOIN (
SELECT cte_BOM.Original_Serial_id
, MAX(sort) sort_max
FROM cte_BOM
WHERE cte_BOM.Original_Serial_id IN (
SELECT serial_id
FROM item_serial_nos
WHERE item_serial_nos.item_id = '15683'
)
GROUP BY cte_BOM.Original_Serial_id
) max_cte
ON max_cte.Original_Serial_id = cte_BOM.Original_Serial_id
AND max_cte.sort_max = cte_BOM.sort
The recursive CTE is only executed when it's called from the last select, so it is only executed for those records that are selected in the IN query. So you shouldn't suffer a performance hit because of this.

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

Joining reports

I am trying to join 3 reports into one, taking parts out of each report.
This is my script that works with 2 of the reports:
ALTER VIEW [dbo].[v_JB2] AS
SELECT R.*, I.ENTERED, I.PROBLEM_CODE, I.WORKORDER
FROM DALE.DBO.V_JBTRB R
JOIN REPORTS.DBO.V_TC_ANALYSIS_JEREMY I
ON R.HUBID = I.HUB
AND R.NODEID = I.NODE
AND CAST(R.CREATE_DATE AS DATE) = I.ENTERED_DATE
GO
and I want to add this field A.CREATE_DATE-O.ACTUAL_START_DATE AS ASSIGN_SECS from what should be DALE.DBO.V_MTTA
Your join of DALE.DBO.V_MTTA has no ON condition...
Try this:
SELECT R.*, I.ENTERED, I.PROBLEM_CODE, I.WORKORDER,
A.CREATE_DATE-O.ACTUAL_START_DATE as ASSIGN_SECS
FROM
DALE.DBO.V_JBTRB R JOIN
REPORTS.DBO.V_TC_ANALYSIS_JEREMY I
ON R.HUBID = I.HUB AND R.NODEID = I.NODE AND
CAST(R.CREATE_DATE AS DATE) = I.ENTERED_DATE
JOIN DALE.DBO.V_MTTA A ON A.CREATE_DATE-O.ACTUAL_START_DATE = ??? (what do you want this to be joined on? I don't know how your tables are related, but you need a valid ON statement for this join to work)
so the right answer was and i don't think anyone would have been able to tell based on the code was instead of joining a third query i added to my trb query and got the same data not sure why i didn't think of it sooner.
ALTER VIEW [dbo].[v_JBTRB] AS
SELECT SINGLE_USER, RECORD_ID, DIVISION, CREATE_DATETIMEINNEW, OUTAGESTARTDATE, STATUS_DESC, CAST(HUBID AS VARCHAR(255)) AS HUBID, CAST(NODEID AS VARCHAR(255)) AS NODEID, CATEGORY, STATUS, ASSIGN_SECS
FROM OPENQUERY(REMEDY_BI,
'
SELECT
T.RECORD_ID AS Record_ID
, T.DIVISION AS Division
, T.CREATE_DATE_ET AS Create_Date
, T.TIME_IN_NEW AS TimeInNew
, O.ACTUAL_START_DATE_ET AS OutageStartDate
, T.STATUS_DESC
, T.FACILITY AS HubID
, T.NODE AS NodeID
, T.CATEGORY
, T.STATUS
, T.SINGLE_USER
, T.CREATE_DATE-O.ACTUAL_START_DATE AS ASSIGN_SECS
FROM ARNEUSER.VW_BASE_TROUBLE T
JOIN ARNEUSER.VW_BASE_OUTAGE O
ON O.INSTANCE_ID = T.OUTAGE_INSTANCE_ID
AND O.SUBMITTED_BY = T.SUBMITTER
JOIN ARNEUSER.VW_BASE_TROUBLE_TKT_ASGN_HIS A
ON A.TROUBLE_ID = T.TROUBLE_ID
AND A.CREATE_DATE = ( SELECT MIN(CREATE_DATE)
FROM ARNEUSER.VW_BASE_TROUBLE_TKT_ASGN_HIS
WHERE TROUBLE_ID=T.TROUBLE_ID
AND STATUS_NUM=1
AND CREATE_DATE>=O.ACTUAL_START_DATE
AND SUBMITTER=T.SUBMITTER )
WHERE T.STATUS > 3
AND T.REGION = ''Carolina''
AND T.CREATE_DATE >= DATE_TO_UNIX_TZ(TRUNC(SYSDATE)-14)
AND T.CATEGORY IN (''HFC'',''CRITICAL INFRASTRUCTURE'',''VIDEO DIGITAL'',''VIDEO ANALOG'',''DIGITAL PHONE'',''HEADEND/HUB'',''METRO/REGIONAL NETWORK'',''NATIONAL BACKBONE'',''NETWORK'')
')
I added this part the rest was already there if that helps this is one of the reports i was originally joining. I was trying to join another report but it came from the same data base.
, T.CREATE_DATE-O.ACTUAL_START_DATE AS ASSIGN_SECS
AND A.CREATE_DATE = ( SELECT MIN(CREATE_DATE)
FROM ARNEUSER.VW_BASE_TROUBLE_TKT_ASGN_HIS
WHERE TROUBLE_ID=T.TROUBLE_ID
AND STATUS_NUM=1
AND CREATE_DATE>=O.ACTUAL_START_DATE
AND SUBMITTER=T.SUBMITTER )
this is the other query that was being joined for anyone curious the 8 **** replace some sensitive data
ALTER VIEW [dbo].[v_TC_ANALYSIS_JEREMY] AS
SELECT *, cast(entered_date + ' ' + entered_time as datetime) as ENTERED FROM OPENQUERY(ICOMS_H,'
SELECT
W.WONUM AS WORKORDER,
W.WOTYC AS TYPE,
CVGDT2DATE(W.WOEDT) AS ENTERED_DATE,
W.WOQCD AS QUEUE_CODE,
W.WOETM AS TIME_ENTERED,
W.WOPB1 AS PROBLEM_CODE,
TRIM(H.HOAAEQ) AS HUB,
TRIM(H.HONODE) AS NODE,
H.HOZIP5 AS ZIPCODE,
W.WOPOL AS POOL,
P.EXTXD0 AS AREA,
CVGTM2TIME(W.WOETM) AS ENTERED_TIME
FROM
********.WOMHIPF W
JOIN ******.HOSTPF H ON H.HONUM = W.WOHNUM
JOIN CF83PF P ON P.EXPLLL = W.WOPOL
WHERE
W.WOEDT >= REPLACE(CHAR(CURRENT_DATE - 14 DAYS,ISO),''-'','''')-19000000
AND ((WOTYC =''SR'' AND WOQCD IN (''O'',''M'')) OR (WOTYC =''TC''))
AND WOPOL IN (''1'',''2'',''3'',''4'',''6'',''7'',''E'',''M'',''R'')

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