Left outer join multiple selects - sql

I have the following sql statement, that does exactly what it should:
select C.Company_RecID, C.Contact_RecID, C.First_Name, C.Last_Name,
C.Title, C.Inactive_Flag, e.Description
FROM dbo.Contact AS C
LEFT OUTER JOIN dbo.Contact_Communication AS e ON C.Contact_RecID = e.Contact_RecID
AND e.Communication_Type_RecID = 1 AND e.Default_Flag = 1
However, in dbo.contact_communication, the description field means different things depending upon the communication_type_recID. If it's 1, description is an email address. If it's 4, it's a cell phone number, if it's 2, it's a direct number, and if it's 14, it's a personal cell phone number.
I'd like to change the query to return three additional columns. Column 8 would be the value of description if there is a record for this contact with a recid of 4, column 9 the value of description if there is a record for this contact with a recid of 2, and column 10 if there is a value of 14.

Something like this should be pretty close as I understand what you are looking for.
select C.Company_RecID
, C.Contact_RecID
, C.First_Name
, C.Last_Name
, C.Title
, C.Inactive_Flag
, e.Description
, EmailAddress = MAX(case when communication_type_recID = 1 then e.Description end)
, CellPhone = MAX(case when communication_type_recID = 4 then e.Description end)
, DirectNumber = MAX(case when communication_type_recID = 2 then e.Description end)
, PersonalCellPhone = MAX(case when communication_type_recID = 14 then e.Description end)
FROM dbo.Contact AS C
LEFT OUTER JOIN dbo.Contact_Communication AS e ON C.Contact_RecID = e.Contact_RecID
AND e.Communication_Type_RecID IN (1,2,4,14)
AND e.Default_Flag = 1
group by C.Company_RecID
, C.Contact_RecID
, C.First_Name
, C.Last_Name
, C.Title
, C.Inactive_Flag
, e.Description

I think UNION might help you. (https://learn.microsoft.com/en-us/sql/t-sql/language-elements/set-operators-union-transact-sql?view=sql-server-2017)
You can try something like this:
select col_1, 'something' as A, '' as B from TableA
union
select col_2, '' as A, 'something' as B from TableA
col_1 and col_2 are actual columns in the table, while A and B are aliases for this extra information.

Without aggregation
select C.Company_RecID
, C.Contact_RecID
, C.First_Name
, C.Last_Name
, C.Title
, C.Inactive_Flag
, e.Description
, e1.Description as EmailAddress
, e2.Description as CellPhone
, e4.Description as DirectNumber
, e14.Description as PersonalCellPhone
FROM dbo.Contact AS C
LEFT OUTER JOIN dbo.Contact_Communication AS e1
ON e1.Contact_RecID = C.Contact_RecID
AND e1.Communication_Type_RecID = 1
AND e1.Default_Flag = 1
LEFT OUTER JOIN dbo.Contact_Communication AS e2
ON e2.Contact_RecID = C.Contact_RecID
AND e2.Communication_Type_RecID = 2
AND e2.Default_Flag = 1
LEFT OUTER JOIN dbo.Contact_Communication AS e4
ON e4.Contact_RecID = C.Contact_RecID
AND e4.Communication_Type_RecID = 4
AND e4.Default_Flag = 1
LEFT OUTER JOIN dbo.Contact_Communication AS e14
ON e14.Contact_RecID = C.Contact_RecID
AND e14.Communication_Type_RecID = 14
AND e14.Default_Flag = 1

Related

Display Only More Than One Unique Customer/Address Per Truck Number

Been working on a project in which a report will generated from the SQL Query. I wish to display all Shipments (based on unique automatic truck ID) which contain any combination of:
Unique Customers (based on Customer Number, more than one Customer
Number per shipment)
Unique Addresses (based on defined Address Field, more than one unique
Address per shipment)
The output should look like this when the code runs correct:
Truck Customer First Address (other addresses) City State ZIP Country
12345 C12345 567 Hummingbird Lane Detroit MI 48610 US
12345 C12345 908 Elm Street Detroit MI 48611 US
12345 C78901 219 Maple Street Lansing MI 49012 US
Here is a sample of the code I been trying to tease out this information:
WITH cte
AS (SELECT DISTINCT shp.shipmentID
, ven.CustomerCode
, ven.CustomerName
, ads.FirstAddress
, ads.SecondAddress
, ads.ThirdAddress
, ads.City
, ads.State
, ads.Zip
, ads.Country
FROM
dbo.OrderItems AS ori
JOIN dbo.OrderLineProducts AS olns ON olns.olnID = ori.olnID
JOIN dbo.OrderLines AS oln ON oln.olnID = olns.olnID
JOIN dbo.Orders AS ord ON oln.ordID = ord.ordID
JOIN dbo.VendorCustomer AS ven ON ven.venID = ord.venID
JOIN dbo.OrderAddresses AS oa ON oa.ordID = ord.ordID
JOIN dbo.Address AS ads ON ads.addID = oa.addID
JOIN dbo.AddressType AS adst ON adst.atcID = ads.atcID
AND adst.atcAddressTypeCode = N'SHIP'
JOIN dbo.OrderItemShipments AS shpo ON ori.itmID = shpo.itmID
AND ori.itmIDInstance = shpo.itmIDInstance
AND ori.olnID = shpo.olnID
AND ori.olnIDInstance = shpo.olnIDInstance
JOIN dbo.Shipments AS shp ON shp.shipmentID = shpo.shpID
WHERE shpo.shpID = shp.shipmentID
AND ven.venCode IS NOT NULL
)
, maxadd
AS (SELECT
aa.venCode
, MAX(Multadd) AS Multadd
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY cte.shipmentID, cte.CustomerCode ORDER BY cte.shipmentID) Multadd
, cte.shipmentID
, cte.CustomerCode
, cte.CustomerName
, cte.FirstAddress
, cte.SecondAddress
, cte.ThirdAddress
, cte.City
, cte.State
, cte.Zip
, cte.Country
FROM
cte
) AS aa
GROUP BY
aa.CustomerCode
HAVING COUNT (*)>1
)
, maxshp
AS (SELECT
cc.shipmentID
, MAX(cc.Multadd) AS MultVencode
FROM (
SELECT
bb.shipmentID
, bb.CustomerCode
, ROW_NUMBER() OVER (PARTITION BY shipmentID ORDER BY CustomerCode) Multadd
FROM (SELECT DISTINCT cte.shipmentID, cte.CustomerCode FROM cte) AS bb
) AS cc
GROUP BY
cc.shipmentID
HAVING COUNT(*) > 1
)
SELECT
cte.shipmentID
, cte.CustomerCode
, cte.CustomerName
, cte.FirstAddress
, cte.SecondAddress
, cte.ThirdAddress
, cte.City
, cte.State
, cte.Zip
, cte.Country
, maxadd.Multadd AS AddOnShipID
, maxshp.MultVencode AS VenOnShipID
FROM
cte
JOIN maxadd ON maxadd.CustomerCode = cte.CustomerCode
JOIN maxshp ON maxshp.shipmentID = cte.shipmentID
WHERE
(
maxadd.Multadd <> 2
AND maxshp.MultVencode <> 1
)
ORDER BY
cte.shipmentID
, cte.CustomerCode;
This "quasi" works. I have been racking my brain as to why this still is not working. Wondering if a second set of eyes may find something I am overlooking.
SELECT * FROM (SELECT DISTINCT shp.shipmentID
, ven.CustomerCode
, ven.CustomerName
, ads.FirstAddress
, ads.SecondAddress
, ads.ThirdAddress
, ads.City
, ads.State
, ads.Zip
, CASE WHEN(ads.Country LIKE 'US') THEN N'USA' ELSE 'CANADA' END AS Country
, COUNT (shp.shipmentID) OVER (PARTITION BY shipmentID ORDER BY shp.shpID) AS cntshpID
FROM dbo.OrderItems AS ori
JOIN dbo.OrderLineProducts AS olns ON olns.olnID = ori.olnID
JOIN dbo.OrderLines AS oln ON oln.olnID = olns.olnID
JOIN dbo.Orders AS ord ON oln.ordID = ord.ordID
JOIN dbo.VendorCustomer AS ven ON ven.venID = ord.venID
JOIN dbo.OrderAddresses AS oa ON oa.ordID = ord.ordID
JOIN dbo.Address AS ads ON ads.addID = oa.addID
JOIN dbo.AddressType AS adst ON adst.atcID = ads.atcID
AND adst.atcAddressTypeCode = N'SHIP'
JOIN dbo.OrderItemShipments AS shpo ON ori.itmID = shpo.itmID
AND ori.itmIDInstance = shpo.itmIDInstance
AND ori.olnID = shpo.olnID
AND ori.olnIDInstance = shpo.olnIDInstance
JOIN dbo.Shipments AS shp ON shp.shpID = shpo.shipmentID
WHERE shpo.shpID = shp.shipmentID
GROUP BY shp.shipmentID
, ven.CustomerCode
, ven.CustomerName
, ads.FirstAddress
, ads.SecondAddress
, ads.ThirdAddress
, ads.City
, ads.State
, ads.aZip
, ads.Country) AS bb
WHERE bb.cntshpID > 1
ORDER BY shpID ASC
CTE was not the way to go, it overcomplicated something simple.

Oracle Join - Which is faster - using the whole table or a subquery that has specific columns needed in the table?

I am really new into optimizing queries. Could you please advise which INNER JOIN runs faster?
Please note that i am using two different ways of inner join syntax(have same # of records)
1.) INNER JOIN of subqueries that have DISTINCT and selected columns only from its respective table
select
fac.fac_id ,
dept.dept_id ,
wk.week_id ,
sum(case when TRIM(fpl.MEASURE) like '%Salar%Wage%' then DATAVALUE else 0 end) WAGES_AMT,
sum(case when TRIM(fpl.MEASURE) like '%Tot%Man%hour%Ret%' then DATAVALUE else 0 end) MANHRS_QTY,
fpl.md_cycle_nbr ,
fpl.md_load_dt
from
EAS_STG.FPA_PLAN_LABOR fpl
INNER JOIN
(
select distinct(dept_nbr), dept_id
from department_D
where regexp_instr( Dept_nbr,'([^0-9])') = 0
) dept
ON TO_NUMBER(TRIM( 'D' FROM fpl.department)) = TO_NUMBER(dept.dept_nbr)
INNER JOIN
(
select distinct(FAC.FAC_NBR), fai.fac_id
from FACILITY_D fac, FACILITY_ALTERNATE_ID fai
where fac.fac_id = fai.fac_id
and fac.company_id = 1101
) fac
ON TRIM(REPLACE(fpl.facility, 'Fac-')) = fac.fac_nbr
INNER JOIN
(
select distinct(wk_hierarchy_id) week_id from DAY_HIERARCHY_D
) wk ON TO_NUMBER(TRIM(REPLACE(fpl.scenario, 'Plan ')) || TRIM(REPLACE(fpl.time, 'Wk '))) = WK.week_id
GROUP BY
fac.fac_id ,
dept.dept_id ,
wk.week_id ,
fpl.md_cycle_nbr ,
fpl.md_load_dt
;
2.) INNER JOIN of the whole table without the selected columns
SELECT fac.fac_id
, dept.dept_id
, d.wk_hierarchy_id week_id
, SUM(CASE WHEN TRIM(fpl.MEASURE) LIKE '%Salar%Wage%' THEN datavalue ELSE 0 END) WAGES_AMT
, SUM(CASE WHEN TRIM(fpl.MEASURE) LIKE '%Tot%Man%hour%Ret%' THEN datavalue ELSE 0 END) MANHRS_QTY
, fpl.md_cycle_nbr
, fpl.md_load_dt
FROM EAS_STG.FPA_PLAN_LABOR fpl
JOIN department_d dept
ON TO_NUMBER(TRIM( 'D' FROM fpl.department)) = TO_NUMBER(dept.dept_nbr)
JOIN facility_d fac
ON TRIM(REPLACE(fpl.facility, 'Fac-')) = fac.fac_nbr
JOIN facility_alternate_id fai
ON fac.fac_id = fai.fac_id
JOIN day_hierarchy_d d
ON TO_NUMBER(TRIM(REPLACE(fpl.scenario, 'Plan ')) || TRIM(REPLACE(fpl.time, 'Wk '))) = d.wk_hierarchy_id
WHERE fac.company_id = 1101
AND REGEXP_INSTR(dept_nbr,'([^0-9])') = 0
GROUP BY fac.fac_id
, dept.dept_id
, d.wk_hierarchy_id
, fpl.md_cycle_nbr
, fpl.md_load_dt
;

SQL Left Outer Join acting like Inner Join

I am trying to do a left outer join on two tables (well, an inline view and a table).
What I want to happen is to list all the grads (I know there are 3815 DISTINCT Grads) with any of their enrolments (there could be 0 or n enrolments). What I'm getting is only a list of the grads that have enrolments (3649 DISTINCT students). I'm not sure where I'm going wrong with not getting all the rows from the grad 'view' (I don't have create view privs so this is my workaround).
This is my code:
SELECT C.*, D.FREEZE_EVENT, D.ACADEMIC_PERIOD, D.CAMPUS, D.COLLEGE, D.COLLEGE_DESC,D.MAJOR, D.MAJOR_DESC , D.STUDENT_RATE
FROM
(SELECT A.STUDENT_LEVEL_DESC, A.CAMPUS, A.CAMPUS_DESC, A.COLLEGE, A.COLLEGE_DESC, A.MAJOR_DESC, A.MAJOR, A.DEGREE_DESC, A.PERSON_UID, A.ID, A.NAME,
A.OUTCOME_GRADUATION_DATE, A.STATUS, A.GRAD_YEAR, A.TRAINING_LOCATION, B.CITIZENSHIP_TYPE
FROM ACAD_OUTOCME A, PERSON_DETAIL B
WHERE A.STUDENT_LEVEL IN ('02','03') AND A.GRAD_YEAR = '2015' AND A.FREEZE_EVENT = '10TH_SEP2016' AND B.FREEZE_EVENT = '10TH_SEP2016'
AND A.ID = B.ID) C
LEFT OUTER JOIN ACAD_STUDY D ON
C.CAMPUS = D.CAMPUS
AND C.COLLEGE = D.COLLEGE
AND C.MAJOR = D.MAJOR
AND C.PERSON_UID = D.PERSON_UID
WHERE D.FREEZE_EVENT = '10TH_SEP2016'
ORDER BY C.NAME
Any suggestions? I'm using Toad Data Point. I'm also the loan developer at work, so I don't have anyone I can ask to help out with this, and google has failed me.
Thanks!
Move your WHERE condition to the ON condition:
Select C.*
, D.FREEZE_EVENT
, D.ACADEMIC_PERIOD
, D.CAMPUS
, D.COLLEGE
, D.COLLEGE_DESC
, D.MAJOR
, D.MAJOR_DESC
, D.STUDENT_RATE
From (Select A.STUDENT_LEVEL_DESC
, A.CAMPUS
, A.CAMPUS_DESC
, A.COLLEGE
, A.COLLEGE_DESC
, A.MAJOR_DESC
, A.MAJOR
, A.DEGREE_DESC
, A.PERSON_UID
, A.ID
, A.NAME
, A.OUTCOME_GRADUATION_DATE
, A.STATUS
, A.GRAD_YEAR
, A.TRAINING_LOCATION
, B.CITIZENSHIP_TYPE
From ACAD_OUTOCME A
Join PERSON_DETAIL B On A.ID = B.ID
Where A.STUDENT_LEVEL In ('02', '03')
And A.GRAD_YEAR = '2015'
And A.FREEZE_EVENT = '10TH_SEP2016'
And B.FREEZE_EVENT = '10TH_SEP2016'
) C
Left Outer Join ACAD_STUDY D
On C.CAMPUS = D.CAMPUS
And C.COLLEGE = D.COLLEGE
And C.MAJOR = D.MAJOR
And C.PERSON_UID = D.PERSON_UID
And D.FREEZE_EVENT = '10TH_SEP2016'
Order By C.NAME;
The WHERE clause is evaluated after the OUTER JOIN, which would cause it to filter out the NULL records from the LEFT JOIN. So, having the right-hand table of a LEFT JOIN in the WHERE clause will effectively transform the OUTER JOIN into an INNER JOIN.

sql sum() causing doubling of values with left outer join

The left out join on dbo.SalespersonProject is causing the value for TranAmt to double. I need to sum the legit TranAmt for projects, but adding in the left outer join and SalesPerson02, causes a match an incorrect doubling.
SELECT ARDoc.SlsperId AR_Doc_Sls_ID
, CASE
WHEN ARTran.TranType = 'CM' THEN SUM(ARTran.TranAmt) * -1
ELSE SUM(ARTran.TranAmt)
END TranAmt
, MAX(CASE
WHEN SalesCommOrder = 1 THEN SalesPersonId
END) Salesperson01
, MAX(ISNULL(CASE
WHEN SalesCommOrder = 1 THEN Percentage
END, .03)) Commission01
, MAX(CASE
WHEN SalesCommOrder = 2 THEN SalesPersonId
END) Salesperson02
, MAX(CASE
WHEN SalesCommOrder = 2 THEN Percentage
END) Commission02
, PJPROJ.project PJ_ID
, PJPROJ.project_desc PJ_Description
, PJPROJ.slsperid SME
, ARDoc.CustId Cust_ID
, CASE
WHEN RTRIM(ARTran.InvtId) = 'GRAPHICS' THEN 1
WHEN RTRIM(ARTran.InvtID) = 'SERVICE CONTRACT' THEN 2
END InvtID
, RTRIM(ARDoc.CustId) + ' ' + Customer.BillName Cust_ID_Name
, CONVERT( DATE, ARTran.TranDate, 101) Doc_Date
, ARTran.TranType Doc_Type
, ARTran.RefNbr
, PJPROJ.start_date
, SUM(ARTran.ExtCost) ExtCost
, SUM(ARTran.UnitPrice) UnitPrice
, SUM(ARTran.Qty) Qty
, (
SELECT SUM(b.eac_amount) [Budg Rev]
FROM pjptdsum b
INNER JOIN pjacct a ON a.acct = b.acct
AND a.acct_type = 'RV'
WHERE ARDoc.ProjectID = b.project) Budget_Rev
, (
SELECT SUM(b.eac_amount) [Budg Rev]
FROM pjptdsum b
INNER JOIN pjacct a ON a.acct = b.acct
AND a.acct_type = 'EX'
WHERE ARDoc.ProjectID = b.project) Budget_EAC
, so.TotMerch SalesOrderTotal
, Salesperson.Name
, ARTran.PerPost
, PJPROJ.manager2
, PJEMPLOY.emp_name
FROM Testnewgroundapp.dbo.ARDoc ARDoc
INNER JOIN Testnewgroundapp.dbo.ARTran ARTran ON ARDoc.CustId = ARTran.CustId
AND ARDoc.RefNbr = ARTran.RefNbr
AND ARDoc.DocType = ARTran.TranType
INNER JOIN Testnewgroundapp.dbo.Customer Customer ON ARDoc.CustId = Customer.CustId --INNER JOIN #CustomerTab ct
LEFT OUTER JOIN Testnewgroundapp.dbo.Salesperson Salesperson ON ARDoc.SlsperId = Salesperson.SlsperId
LEFT OUTER JOIN Testnewgroundapp.dbo.PJPROJ PJPROJ ON ARDoc.ProjectID = PJPROJ.project
LEFT OUTER JOIN Testnewgroundapp.dbo.PJEMPLOY PJEMPLOY ON PJPROJ.manager2 = PJEMPLOY.employee
LEFT OUTER JOIN (
SELECT h.PerPost
, h.SlsperID
, SUM(h.TotMerch) TotMerch
FROM SOShipHeader H
GROUP BY h.PerPost
, h.SlsperID) so ON ARTran.PerPost = so.PerPost
AND ARDoc.SlsperId = so.SlsperID
LEFT OUTER JOIN TestCommissions.dbo.SalespersonProject SalespersonProject ON SalespersonProject.ProjectId = PJPROJ.project --AND SalespersonProject.SalesPerson_Id = #ApplicationUserID
LEFT OUTER JOIN TestCommissions.dbo.SalesPerson AppSalesPerson ON AppSalesPerson.Id = SalespersonProject.SalesPerson_Id
WHERE
(ARTran.TranType = 'CM'
AND ARTran.DrCr = 'D'
OR ARTran.DrCr = 'C'
AND
(ARTran.TranType = 'CS'
OR ARTran.TranType = 'DM'
OR ARTran.TranType = 'IN'
)
)
AND ARTran.TaskID NOT LIKE '%60850'
AND ARTRan.TaskID NOT LIKE '%60900'
AND ARTran.invtid <> 'TSCINC001'
AND ARTran.TranClass NOT IN ('F', 'N', 'T')
AND ARTran.Acct NOT IN ('2590', '2040', '2037')
AND CONVERT(INT, ARTran.Acct) > 1301
AND CONVERT(INT, ARTran.PerPost) BETWEEN 201504 AND 201504
AND ARTran.Rlsed = 1
AND PJPROJ.project IS NOT NULL
AND artran.cpnyid IN ('R', 'A')
GROUP BY ARDoc.SlsperId
, ARDoc.ProjectID
, PJPROJ.project
, PJPROJ.project_desc
, PJPROJ.slsperid
, ARDoc.CustId
, ARTran.InvtId
, Customer.BillName
, ARTran.TranDate
, ARTran.TranType
, ARTran.RefNbr
, PJPROJ.start_date
, so.TotMerch
, Salesperson.Name
, ARTran.PerPost
, ARDoc.CpnyID
, PJPROJ.manager2
, PJEMPLOY.emp_name
HAVING ARDoc.SlsperId = 'bpettit'
ORDER BY ARDoc.SlsperId, ARTran.PerPost, PJPROJ.project
If an extra joined table has two records per one main record, this makes each main record appear twice in the result set. The following grouping and summing will then sum each value of the main record or another joined table twice.
Temporarily remove the grouping and summing, but keep all the joins and look at the result set. You will then probably see what causes this doubling.

CASE statement returning duplicate rows. I only want 1 row per record

The following CASE statement is returning 2 rows, 1 with the joindate = to the join date (cd.user_d1) if the person is a member and null if there is no join date on the record. How can i get the CASE statement to only return 1 row with the joindate field either null or with the member's join date?
I've searched and found solutions for other type fields with SUM, but nothing for date fields. Any help would be greatly appreciated.
SELECT DISTINCT
c.master_customer_id ,
c.SUB_CUSTOMER_ID ,
c.PRIMARY_EMAIL_ADDRESS ,
c.FIRST_NAME ,
c.INFORMAL_SALUTATION ,
c.LAST_NAME ,
c.LABEL_NAME ,
c.PRIMARY_JOB_TITLE ,
cad.company_name ,
ca.ADDRESS_1 ,
ca.ADDRESS_2 ,
ca.ADDRESS_3 ,
ca.ADDRESS_4 ,
ca.CITY ,
ca.STATE ,
ca.POSTAL_CODE ,
ca.COUNTRY_DESCR ,
c.PRIMARY_URL ,
c.BIRTH_DATE ,
CASE WHEN cd.DEMOGRAPHIC_SUBCODE = 'join_date'
AND cd.user_d1 IS NOT NULL THEN cd.USER_D1
ELSE NULL
END AS JOINDATE ,
CASE WHEN cc.comm_type_code = 'EMAIL'
AND cc.primary_flag <> 'Y' THEN cc.formatted_phone_address
END AS secondary_email
FROM customer c
LEFT OUTER JOIN CUS_DEMOGRAPHIC cd ON cd.MASTER_CUSTOMER_ID = c.MASTER_CUSTOMER_ID
LEFT OUTER JOIN CUS_ADDRESS ca ON ca.MASTER_CUSTOMER_ID = c.MASTER_CUSTOMER_ID
LEFT OUTER JOIN CUS_ADDRESS_DETAIL cad ON cad.CUS_ADDRESS_ID = ca.CUS_ADDRESS_ID
LEFT OUTER JOIN CUS_COMMUNICATION cc ON cc.MASTER_CUSTOMER_ID = c.MASTER_CUSTOMER_ID
WHERE c.CUSTOMER_STATUS_CODE = 'active'
AND c.ALLOW_EMAIL_FLAG = 'Y'
AND cad.PRIORITY_SEQ = 0
AND c.PRIMARY_EMAIL_ADDRESS <> ' '
ORDER BY c.MASTER_CUSTOMER_ID