Combining two independent inner joins into one on certain conditions - sql

I have the below two queries that are shown below, actually both of the queries use an inner join internally. Now I want to combine these two queries into one, but the condition that where the value of column invo_id = 2 and the column invo_id is in table ioa_invoice_line
So the relationship among three tables
ioa_invoice_line
ioa_invoice_line_notes
IOA_INV_LINE_NOTE_MAP
These are the queries
select
e.id
, e.invo_id
, b.id
, b.inli_id
from
ioa_invoice_line e
inner join
ioa_invoice_line_notes b on e.id = b.inli_id;
select
e.id
, b.id
, b.ATTACHMENT_BLOB_ID
, b.INV_LINE_NOTE_ID
from
ioa_invoice_line_notes e
inner join
IOA_INV_LINE_NOTE_MAP b on e.id = b.INV_LINE_NOTE_ID;
ioa_invoice_line enter image description here

This is the way I assumed you'd want to do the joins. Since you're looking for two conditions to be true:
1) That ioa_invoice_line.invo_id = 2
2) That ioa_invoice_line.invo_id exists
Since you'll be checking to see that invo_id is equal to 2 you can be pretty sure that it exists if it finds a value of 2.
SELECT L.id, L.invo_id, LN.id, LNM.id, LNM.attachment_blob_id, LNM.inv_line_note_id
FROM ioa_invoice_line_notes LN
INNER JOIN ioa_invoice_line L ON LN.inli_id = L.id
INNER JOIN ioa_inv_line_note_map LNM ON LN.id = LNM.inv_line_note_id
WHERE L.invo_id = 2;
It just looked like you were looking for Inv Line ID, Inv Line Invoice ID, Line Notes ID, Line Notes Map ID and the other IDs in the Notes Map table.

The query integrates the condition on the invo_id into the join. As it is an inner join, the existence of invo_id in the selected records comes for free:
select line.id id_line
, line.invo_id
, notes.id id_notes
, notes.inli_id
, map.id id_map
, map.attachment_blob_id
, map.inv_line_note_id
from ioa_invoice_line line
INNER JOIN ioa_invoice_line_notes notes on (
line.id = notes.inli_id
AND line.invo_id = 2
)
INNER JOIN ioa_inv_line_note_map map on map.id = notes.inv_line_note_id
;

Related

SQL: Multiple joins on multiple tables where some column values are not mandatory

I am trying to join multiple tables where the values in columns e.Email, e.Phone are voluntary. I would like to select all rows even if e.Email, e.Phone contain empty values.
Currently, I am only able to select rows where e.Email, e.Phone values are present.
SELECT a.ID_1
,b.Tier
,e.Email
,e.Phone
FROM CustomerActivity a
JOIN CustomerSummary b
ON a.ID_1 = b.ID_1
JOIN DimensionCustomer c
ON b.ID_1 = c.ID_1
JOIN LegacyCustomerMapping d
ON c.ID_2 = d.ID_2
JOIN LegacyCustomerContactData e
d.ID_3 = e.ID_3
Many thanks for any kind of advice!
I would recommend using left join instead of join in your query. That should get the results you are looking for.
Image from: https://www.w3schools.com/sql/sql_join.asp
This can be obtained by using a LEFT OUTER JOIN for the table containing the Email and Phone fields:
SELECT a.ID_1, b.Tier, e.Email ,e.Phone
FROM CustomerActivity a
JOIN CustomerSummary b ON a.ID_1 = b.ID_1
JOIN DimensionCustomer c ON b.ID_1 = c.ID_1
JOIN LegacyCustomerMapping d ON c.ID_2 = d.ID_2
LEFT OUTER JOIN LegacyCustomerContactData e d.ID_3 = e.ID_3
Using an OUTER JOIN avoids records not being returned when there are no related rows in the joined table. Note that OUTER is optional and might not be supported by all databases.

Can use aggregate functions with join?

table projects : pid(pk), name ...
table categories : pid(pk), project(project's pid), parent(other category's pid) ...
table counts : project(project's pid), category(category's pid), count ...
I used this query before
SELECT
categories.*, projects.pid, projects.name, parent_category.*
FROM categories
INNER JOIN projects ON projects.pid = categories.project
LEFT JOIN categories AS parent_category ON parent_category.pid = categories.parent
and it worked well
This time we need SUM, COUNT data. So i added "counts" table and made this query.
SELECT
categories.*, projects.pid, projects.name, SUM(counts.count), COUNT(counts.count),
parent_category.*, SUM(parent_category_count.count), COUNT(parent_category_count.count)
FROM categories
INNER JOIN projects ON projects.pid = categories.project
LEFT JOIN counts ON counts.category = categories.pid
LEFT JOIN categories AS parent_category ON parent_category.pid = categories.parent
LEFT JOIN counts AS parent_category_count ON parent_category_count.category = categories.pid
Then I get
ERROR: aggregate function calls cannot be nested
What can I do? Does this query basically make sense? Or should I split it?
You should add a proper GROUP BY clause (in your case should be categories.pid )
SELECT
categories.*
, projects.pid
, projects.name
, SUM(counts.count)
, COUNT(counts.count)
, parent_category.*
, SUM(parent_category_count.count)
, COUNT(parent_category_count.count)
FROM categories
INNER JOIN projects ON projects.pid = categories.project
LEFT JOIN counts ON counts.category = categories.pid
LEFT JOIN categories AS parent_category ON parent_category.pid = categories.parent
LEFT JOIN counts AS parent_category_count ON parent_category_count.category = categories.pid
GROUP BY categories.pid
or as in your comment
SELECT
categories.*
, projects.pid
, projects.name
, SUM(counts.count)
, COUNT(counts.count)
, parent_category.*
, SUM(parent_category_count.count)
, COUNT(parent_category_count.count)
FROM categories
INNER JOIN projects ON projects.pid = categories.project
LEFT JOIN counts ON counts.category = categories.pid
LEFT JOIN categories AS parent_category ON parent_category.pid = categories.parent
LEFT JOIN counts AS parent_category_count ON parent_category_count.category = categories.pid
GROUP BY categories.pid, projects.pid, parent_category.pid

Left Outer Join returning results to be excluded

I have a query like
WITH a AS ( SELECT *
FROM inventory_tagalongs
WHERE TagAlong_ItemNum <> 'bokiwi2'
)
SELECT inventory.itemnum
, inventory.itemname
, inventory.ItemType,inventory.dept_id
FROM inventory
LEFT OUTER JOIN a
ON inventory.itemnum = a.itemnum
JOIN departments
ON inventory.dept_id = departments.dept_id
JOIN categories
ON departments.subtype = categories.cat_id AND categories.description = 'vapors'
in which i am trying to exclude a's results from the lower syntax but the results return are exactly the same whether or not left outer join..... is there or not.
Do i have my syntax incorrect here?
Good afternoon. Please try this:
select
inventory.itemnum
, inventory.itemname
, inventory.ItemType
, inventory.dept_id
from inventory
join departments on inventory.dept_id=departments.dept_id
join categories on departments.subtype=categories.cat_id and categories.description='vapors'
WHERE NOT EXISTS(
select 1 from inventory_tagalongs B where inventory.itemnum = b.itemnum
AND B.TagAlong_ItemNum <>'bokiwi2');
The CTE overthought the issue a bit. This accomplishes the goal with easier-to-read code and should perform better as well.
Thanks, John.
If you are trying to get results that don't have the tag, your logic is inverted. You want:
SELECT i.itemnum, i.itemname, i.ItemType, i.dept_id
FROM inventory i JOIN
departments d
ON i.dept_id = d.dept_id JOIN
categories c
ON d.subtype = c.cat_id AND
c.description = 'vapors' LEFT OUTER JOIN
a
ON i.itemnum = a.itemnum
WHERE a.itemnum IS NULL;
You don't need a CTE for this at all. It would usually be written as:
WITH a AS (
)
SELECT i.itemnum, i.itemname, i.ItemType, i.dept_id
FROM inventory i JOIN
departments d
ON i.dept_id = d.dept_id JOIN
categories c
ON d.subtype = c.cat_id AND
c.description = 'vapors' LEFT OUTER JOIN
inventory_tagalongs it
ON i.itemnum = it.itemnum AND it.TagAlong_ItemNum = 'bokiwi2'
WHERE a.itemnum IS NULL;
And -- as mentioned in another answer -- NOT EXISTS is another typical way to approach this problem.

How do I use a table name that's returned in a select statement, in a join?

*Note: This is not the same as the "possible duplicate". Here, the table name will be different for each record returned in the SELECT statement. So I can't just "set" a variable like set #tableName = 'whatever'.
Here's my SQL - take a look at my last inner join. e.Name from the table EmailSendDefintion is the name of the table I need to join to. So, this is kind of dynamic, I know, but how do I join to a table that is stored in a field in another table?
select top 5000
x.HL_ACCT_ID as 'HL_ACCT_ID',
x.SALE_CODE as 'SALE_CODE',
s.SubscriberKey as 'EmailAddress',
o.EventDate as 'Opened',
c.EventDate as 'Clicked',
b.EventDate as 'Bounced'
from c100._sent s with (nolock)
inner join c100._job j with (nolock) on s.jobid = j.jobid
inner join emailsenddefinition e with (nolock) on e.customerkey = j.emailsenddefinition
left join c100._open o with (nolock) on o.jobid = s.jobid and o.subscriberkey = s.subscriberkey
left join c100._click c with (nolock) on c.jobid = s.jobid and c.subscriberkey = s.subscriberkey
left join c100._bounce b with (nolock) on b.jobid = s.jobid and b.subscriberkey = s.subscriberkey
inner join c100.[e.name] x with (nolock) on x.EmailAddress = s.SubscriberKey
where e.clientid = 100
Perhaps you could just create a view that outputs the union of all the e.name tables? Then join to the view.
In order to keep this short, let's say you have just 2 different tables whose name could be in the e.name column, SubscriberEmail1 and SubscriberEmail2.
Then you could create a view like this:
CREATE VIEW SubscriberEmailUnion
AS
SELECT
'SubscriberEmail1' as TableName,
HL_ACCT_ID,
SALE_CODE,
EmailAddress
FROM SubscriberEmail1
UNION
SELECT
'SubscriberEmail2' as TableName,
HL_ACCT_ID,
SALE_CODE,
EmailAddress
FROM SubscriberEmail2
GO
Note that each part of the view is adding the name of it's underlying table as a column. You can then change your final join to:
inner join SubscriberEmailUnion x with (nolock) on (
x.EmailAddress = s.SubscriberKey
AND x.TableName = e.Name
)
I'm personally most familiar with MS Sql Server so my sample uses that syntax. Should be easy enough to change to work with a different server if necessary though.
For performance you can then use whatever feature your DB has, indexed views etc.
How many tables do you have? If not too many one option would be to left join all of them
left join c100.table1 x1 on x1.EmailAddress = s.SubscriberKey and [e.name] = 'table1'
left join c100.table2 x1 on x2.EmailAddress = s.SubscriberKey and [e.name] = 'table2'
etc...
and then in the select
coalesce(x1.HL_ACCT_ID, x2.HL_ACCT_ID, etc...) as 'HL_ACCT_ID',

Get DISTINCT record using INNER JOIN

I have the follwong Query on multi tables
SELECT DISTINCT b.BoxBarcode as [Box Barcode], (select case when b.ImagesCount IS NULL
then 0
else b.ImagesCount end) as [Total Images], s.StageName as [Current Stage] ,d.DocuementTypeName as [Document Type],
u.UserName as [Start User],uu.UserName as [Finished User]
FROM [dbo].[Operations] o
inner join dbo.LKUP_Stages s on
o.stageid=s.id
inner join dbo.LKUP_Users u on
u.id=o.startuserid
left join dbo.LKUP_Users uu on
uu.id=o.FinishedUserID
inner join boxes b on
b.id=o.boxid
inner join LKUP_DocumentTypes d on
d.ID = b.DocTypeID
where b.IsExportFinished = 0
when i select count from the Boxes table where IsExportFinished = 0
i got the Count 42 records, when i run the above qoury i got 71 records,
i want just the 42 records in Boxes table to retrived.
You are doing a one-to-many join, i.e. at least one of the tables have multiple rows that match the join criteria.
Step one is to find which table(s) that give the "duplicates".
Once you have done that you may be able to fix the problem by adding additional criteria to the join. I'm taking a guess that the same boxid occurs several times in the Operations table. If that is the case you need to decide which Operation row you want to select and then update the SQL accordingly.
Try this one -
SELECT
Box_Barcode = b.BoxBarcode
, Total_Images = ISNULL(b.ImagesCount, 0)
, Current_Stage = s.StageName
, Document_Type = d.DocuementTypeName
, Start_User = u.UserName
, Finished_User = uu.UserName
FROM (
SELECT DISTINCT
o.stageid
, o.boxid
, o.startuserid
, o.FinishedUserID
FROM dbo.[Operations]
) o
JOIN dbo.LKUP_Stages s ON o.stageid = s.id
JOIN dbo.boxes b ON b.id = o.boxid
JOIN dbo.LKUP_DocumentTypes d ON d.id = b.DocTypeID
JOIN dbo.LKUP_Users u ON u.id = o.startuserid
LEFT JOIN dbo.LKUP_Users uu ON uu.id = o.FinishedUserID
WHERE b.IsExportFinished = 0
I guess that if you change your LEFT JOIN into INNER JOIN you will get 42 records as requested.