Union Join between 3 SQL Queries

  • I am looking to perform a UNION join between 3 select queries, this is what I think I need to do to get the desired result set. The SQL Query is for a report which displays emergency/next of kin contact information. I have added 'IsNextOfKin' flags to the three static tables; StaticAddressType, StaticPhoneType and StaticEmailType. For each of these tables, the desired types are 'Emergency' and 'Next Of Kin' ONLY. I cannot use 'hard coding' i.e where staticaddresstype = 'Emergency' or where staticaddresstype in ('Emergency', 'Next Of Kin') etc. I am using the flags StaticAddressType.IsNextOfKin=1, StaticEmailType.IsNextOfKin=1, StaticPhoneType.IsNextOfKin=1.

    I ONLY want to return values which contain Emergency or Next Of Kin. I think i might need to make this three seperate queries and join them? a trimmed down version of my SQL query is below. I have tried to take as much of the irrelevant logic out as possible.

    SELECT st.keyfield as [Title],

    e.FirstName as [First Name],

    e.LastName as [Last Name],

    isnull(spt.PhoneType, '') as [Phone Type],

    isnull(emph.Phone, '') as [Phone],

    isnull([set].EmailType, '') as [Email Type],

    isnull(em.Email, '') as [Email],

    isnull(sat.AddressType, '') as [Address Type],

    isnull(ea.Address1, '') as [Property Name],

    isnull(ea.Address2, '') as [Property Number],

    isnull(ea.Address3, '') as [Flat Number],

    isnull(ea.Address4, '') as [Address Line 1],

    isnull(ea.Address5, '') as [Address Line 2],

    isnull(ea.City,'') as [City],

    isnull(ea.Region, '') as [Region],

    isnull(ea.Postcode,'') as [Postcode],

    FROM Employee e

    Left Join StaticTitle st on e.title = st.id and st.IsActive=1

    left Join

    (SELECT eph.EmployeeID, eph.DateFrom as DateFrom1, eph.DateTo as DateTo1, eph.Pay,

    eph.EmployeePosition, eph.ForeignCurrencyCode, eph.TotalSalaryPackage,

    eph.SalaryCategory, eph.Frequency, eph.FTEEquivalentAmount, eph.IsBasicSalary,

    eph.IsCurrent, eph.IncludeInPayroll, eph.IsoneOff, eph.IsPegged, ej.DateFrom as DateFrom2,

    ej.DateTo as DateTo2, ej.position, ej.Notes, ej.ChangeReason, ej.SalaryBand, ej.HoursPerWeek,

    ej.Country, ej.PositionLocation, ej.IsCurrent as EJIsCurrent

    FROMEmployeePayHistory as eph

    inner Join EmployeeJob as ej on ej.Employee = eph.EmployeeID and ej.position = eph.EmployeePosition

    and eph.IsActive=1 and eph.IsCurrent=1 and eph.IncludeInPayroll=1

    and eph.DateFrom = ej.DateFrom) as PAP on e.EmployeeID = PAP.EmployeeID

    Left Join StaticNationality sn2 on PAP.Country = sn2.IDand sn2.IsActive=1

    left Join StaticRelation sr on e.NextOfKinRelation = sr.ID and sr.IsActive=1

    left Join EmployeePhone emph on e.EmployeeID = emph.Employee and emph.IsActive=1

    left Join EmployeeEmail em on e.EmployeeID = em.employee and em.IsActive=1

    left Join EmployeeAddress ea on e.EmployeeID = ea.Employee and ea.IsActive=1

    left Join StaticPhoneType spt on emph.PhoneType = spt.PhoneTypeID and spt.IsActive=1

    inner Join StaticEmailType [set] on em.EmailType = [set].EmailTypeID and [set].IsActive=1

    inner Join StaticAddressType sat on ea.AddressTypeID = sat.AddressTypeID and sat.IsActive=1

    WHERE(e.IsActive=1)

    and (sr.IsActive=1)

    and (pap.EJIsCurrent=1)

    and (PAP.IsCurrent=1)

    and (spt.IsNextOfKin=1)or /* using OR as not ALL employees meet the three conditions */

    ([set].IsNextOfKin=1)or

    (sat.IsNextOfKin=1)

    ORDER BY e.LastName asc

  • Hi and welcome to the forums!!! In order to help we will need a few things:

    1. Sample DDL in the form of CREATE TABLE statements

    2. Sample data in the form of INSERT INTO statements

    3. Expected results based on the sample data

    Please take a few minutes and read the first article in my signature for best practices when posting questions.

    _______________________________________________________________

    Need help? Help us help you.

    Read the article at http://www.sqlservercentral.com/articles/Best+Practices/61537/ for best practices on asking questions.

    Need to split a string? Try Jeff Modens splitter http://www.sqlservercentral.com/articles/Tally+Table/72993/.

    Cross Tabs and Pivots, Part 1 – Converting Rows to Columns - http://www.sqlservercentral.com/articles/T-SQL/63681/
    Cross Tabs and Pivots, Part 2 - Dynamic Cross Tabs - http://www.sqlservercentral.com/articles/Crosstab/65048/
    Understanding and Using APPLY (Part 1) - http://www.sqlservercentral.com/articles/APPLY/69953/
    Understanding and Using APPLY (Part 2) - http://www.sqlservercentral.com/articles/APPLY/69954/

  • I would look at this part of your where clauseand (spt.IsNextOfKin=1)or /* using OR as not ALL employees meet the three conditions */

    ([set].IsNextOfKin=1)or

    (sat.IsNextOfKin=1)

    If you want one of those three to be true and the rest of the where to be true you need to enclose these inside of parentheses

    and (

    (spt.IsNextOfKin=1)or /* using OR as not ALL employees meet the three conditions */

    ([set].IsNextOfKin=1)or

    (sat.IsNextOfKin=1)

    )



    Microsoft Certified Master - SQL Server 2008
    Follow me on twitter: @keith_tate

    Forum Etiquette: How to post data/code on a forum to get the best help[/url]

  • Keith Tate (12/11/2013)


    I would look at this part of your where clauseand (spt.IsNextOfKin=1)or /* using OR as not ALL employees meet the three conditions */

    ([set].IsNextOfKin=1)or

    (sat.IsNextOfKin=1)

    If you want one of those three to be true and the rest of the where to be true you need to enclose these inside of parentheses

    and (

    (spt.IsNextOfKin=1)or /* using OR as not ALL employees meet the three conditions */

    ([set].IsNextOfKin=1)or

    (sat.IsNextOfKin=1)

    )

    ORs without appropriate parentheses is one of the most common logic flaws I see in WHERE clauses at clients. They can be VERY sneaky, and difficult to "see" too!

    Best,
    Kevin G. Boles
    SQL Server Consultant
    SQL MVP 2007-2012
    TheSQLGuru on googles mail service

  • If the columns are all 1 or 0, if a + b + c > 0, one of the columns is populated.

  • Take care with your join types. Referencing a column from an outer-joined table will convert the join to an IJ (except the special case of checking a column for NULL).

    SELECT

    st.keyfield as [Title],

    e.FirstName as [First Name],

    e.LastName as [Last Name],

    isnull(spt.PhoneType, '') as [Phone Type],

    isnull(emph.Phone, '') as [Phone],

    isnull([set].EmailType, '') as [Email Type],

    isnull(em.Email, '') as [Email],

    isnull(sat.AddressType, '') as [Address Type],

    isnull(ea.Address1, '') as [Property Name],

    isnull(ea.Address2, '') as [Property Number],

    isnull(ea.Address3, '') as [Flat Number],

    isnull(ea.Address4, '') as [Address Line 1],

    isnull(ea.Address5, '') as [Address Line 2],

    isnull(ea.City,'') as [City],

    isnull(ea.Region, '') as [Region],

    isnull(ea.Postcode,'') as [Postcode] --,

    FROM Employee e

    Left Join StaticTitle st on e.title = st.id and st.IsActive=1

    left Join (

    SELECT

    eph.EmployeeID, eph.DateFrom as DateFrom1, eph.DateTo as DateTo1, eph.Pay,

    eph.EmployeePosition, eph.ForeignCurrencyCode, eph.TotalSalaryPackage,

    eph.SalaryCategory, eph.Frequency, eph.FTEEquivalentAmount, eph.IsBasicSalary,

    eph.IsCurrent, eph.IncludeInPayroll, eph.IsoneOff, eph.IsPegged, ej.DateFrom as DateFrom2,

    ej.DateTo as DateTo2, ej.position, ej.Notes, ej.ChangeReason, ej.SalaryBand, ej.HoursPerWeek,

    ej.Country, ej.PositionLocation, ej.IsCurrent as EJIsCurrent

    FROM EmployeePayHistory as eph

    inner Join EmployeeJob as ej on ej.Employee = eph.EmployeeID and ej.position = eph.EmployeePosition

    and eph.IsActive=1 and eph.IsCurrent=1 and eph.IncludeInPayroll=1

    and eph.DateFrom = ej.DateFrom

    ) as PAP on e.EmployeeID = PAP.EmployeeID

    Left Join StaticNationality sn2 on PAP.Country = sn2.ID and sn2.IsActive=1

    left Join StaticRelation sr on e.NextOfKinRelation = sr.ID and sr.IsActive=1

    left Join EmployeePhone emph on e.EmployeeID = emph.Employee and emph.IsActive=1

    left Join EmployeeEmail em on e.EmployeeID = em.employee and em.IsActive=1

    left Join EmployeeAddress ea on e.EmployeeID = ea.Employee and ea.IsActive=1

    left Join StaticPhoneType spt on emph.PhoneType = spt.PhoneTypeID and spt.IsActive=1

    inner Join StaticEmailType [set] on em.EmailType = [set].EmailTypeID and [set].IsActive=1

    inner Join StaticAddressType sat on ea.AddressTypeID = sat.AddressTypeID and sat.IsActive=1

    CROSS APPLY (

    SELECT ValidRow = CASE WHEN spt.IsNextOfKin = 1 OR [set].IsNextOfKin = 1 OR sat.IsNextOfKin = 1 THEN 1 ELSE 0 END

    ) x

    WHERE e.IsActive = 1

    and sr.IsActive = 1 -- converted [sr] from outer to inner join

    and pap.EJIsCurrent = 1 -- converted [pap] from outer to inner join

    and PAP.IsCurrent = 1 -- converted [pap] from outer to inner join

    and x.ValidRow = 1

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • I recently worked on a process that had about 10 different fields I needed to check, all were had 'Y' or 'N' as the value. If any one of these were set to 'N' then that record didn't qualify. My first thought went to one big nested case statement checking each field one at a time. No one likes to deal with that and it's hard to read and to follow at times.

    casewhen field1 = 'Y'

    then casewhen field2 = 'Y'

    thencasewhen field3 = 'Y'

    So I decided to turn my thinking around:

    casewhen 'N' in (field1, field2, field3, ...)

    This is so simple but I had never thought about it that way. Just wanted to share, maybe just me but I get stuck thinking one way, and just stepping back for a minute to look at it differently made a huge difference to me.

    For what you want and your fields being 1 or 0, I think the adding and checking for greater than zero is an easy way to do that if only one has to be 'true'.

    -------------------------------------------------------------
    we travel not to escape life but for life not to escape us
    Don't fear failure, fear regret.

  • Hi, thanks for your replies.

    Apologies if I wasn't being clear in my explanation.

    So I need to retrieve all employees who have emergency/next of kin contact details in the system.

    eg

    John Smith could have emergency phone number, emergency address, next of kin email

    Joan smith might only have emergency phone number

    Joe Bloggs might have emergency phone number and emergency address.

    Note: these employees also have work, person, other phone/email/address types, which are currently showing and do not want. This is why i have a flag on each of the static tables.

    StaticAddressType.IsNextOfKin

    StaticEmailType.IsNextOfKin

    StaticPhoneType.IsNextOfKin

    These are set to 'IsNextOfKin=1', the other types (work, personal, business, other are set to '0'

    So, i want to retrieve all records where the three contact types are EMERGENCY or IS NEXT OF KIN, but cannot search for the types themselves in the where clause as this would be hard coding.

    My question is, should I take the query, turn it into 3 queries, have StaticAddressType.IsNextOfKin=1 in the first query, StaticEmailType.IsNextOfKin=1 in the next query, and StaticPhoneType.IsNextOfKin=1 in the last query, and join the three queries using UNION, which i have done with no luck. See below.

    (

    SELECTe.EmployeeReference as [Employee Reference],

    st.keyfield as [Title],

    e.FirstName as [First Name],

    e.LastName as [Last Name],

    isnull(spt.PhoneType, '') as [Phone Type],

    isnull(emph.Phone, '') as [Phone],

    isnull([set].EmailType, '') as [Email Type],

    isnull(sat.AddressType, '') as [Address Type],

    isnull(ea.Address1, '') as [Property Name],

    isnull(ea.Address2, '') as [Property Number],

    FROM Employee e

    Left Join StaticTitle st on e.title = st.idand st.IsActive=1

    left Join

    (SELECT eph.EmployeeID, eph.DateFrom as DateFrom1, eph.DateTo as DateTo1, eph.Pay,

    eph.EmployeePosition, eph.ForeignCurrencyCode, eph.TotalSalaryPackage,

    eph.SalaryCategory, eph.Frequency, eph.FTEEquivalentAmount, eph.IsBasicSalary,

    eph.IsCurrent, eph.IncludeInPayroll, eph.IsoneOff, eph.IsPegged, ej.DateFrom as DateFrom2,

    ej.DateTo as DateTo2, ej.position, ej.Notes, ej.ChangeReason, ej.SalaryBand, ej.HoursPerWeek,

    ej.Country, ej.PositionLocation, ej.IsCurrent as EJIsCurrent

    FROMEmployeePayHistory as eph

    inner Join EmployeeJob as ej on ej.Employee = eph.EmployeeID and ej.position = eph.EmployeePosition

    and eph.IsActive=1 and eph.IsCurrent=1 and eph.IncludeInPayroll=1

    and eph.DateFrom = ej.DateFrom) as PAP on e.EmployeeID = PAP.EmployeeID

    Left Join StaticNationality sn2 on PAP.Country = sn2.IDand sn2.IsActive=1

    left Join StaticRelation sr on e.NextOfKinRelation = sr.ID and sr.IsActive=1

    left Join EmployeePhone emph on e.EmployeeID = emph.Employee and emph.IsActive=1

    left Join EmployeeEmail em on e.EmployeeID = em.employee and em.IsActive=1

    left Join EmployeeAddress ea on e.EmployeeID = ea.Employee and ea.IsActive=1

    inner Join StaticPhoneType spt on emph.PhoneType = spt.PhoneTypeID and spt.IsActive=1

    inner Join StaticEmailType [set] on em.EmailType = [set].EmailTypeID and [set].IsActive=1

    inner Join StaticAddressType sat on ea.AddressTypeID = sat.AddressTypeID and sat.IsActive=1

    WHERE(e.IsActive=1)

    and (sr.IsActive=1)

    and (pap.EJIsCurrent=1)

    and (PAP.IsCurrent=1)

    and (spt.IsNextOfKin=1)

    )

    union

    (

    SELECTe.EmployeeReference as [Employee Reference],

    st.keyfield as [Title],

    e.FirstName as [First Name],

    e.LastName as [Last Name],

    isnull(spt.PhoneType, '') as [Phone Type],

    isnull(emph.Phone, '') as [Phone],

    isnull([set].EmailType, '') as [Email Type],

    isnull(sat.AddressType, '') as [Address Type],

    isnull(ea.Address1, '') as [Property Name],

    isnull(ea.Address2, '') as [Property Number],

    FROM Employee e

    Left Join StaticTitle st on e.title = st.idand st.IsActive=1

    left Join

    (SELECT eph.EmployeeID, eph.DateFrom as DateFrom1, eph.DateTo as DateTo1, eph.Pay,

    eph.EmployeePosition, eph.ForeignCurrencyCode, eph.TotalSalaryPackage,

    eph.SalaryCategory, eph.Frequency, eph.FTEEquivalentAmount, eph.IsBasicSalary,

    eph.IsCurrent, eph.IncludeInPayroll, eph.IsoneOff, eph.IsPegged, ej.DateFrom as DateFrom2,

    ej.DateTo as DateTo2, ej.position, ej.Notes, ej.ChangeReason, ej.SalaryBand, ej.HoursPerWeek,

    ej.Country, ej.PositionLocation, ej.IsCurrent as EJIsCurrent

    FROMEmployeePayHistory as eph

    inner Join EmployeeJob as ej on ej.Employee = eph.EmployeeID and ej.position = eph.EmployeePosition

    and eph.IsActive=1 and eph.IsCurrent=1 and eph.IncludeInPayroll=1

    and eph.DateFrom = ej.DateFrom) as PAP on e.EmployeeID = PAP.EmployeeID

    Left Join StaticNationality sn2 on PAP.Country = sn2.IDand sn2.IsActive=1

    left Join StaticRelation sr on e.NextOfKinRelation = sr.ID and sr.IsActive=1

    left Join EmployeePhone emph on e.EmployeeID = emph.Employee and emph.IsActive=1

    left Join EmployeeEmail em on e.EmployeeID = em.employee and em.IsActive=1

    left Join EmployeeAddress ea on e.EmployeeID = ea.Employee and ea.IsActive=1

    inner Join StaticPhoneType spt on emph.PhoneType = spt.PhoneTypeID and spt.IsActive=1

    inner Join StaticEmailType [set] on em.EmailType = [set].EmailTypeID and [set].IsActive=1

    inner Join StaticAddressType sat on ea.AddressTypeID = sat.AddressTypeID and sat.IsActive=1

    WHERE(e.IsActive=1)

    and (sr.IsActive=1)

    and (pap.EJIsCurrent=1)

    and (PAP.IsCurrent=1)

    and ([set].IsNextOfKin=1)

    )

    union

    (

    SELECTe.EmployeeReference as [Employee Reference],

    st.keyfield as [Title],

    e.FirstName as [First Name],

    e.LastName as [Last Name],

    isnull(spt.PhoneType, '') as [Phone Type],

    isnull(emph.Phone, '') as [Phone],

    isnull([set].EmailType, '') as [Email Type],

    isnull(sat.AddressType, '') as [Address Type],

    isnull(ea.Address1, '') as [Property Name],

    isnull(ea.Address2, '') as [Property Number],

    FROM Employee e

    Left Join StaticTitle st on e.title = st.idand st.IsActive=1

    left Join

    (SELECT eph.EmployeeID, eph.DateFrom as DateFrom1, eph.DateTo as DateTo1, eph.Pay,

    eph.EmployeePosition, eph.ForeignCurrencyCode, eph.TotalSalaryPackage,

    eph.SalaryCategory, eph.Frequency, eph.FTEEquivalentAmount, eph.IsBasicSalary,

    eph.IsCurrent, eph.IncludeInPayroll, eph.IsoneOff, eph.IsPegged, ej.DateFrom as DateFrom2,

    ej.DateTo as DateTo2, ej.position, ej.Notes, ej.ChangeReason, ej.SalaryBand, ej.HoursPerWeek,

    ej.Country, ej.PositionLocation, ej.IsCurrent as EJIsCurrent

    FROMEmployeePayHistory as eph

    inner Join EmployeeJob as ej on ej.Employee = eph.EmployeeID and ej.position = eph.EmployeePosition

    and eph.IsActive=1 and eph.IsCurrent=1 and eph.IncludeInPayroll=1

    and eph.DateFrom = ej.DateFrom) as PAP on e.EmployeeID = PAP.EmployeeID

    Left Join StaticNationality sn2 on PAP.Country = sn2.IDand sn2.IsActive=1

    left Join StaticRelation sr on e.NextOfKinRelation = sr.ID and sr.IsActive=1

    left Join EmployeePhone emph on e.EmployeeID = emph.Employee and emph.IsActive=1

    left Join EmployeeEmail em on e.EmployeeID = em.employee and em.IsActive=1

    left Join EmployeeAddress ea on e.EmployeeID = ea.Employee and ea.IsActive=1

    inner Join StaticPhoneType spt on emph.PhoneType = spt.PhoneTypeID and spt.IsActive=1

    inner Join StaticEmailType [set] on em.EmailType = [set].EmailTypeID and [set].IsActive=1

    inner Join StaticAddressType sat on ea.AddressTypeID = sat.AddressTypeID and sat.IsActive=1

    WHERE(e.IsActive=1)

    and (sr.IsActive=1)

    and (pap.EJIsCurrent=1)

    and (PAP.IsCurrent=1)

    and (sat.IsNextOfKin=1)

    )

    ORDER BY e.LastName asc

  • What results are you getting? There is syntax errors in your posted SQL, commas before the from, I assume you removed some fields for the post.

    Formatting the SQL will help us better understand what you are doing. Like this:

    SELECT e.EmployeeReference as [Employee Reference],

    st.keyfield as [Title],

    e.FirstName as [First Name],

    e.LastName as [Last Name],

    isnull(spt.PhoneType, '') as [Phone Type],

    isnull(emph.Phone, '') as [Phone],

    isnull([set].EmailType, '') as [Email Type],

    isnull(sat.AddressType, '') as [Address Type],

    isnull(ea.Address1, '') as [Property Name],

    isnull(ea.Address2, '') as [Property Number]

    FROM Employee e

    Left Join StaticTitle st on

    e.title = st.id

    and st.IsActive=1

    left Join (SELECT eph.EmployeeID, eph.DateFrom as DateFrom1, eph.DateTo as DateTo1, eph.Pay,

    eph.EmployeePosition, eph.ForeignCurrencyCode, eph.TotalSalaryPackage,

    eph.SalaryCategory, eph.Frequency, eph.FTEEquivalentAmount, eph.IsBasicSalary,

    eph.IsCurrent, eph.IncludeInPayroll, eph.IsoneOff, eph.IsPegged, ej.DateFrom as DateFrom2,

    ej.DateTo as DateTo2, ej.position, ej.Notes, ej.ChangeReason, ej.SalaryBand, ej.HoursPerWeek,

    ej.Country, ej.PositionLocation, ej.IsCurrent as EJIsCurrent

    FROM EmployeePayHistory as eph

    inner Join EmployeeJob as ej on

    ej.Employee = eph.EmployeeID

    and ej.position = eph.EmployeePosition

    and eph.IsActive=1

    and eph.IsCurrent=1

    and eph.IncludeInPayroll=1

    and eph.DateFrom = ej.DateFrom) as PAP on

    e.EmployeeID = PAP.EmployeeID

    Left Join StaticNationality sn2 on

    PAP.Country = sn2.ID

    and sn2.IsActive=1

    left Join StaticRelation sr on

    e.NextOfKinRelation = sr.ID

    and sr.IsActive=1

    left Join EmployeePhone emph on

    e.EmployeeID = emph.Employee

    and emph.IsActive=1

    left Join EmployeeEmail em on

    e.EmployeeID = em.employee

    and em.IsActive=1

    left Join EmployeeAddress ea on

    e.EmployeeID = ea.Employee

    and ea.IsActive=1

    inner Join StaticPhoneType spt on

    emph.PhoneType = spt.PhoneTypeID

    and spt.IsActive=1

    inner Join StaticEmailType [set] on

    em.EmailType = [set].EmailTypeID

    and [set].IsActive=1

    inner Join StaticAddressType sat on

    ea.AddressTypeID = sat.AddressTypeID

    and sat.IsActive=1

    WHERE (e.IsActive=1)

    and (sr.IsActive=1)

    and (pap.EJIsCurrent=1)

    and (PAP.IsCurrent=1)

    and (spt.IsNextOfKin=1)

    union

    SELECT e.EmployeeReference as [Employee Reference],

    st.keyfield as [Title],

    e.FirstName as [First Name],

    e.LastName as [Last Name],

    isnull(spt.PhoneType, '') as [Phone Type],

    isnull(emph.Phone, '') as [Phone],

    isnull([set].EmailType, '') as [Email Type],

    isnull(sat.AddressType, '') as [Address Type],

    isnull(ea.Address1, '') as [Property Name],

    isnull(ea.Address2, '') as [Property Number]

    FROM Employee e

    Left Join StaticTitle st on

    e.title = st.id

    and st.IsActive=1

    left Join (SELECT eph.EmployeeID, eph.DateFrom as DateFrom1, eph.DateTo as DateTo1, eph.Pay,

    eph.EmployeePosition, eph.ForeignCurrencyCode, eph.TotalSalaryPackage,

    eph.SalaryCategory, eph.Frequency, eph.FTEEquivalentAmount, eph.IsBasicSalary,

    eph.IsCurrent, eph.IncludeInPayroll, eph.IsoneOff, eph.IsPegged, ej.DateFrom as DateFrom2,

    ej.DateTo as DateTo2, ej.position, ej.Notes, ej.ChangeReason, ej.SalaryBand, ej.HoursPerWeek,

    ej.Country, ej.PositionLocation, ej.IsCurrent as EJIsCurrent

    FROM EmployeePayHistory as eph

    inner Join EmployeeJob as ej on

    ej.Employee = eph.EmployeeID

    and ej.position = eph.EmployeePosition

    and eph.IsActive=1

    and eph.IsCurrent=1

    and eph.IncludeInPayroll=1

    and eph.DateFrom = ej.DateFrom) as PAP on

    e.EmployeeID = PAP.EmployeeID

    Left Join StaticNationality sn2 on

    PAP.Country = sn2.ID

    and sn2.IsActive=1

    left Join StaticRelation sr on

    e.NextOfKinRelation = sr.ID

    and sr.IsActive=1

    left Join EmployeePhone emph on

    e.EmployeeID = emph.Employee

    and emph.IsActive=1

    left Join EmployeeEmail em on

    e.EmployeeID = em.employee

    and em.IsActive=1

    left Join EmployeeAddress ea on

    e.EmployeeID = ea.Employee

    and ea.IsActive=1

    inner Join StaticPhoneType spt on

    emph.PhoneType = spt.PhoneTypeID

    and spt.IsActive=1

    inner Join StaticEmailType [set] on

    em.EmailType = [set].EmailTypeID

    and [set].IsActive=1

    inner Join StaticAddressType sat on

    ea.AddressTypeID = sat.AddressTypeID

    and sat.IsActive=1

    WHERE (e.IsActive=1)

    and (sr.IsActive=1)

    and (pap.EJIsCurrent=1)

    and (PAP.IsCurrent=1)

    and ([set].IsNextOfKin=1)

    union

    SELECT e.EmployeeReference as [Employee Reference],

    st.keyfield as [Title],

    e.FirstName as [First Name],

    e.LastName as [Last Name],

    isnull(spt.PhoneType, '') as [Phone Type],

    isnull(emph.Phone, '') as [Phone],

    isnull([set].EmailType, '') as [Email Type],

    isnull(sat.AddressType, '') as [Address Type],

    isnull(ea.Address1, '') as [Property Name],

    isnull(ea.Address2, '') as [Property Number]

    FROM Employee e

    Left Join StaticTitle st on

    e.title = st.id

    and st.IsActive=1

    left Join (SELECT eph.EmployeeID, eph.DateFrom as DateFrom1, eph.DateTo as DateTo1, eph.Pay,

    eph.EmployeePosition, eph.ForeignCurrencyCode, eph.TotalSalaryPackage,

    eph.SalaryCategory, eph.Frequency, eph.FTEEquivalentAmount, eph.IsBasicSalary,

    eph.IsCurrent, eph.IncludeInPayroll, eph.IsoneOff, eph.IsPegged, ej.DateFrom as DateFrom2,

    ej.DateTo as DateTo2, ej.position, ej.Notes, ej.ChangeReason, ej.SalaryBand, ej.HoursPerWeek,

    ej.Country, ej.PositionLocation, ej.IsCurrent as EJIsCurrent

    FROM EmployeePayHistory as eph

    inner Join EmployeeJob as ej on

    ej.Employee = eph.EmployeeID

    and ej.position = eph.EmployeePosition

    and eph.IsActive=1

    and eph.IsCurrent=1

    and eph.IncludeInPayroll=1

    and eph.DateFrom = ej.DateFrom) as PAP on

    e.EmployeeID = PAP.EmployeeID

    Left Join StaticNationality sn2 on

    PAP.Country = sn2.ID

    and sn2.IsActive=1

    left Join StaticRelation sr on

    e.NextOfKinRelation = sr.ID

    and sr.IsActive=1

    left Join EmployeePhone emph on

    e.EmployeeID = emph.Employee

    and emph.IsActive=1

    left Join EmployeeEmail em on

    e.EmployeeID = em.employee

    and em.IsActive=1

    left Join EmployeeAddress ea on

    e.EmployeeID = ea.Employee

    and ea.IsActive=1

    inner Join StaticPhoneType spt on

    emph.PhoneType = spt.PhoneTypeID

    and spt.IsActive=1

    inner Join StaticEmailType [set] on

    em.EmailType = [set].EmailTypeID

    and [set].IsActive=1

    inner Join StaticAddressType sat on

    ea.AddressTypeID = sat.AddressTypeID

    and sat.IsActive=1

    WHERE (e.IsActive=1)

    and (sr.IsActive=1)

    and (pap.EJIsCurrent=1)

    and (PAP.IsCurrent=1)

    and (sat.IsNextOfKin=1)

    ORDER BY e.LastName asc

    Without seeing your data I would think this would work, doing the union would eliminate any duplicate entries.

    Test data would be needed for each table to better know, and what you are getting compared to what you are expecting.

    -------------------------------------------------------------
    we travel not to escape life but for life not to escape us
    Don't fear failure, fear regret.

  • Hi, Sorry - ignore the commas. these aren't in the query. Just trimmed the select statement down to the most important fields

  • Without more detail it is hard to help, see Sean's post.

    As I said I would think the union's would work but without data to test it I can't be sure. Let us know what results you are getting.

    And I think Greg's response would work if you don't want to do the union. May need to add ISNULL to each in case there isn't a record. Something like (ISNULL(sat.IsNextOfKin, 0) + ISNULL(set].IsNextOfKin, 0) + ISNULL(spt.IsNextOfKin, 0)) > 0

    -------------------------------------------------------------
    we travel not to escape life but for life not to escape us
    Don't fear failure, fear regret.

  • I created a real quick sample of a few tables.

    The problem I see, is in doing an outer join and selecting any next of kin records that have information without getting duplicates.

    Yes, some sample tables with sample data would go a long ways towards an answer vs. guessing.

    And a better description of what the poster is actually seeing would be helpful too.

    A view against each of the tables with only the next of kin records selected, a view using having to select a distinct list of the keys, and then a view using this to select those keys, the employee, and outer join to the next of kin views for address, phone, and email can return what it appears the poster wants to see.

    No record for an employee with no additional contact info, a record where such info exists (null if not in any field).

    Not sure if there is any option to do any work to rearchitect the tables.

    That could simplify things considerably.

  • Why read ALL OF THOSE TABLES three times when you can get your results by reading them only once?

    Why include tons of columns in your subquery - then throw them away?

    Why use LEFT JOIN for tables which are referenced in your WHERE clause?

    Why left join tables which aren't referenced anywhere else in your query?

    Why overcomplicate something so simple?

    Accounting for these, this is what I think your query should look like:

    SELECT

    st.keyfield as [Title],

    e.FirstName as [First Name],

    e.LastName as [Last Name],

    isnull(spt.PhoneType, '') as [Phone Type],

    isnull(emph.Phone, '') as [Phone],

    isnull([set].EmailType, '') as [Email Type],

    isnull(em.Email, '') as [Email],

    isnull(sat.AddressType, '') as [Address Type],

    isnull(ea.Address1, '') as [Property Name],

    isnull(ea.Address2, '') as [Property Number],

    isnull(ea.Address3, '') as [Flat Number],

    isnull(ea.Address4, '') as [Address Line 1],

    isnull(ea.Address5, '') as [Address Line 2],

    isnull(ea.City,'') as [City],

    isnull(ea.Region, '') as [Region],

    isnull(ea.Postcode,'') as [Postcode]

    FROM Employee e -- output/WHERE

    Left Join StaticTitle st

    on e.title = st.id and st.IsActive = 1 -- output

    INNER JOIN EmployeePayHistory as eph

    on e.EmployeeID = eph.EmployeeID -- WHERE

    and eph.IsActive=1

    and eph.IsCurrent=1

    and eph.IncludeInPayroll=1

    inner Join EmployeeJob as ej

    on ej.Employee = eph.EmployeeID

    and ej.position = eph.EmployeePosition

    and eph.DateFrom = ej.DateFrom

    AND EJ.IsCurrent=1

    -- Left Join StaticNationality sn2 on PAP.Country = sn2.ID and sn2.IsActive=1 -- NOT USED

    INNER Join StaticRelation sr on e.NextOfKinRelation = sr.ID and sr.IsActive=1 -- WHERE

    left Join EmployeePhone emph on e.EmployeeID = emph.Employee and emph.IsActive=1 -- output

    -- left Join EmployeeEmail em on e.EmployeeID = em.employee and em.IsActive=1 -- NOT USED

    left Join EmployeeAddress ea on e.EmployeeID = ea.Employee and ea.IsActive=1 -- output

    left Join StaticPhoneType spt on emph.PhoneType = spt.PhoneTypeID and spt.IsActive=1 -- output/conditional WHERE

    left Join StaticEmailType [set] on em.EmailType = [set].EmailTypeID and [set].IsActive=1 -- output/conditional WHERE

    left Join StaticAddressType sat on ea.AddressTypeID = sat.AddressTypeID and sat.IsActive=1 -- conditional WHERE

    WHERE e.IsActive=1

    --and sr.IsActive=1 -- REDUNDANT FILTER

    --and pap.EJIsCurrent=1 -- REDUNDANT FILTER

    --and PAP.IsCurrent=1 -- REDUNDANT FILTER

    and (

    spt.IsNextOfKin = 1 OR /* using OR as not ALL employees meet the three conditions */

    [set].IsNextOfKin = 1 OR

    sat.IsNextOfKin = 1

    )

    ORDER BY e.LastName asc

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • Chris -

    I agree with a lot of your Why's. See this all the time.

    If you could look at this, run the view for next of kin info, and tell me a better way, I'd appreciate it.

    Not exactly the same as what the poster has, but I think close enough in concept.

    Thanks.

    USE [Test2]

    GO

    /****** Object: Table [dbo].[Employee] Script Date: 12/12/2013 13:42:17 ******/

    SET ANSI_NULLS ON

    GO

    SET QUOTED_IDENTIFIER ON

    GO

    CREATE TABLE [dbo].[Employee](

    [EKey] [smallint] NOT NULL,

    [Emp_First] [nchar](10) NOT NULL,

    [Emp_Last] [nchar](20) NOT NULL

    ) ON [PRIMARY]

    GO

    INSERT INTO [Test2].[dbo].[Employee]

    ([EKey]

    ,[Emp_First]

    ,[Emp_Last])

    VALUES

    (1,'Greg','Johnson'),

    (2,'Fred','Flintstone'),

    (3,'Jenny','May'),

    (4,'Joe','Horn'),

    (5,'Cathy','French')

    GO

    /****** Object: Table [dbo].[Email] Script Date: 12/12/2013 13:43:26 ******/

    CREATE TABLE [dbo].[Email](

    [EKey] [smallint] NOT NULL,

    [Next_of_Kin] [bit] NULL,

    [Email] [nchar](40) NULL

    ) ON [PRIMARY]

    GO

    INSERT INTO [Test2].[dbo].[Email]

    ([EKey]

    ,[Next_of_Kin]

    ,[Email])

    VALUES

    (1,'','greg.johnson@gmail.com'),

    (3,'','jenny.may@gmail.com'),

    (5,'','cathy.french@yahoo.com'),

    (1,'True','johndoe@gmail.com'),

    (2,'True','bettyflintstone@yahoo.com'),

    (5,'True','jerrycan@gmail.com')

    GO

    CREATE TABLE [dbo].[Phone](

    [EKey] [smallint] NOT NULL,

    [Phone] [numeric](18, 0) NULL,

    [Next_of_Kin] [bit] NULL

    ) ON [PRIMARY]

    GO

    INSERT INTO [Test2].[dbo].[Phone]

    ([EKey]

    ,[Phone]

    ,[Next_of_Kin])

    VALUES

    (1,7637531111,''),

    (1,7637532222,'True'),

    (2,7637533333,''),

    (3,7637551234,''),

    (4,7635551245,''),

    (5,7639998888,''),

    (5,6127775555,'True')

    GO

    /****** Object: Table [dbo].[Address] Script Date: 12/12/2013 13:44:22 ******/

    CREATE TABLE [dbo].[Address](

    [EKey] [smallint] NOT NULL,

    [Address] [nchar](50) NULL,

    [Next_of_Kin] [bit] NULL

    ) ON [PRIMARY]

    GO

    INSERT INTO [Test2].[dbo].[Address]

    ([EKey]

    ,[Address]

    ,[Next_of_Kin])

    VALUES

    (1,'111 south St',''),

    (2,'222 North St',''),

    (3,'333 West Ave',''),

    (4,'555 10th St',''),

    (5,'1313 Mockingbird Lane',''),

    (1,'123 South St','True'),

    (4,'487 Xerxes Ave So','True')

    GO

    /****** Object: View [dbo].[v_Next_of_Kin_Keys] Script Date: 12/12/2013 13:44:56 ******/

    CREATE VIEW [dbo].[v_Next_of_Kin_Keys]

    AS

    SELECT DISTINCT a.EKey

    FROM dbo.Employee AS a LEFT OUTER JOIN

    dbo.Email AS b ON a.EKey = b.EKey LEFT OUTER JOIN

    dbo.Phone AS c ON a.EKey = c.EKey LEFT OUTER JOIN

    dbo.Address AS d ON a.EKey = d.EKey

    GROUP BY a.EKey

    HAVING (SUM(CASE b.Next_of_Kin WHEN 'TRUE' THEN 1 ELSE 0 END + CASE c.Next_of_Kin WHEN 'TRUE' THEN 1 ELSE 0 END + CASE d .Next_of_Kin WHEN 'TRUE' THEN 1

    ELSE 0 END) > 0)

    GO

    /****** Object: View [dbo].[v_Next_of_Kin_Address] Script Date: 12/12/2013 13:45:17 ******/

    CREATE VIEW [dbo].[v_Next_of_Kin_Address]

    AS

    SELECT a.EKey, b.Address

    FROM dbo.Employee AS a INNER JOIN

    dbo.Address AS b ON a.EKey = b.EKey

    WHERE (b.Next_of_Kin = 'true')

    GO

    /****** Object: View [dbo].[v_Next_of_Kin_Phone] Script Date: 12/12/2013 13:45:28 ******/

    CREATE VIEW [dbo].[v_Next_of_Kin_Phone]

    AS

    SELECT a.EKey, b.Phone

    FROM dbo.Employee AS a INNER JOIN

    dbo.Phone AS b ON a.EKey = b.EKey

    WHERE (b.Next_of_Kin = 'true')

    GO

    /****** Object: View [dbo].[v_Next_of_Kin_Email] Script Date: 12/12/2013 13:46:22 ******/

    CREATE VIEW [dbo].[v_Next_of_Kin_Email]

    AS

    SELECT a.EKey, b.Email

    FROM dbo.Employee AS a INNER JOIN

    dbo.Email AS b ON a.EKey = b.EKey

    WHERE (b.Next_of_Kin = 'true')

    GO

    /****** Object: View [dbo].[v_Next_of_Kin_Info] Script Date: 12/12/2013 13:46:34 ******/

    CREATE VIEW [dbo].[v_Next_of_Kin_Info]

    AS

    SELECT a.EKey, b.Emp_First, b.Emp_Last, c.Address, d.Phone, e.Email

    FROM dbo.v_Next_of_Kin_Keys AS a LEFT OUTER JOIN

    dbo.Employee AS b ON a.EKey = b.EKey LEFT OUTER JOIN

    dbo.v_Next_of_Kin_Address AS c ON a.EKey = c.EKey LEFT OUTER JOIN

    dbo.v_Next_of_Kin_Phone AS d ON a.EKey = d.EKey LEFT OUTER JOIN

    dbo.v_Next_of_Kin_Email AS e ON a.EKey = e.EKey

    GO

  • Greg Edwards-268690 (12/13/2013)


    Chris -

    I agree with a lot of your Why's. See this all the time.

    If you could look at this, run the view for next of kin info, and tell me a better way, I'd appreciate it.

    Not exactly the same as what the poster has, but I think close enough in concept.

    Thanks.

    I've never been a big fan of views Greg, a device designed to simplify coding almost always ends up doing the exact opposite through overuse -mostly ignorance. Your approach is nice though. The views could easily fit into a query which visibly models the business case. Here's the other side of that coin:

    "What are you trying to do in this crazy 12,000 line stored procedure?"

    "This and this and that and that and then something else then back to the beginning and repeat for each branch, and then go on to the next month, and that's only this year! It's really really complicated and it's taking like 48 nested cursors to process each piece!"

    "What are you really trying to do?"

    "Get last year's gross and net sales figures aggregated by branch and month and compare with what we've got so far for this year".

    😀

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

Viewing 15 posts - 1 through 15 (of 19 total)

You must be logged in to reply to this topic. Login to reply